【问题标题】:Reloading Prototype in Unity doesn't decrease ammo & bullets correctly在 Unity 中重新加载原型不会正确减少弹药和子弹
【发布时间】:2017-12-19 19:58:30
【问题描述】:

所以我是 C# 的新程序员(我知道这很令人震惊),我尝试在 Unity 中制作一个重新编码系统的原型,但只是在 Unity 中使用声音和仪表。

问题是当我重新加载时,它并没有正确减少弹药。因为我这样做是为了在你还剩下子弹的情况下重新加载时,它只会从子弹中减去弹药,我已经必须实现它只会减去一个 if (shots == 0)

在我遇到一些问题(另一个令人震惊)并看到我的整个程序只是 if() 语句之后。在重写和重构之后,我仍然有我的问题和 if 语句。我被告知不要发布 200 行代码并且要具体。

我将发布 200 行代码,因为我不知道更好。真的很抱歉。

公共类镜头:MonoBehaviour {

//"CoolDown" is used to limit rate of fire of my gun
public int CoolDown = 5;

//used to prevent shooting while realoding
public int ReloadCoolDown;
public bool IsReloading = false;

//obvious
public int Shots = 0;
public int TotalShots;
public int Magazine = 25;
public int Ammo = 125;
public bool NoAmmo = false;



void Start() 
{
    ReloadCoolDown = 150;
}

void Update()
{
    //Checks if ammo is still present
    CheckForAmmo();
    //just so i could test some stuff faster, can be ignored
    Skip();
    //Also checks for ammo
    if(!NoAmmo)
    {
        GameShot();
        ReloadEmpty();
        ReloadHalf();
        if (IsReloading == true)
        {
            ReloadCoolDown--;
        }
        if (CoolDown <= 0)
        {
            CoolDown = 0;
        }
        CoolDown--;
    }
    else if (NoAmmo)
    {
        ExecNoAmo();
    }
}

//Just getting the audio clips from unity
AudioSource GetAudio(int index)
{
   AudioSource[] audio = GetComponents<AudioSource>();
    if (index == 1)
    {
        return audio[0];
    }
    else if (index == 2)
    {
        return audio[1];
    }
    else if (index == 3)
    {
        return audio[2];
    }
    else if (index == 4)
    {
        return audio[3];
    }
    else
        return null;


}

void GameShot()
{
    //Shoots, increases total shots and shots (for that mag), plays audio, sets the cooldown for the next shot, decreases bullets in mag
    if (Input.GetKey(KeyCode.Space) &&
        CoolDown <= 0 && IsReloading == false)
    {
        TotalShots++;
        GetAudio(1).Play();
        CoolDown = 5;
        Shots++;
        Magazine--;
    }
}

//Reloads if every bullet in the magazine has been fired
void ReloadEmpty()
{
    //this and ReloadHalf() is where you can find so many if statements and where most of my code is tangled up...
    //im trying to check for ammo and if the mag is completely empty to trigger the empty reload
    if (Magazine == 0 && Ammo > 0)
    {

        if(Ammo >= 25)
        {
            Magazine = 25;
        }
        else
        {
            Magazine = Ammo; 
        }

        Ammo -= Shots;
        Shots = 0;
        ReloadCoolDown = 130;
        GetAudio(2).Play();

        IsReloading = true;
    }
    if (ReloadCoolDown <= 0)
    {
        ReloadCoolDown = 150;
        IsReloading = false;
    }
}
void ReloadHalf()
{
    //Again, many if statements and entaglement...
    if ((Input.GetKeyDown(KeyCode.R) && Magazine < 26) && Ammo > 0)
    {
        if (Shots == 0)
            Ammo -= 1;
        ReloadCoolDown = 80;
        GetAudio(3).Play();
        if(Ammo >= 25)
        { 
            Magazine = 26;
            Ammo -= Shots;
        }
        else if (Ammo <= 25)
        {
            Magazine += Ammo;
            if(Magazine > 26)
            {
                int i = Magazine - 25;
                Ammo = i;
                Magazine = 26;
            }

        }
        Shots = 0;
        IsReloading = true;
    }
    if (ReloadCoolDown <= 0)
    {
        ReloadCoolDown = 100;
        IsReloading = false;
    }
}

void ExecNoAmo()
{
    //plays no ammo sound if ammo == 0
    if(Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.R))
        GetAudio(4).Play();

}

void CheckForAmmo()
{
    if (Ammo <= 0 && Magazine <= 0)
        NoAmmo = true;
}

void Skip()
{
    if (Input.GetKeyDown(KeyCode.Z))
    {
        Ammo = 25;
    }
}

}

【问题讨论】:

  • 这里没有明确的问题。你所说的只是你遇到了问题。
  • 我建议将其发送给Code Review SE。我在GetAudio() 中看到的一件事是传递的索引总是比使用的索引高 1。 return audio[index-1]; 可以工作,将 所有 的 if 块合并到一个语句中(不过,您仍然需要检查是否越界)。
  • 您希望我们帮助解决什么问题?
  • @Draco18s 我的问题是,当您在低弹药时重新加载时,该代码无法正确计算射击次数。对不起,我不应该说得更清楚。我的问题也不是 GetAudio() 方法。这是重新加载方法。我无法在 Code Review SE 上发布我的代码,因为我的代码不起作用。我是这方面的新手,所以我不太确定如何问我的问题。下次我会更具体。现在重写我的代码。 :D
  • 编辑您的问题以包含问题陈述(在您的代码块之外!没有人会注意到 cmets 直到他们开始寻找所陈述的问题)。

标签: c# unity3d reload


【解决方案1】:

你的反子弹方法很少见。我把我的方法留在这里,以防它对某人有用

(数值示例)

    bulletsTotal = 30;
    bulletsMagazine = 15;
    bulletsMagazineSize = 15;

关于更新方法

if (Input.GetKey(KeyCode.R))
        {
            if(bulletsMagazine!= 15)
            {   
                if (bulletsTotal > 0)
                {
                    asGun.clip = reload;
                    asGun.Play();
                    Reloadgun();
                } 
            }
        }

这就是重新加载的功能

public void Reloadgun()
    {
        int bulletToReload= bulletsMagazineSize-bulletsMagazine;

        if(bulletToReload< bulletsTotal)
        {
            bulletsTotal = bulletsTotal - bulletToReload;
            bulletsMagazine = bulletsMagazine + bulletToReload;
        }
        else
        {
            bulletsMagazine = bulletsMagazine + bulletsTotal;
            bulletsTotal = 0;

        }

        bulletsTxt.text = "M92\n   " + (bulletsMagazine) + "/" + bulletsTotal;
    }

【讨论】:

    【解决方案2】:

    我已经尝试重构您的代码,但问题是您尝试做的事情太多,您应该将关注点分开并将其拆分为几个类。

    我创建了新的 PlayerSounds 类,其中包含在您的代码中播放声音的方法,但我懒得完全重构它,因此您的代码逻辑仍然在一个类中,尽管它应该分为 3 个类,一个管理射击,一个管理重新加载,一个管理弹药和杂志。此外,我对重新加载的逻辑完全感到困惑,所以我完全改变了,这将取决于你的需要。

    我所做的事情:在某种程度上移除了幻数,它们被改为常量。删除了 NoAmmo、IsReloading、Shots 字段。删除了所有 cmets,任何方法和字段都应该是不言自明的。反向否定条件 - 它们更难阅读。

    我也完全改变了重新加载的逻辑,我觉得你想多了,一些 if 语句总是错误的所以我删除了它们,我还将数字 25 和 26 更改为常量,我不明白你为什么需要根据射击次数减去弹药,而你所要做的只是填满弹匣,所以我简化了它。更改它以适合您的需要。 看完代码你甚至可能会发现,这两种重装方法几乎相同,可以合二为一,消除 if 语句,并根据重装子弹的数量播放声音。

    去掉 if 就是让方法按照你的意图去做正在做。

    class PlayerSounds
        {
            private const int PlayerShootingSound = 0;
            private const int PlayerReloadingMagazineSound = 1;
            private const int PlayerReloadingHalfOfMagazineSound = 2;
            private const int PlayerHasNoAmmoSound = 3;
            private AudioSource[] audio;
    
            public PlayerSounds(AudioSource[] audio)
            {
                if (audio == null)
                    throw new ArgumentNullException(nameof(audio));
    
                this.audio = audio;
            }
    
            public void PlayerShot()
            {
                audio[PlayerShootingSound].Play();
            }
    
            public void PlayerReloadingMagazine()
            {
                audio[PlayerReloadingMagazineSound].Play();
            }
    
            public void PlayerRealodingHalfMagazine()
            {
                audio[PlayerReloadingHalfOfMagazineSound].Play();
            }
    
            public void PlayerHasNoAmmo()
            {
                audio[PlayerHasNoAmmoSound].Play();
            }
        }
    

    还有你的 Shot 类:

    public class Shot : MonoBehaviour
    {
        private const int MagazineSize = 25; // to remove magic number 25 and 26, also to give this number a meaning
        private PlayerSounds playerSounds;
    
        public int CoolDown = 5;
        public int ReloadCoolDown;
        public int Shots = 0;
        public int TotalShots;
        public int Magazine = 25;
        public int Ammo = 125;
    
        void Start()
        {
            ReloadCoolDown = 150;
            playerSounds = new PlayerSounds(GetComponents<AudioSource>());
        }
    
        void Update()
        {
            if (playerTryingToFire())
            {
                tryToShoot();
                playNoAmmoSoundWhenWithoutAmmo();
            }
            else if (playerTryingToReload())
            {
                tryToReloadHalfMagazine();
                playNoAmmoSoundWhenWithoutAmmo();
            }
    
            tryToReloadEntireMagazine();
    
            if (CoolDown > 0) CoolDown--;
            if (ReloadCoolDown > 0) ReloadCoolDown--;
        }
    
        bool playerTryingToFire()
        {
            return Input.GetKey(KeyCode.Space);
        }
    
        bool playerTryingToReload()
        {
            return Input.GetKeyDown(KeyCode.R);
        }
    
        void tryToShoot()
        {
            if (playerCanFire())
            {
                TotalShots++;
                playerSounds.PlayerShot();
                CoolDown = 5;
                Magazine--;
            }
        }
    
        bool playerCanFire()
        {
            return CoolDown == 0 && ReloadCoolDown == 0 && Magazine > 0;
        }
    
        void playNoAmmoSoundWhenWithoutAmmo()
        {
            if (!hasAmmo())
            {
                playerSounds.PlayerHasNoAmmo();
            }
        }
    
        void tryToReloadHalfMagazine()
        {
            if (magazineIsNotFull() && hasAmmo())
            {
                int missingBulletCountInMagazine = MagazineSize - Magazine;
                transferAmmoToMagazine(missingBulletCountInMagazine);
                ReloadCoolDown = 80;
                playerSounds.PlayerRealodingHalfMagazine();
            }
        }
    
        private bool magazineIsNotFull()
        {
            return Magazine < MagazineSize;
        }
    
        void tryToReloadEntireMagazine()
        {
            if (Magazine == 0 && hasAmmo())
            {
                transferAmmoToMagazine(MagazineSize);
                ReloadCoolDown = 130;
                playerSounds.PlayerReloadingMagazine();
            }
        }
    
        private void transferAmmoToMagazine(int maximumAmountToFitMagazine)
        {
            int possibleBulletCountToFit = Math.Min(Ammo, maximumAmountToFitMagazine);
            Magazine += possibleBulletCountToFit;
            Ammo -= possibleBulletCountToFit;
        }
    
        bool hasAmmo()
        {
            return Ammo > 0;
        }
    }
    

    【讨论】:

    • 这是我一直在寻找的确切答案。我对代码非常纠结,我自己也对此感到困惑。非常感谢你。
    • 好吧,经过一些测试后,我无法让声音正常工作……您的初始代码在我这边吐出了一个错误。 “函数 nameof-Operator 在 C# 4 中不可用。”
    • 抱歉,nameof 是 C# 6 的功能,它所做的只是将您的字段/属性/任何内容的名称更改为字符串,因此只需将 nameof(audio) 更改为“audio”,它应该可以工作。
    • 好的.. 我花了一些时间现在几乎一切正常。我不得不合并我们的两个脚本,因为你的逻辑是我需要的,但声音不起作用,而且 Unity 的类有一些问题。现在一切都在一个类中,并且工作正常。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 2022-06-16
    • 2013-05-03
    • 2022-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    相关资源
    最近更新 更多