Реализация перезарядки Unity - PullRequest
0 голосов
/ 26 января 2020

Я пытаюсь реализовать перезарядки в моем проекте в Unity, хотя этот код, кажется, имеет смысл, он не работает. Опубликованный код представляет собой универсальный сценарий движения c.

Я пытался что-то сделать с cooldown -=time.deltatime, но, похоже, это не сработало. Я пробовал несколько методов, но ни один из них не работает.

Код:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MovementScript : MonoBehaviour
{
    public float cooldown = 0;
    public float actualcooldown = 3f;
    public bool isCooldown = false;

    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.R))
        {
            GetComponent<Renderer>().material.color = Color.red;
        }
        if (Input.GetKey(KeyCode.G))
        {
            GetComponent<Renderer>().material.color = Color.green;
        }
        if (Input.GetKey(KeyCode.B))
        {
            GetComponent<Renderer>().material.color = Color.blue;
        }
        if (Input.GetKey(KeyCode.D))
        {
            transform.Translate(6f * Time.deltaTime, 0, 0);
        }
        if (Input.GetKey(KeyCode.A))
        {
            transform.Translate(-6f * Time.deltaTime, 0, 0);
        }
        if (Input.GetKeyDown(KeyCode.Space) && cooldown <= 0) {
            transform.Translate(0f, 20f * Time.deltaTime, 0f);
            isCooldown = true;
            while (isCooldown == true)
            {
                coolDownhappening();
            }
        }
    }

    public void coolDownhappening()
    {
        cooldown = actualcooldown;
        cooldown -= Time.deltaTime;

        if (cooldown <= 0)
        {
            cooldown = 0;
        }
    }
}

1 Ответ

1 голос
/ 27 января 2020

Вы делаете

 while (isCooldown == true)
 {
     coolDownhappening();
 }

Но вы никогда не меняете isCoolddown где-либо!

Также, как уже упоминалось в комментариях, вы делаете не хочу использовать while в методе Update вообще, по крайней мере, в этом случае! Это заморозит всю основную ветку на указанное время перезарядки - или в вашем случае навсегда!


В вашем коде много других проблем, поэтому давайте go шаг за шагом:

  • Input.GetKey - true каждый кадр , пока нажата данная клавиша. Однако это не имеет смысла и приводит только к ненужным накладным расходам, чтобы повторно установить цвет материалов на одно и то же значение, пока кнопка остается нажатой. Что вы скорее хотите сделать, так это применить его один раз.

    → лучше использовать Input.GetKeyDown для них!

  • GetComponent - довольно дорогой звонок. Вы должны не повторно использовать GetComponent<Renderer>(), а вместо этого сохранять ссылку один раз и использовать ее позже

    // most efficient is always to already reference this via the Inspector
    [SerializeField] private Renderer _renderer;
    
    // alternatively get it on runtime
    private void Awake()
    {
        if(!_renderer) _rednerer = GetComponent<Renderer>();
    }
    

    , а затем позже использовать

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.R))
        {
            _renderer.material.color = Color.red;
        }
    
        ...
    }
    
  • Ваша движущаяся часть в порядке. Чтобы сделать его немного более читабельным, я бы предпочел сделать что-то вроде

    if (Input.GetKey(KeyCode.D))
    {
        transform.Translate(Vector3.right * 6f * Time.deltaTime);
    }
    else if (Input.GetKey(KeyCode.D))
    {
        transform.Translate(Vector3.left * 6f * Time.deltaTime);
    }
    

    , также обратите внимание на else здесь. Конечно, зависит от ваших потребностей, но обычно вы хотите, чтобы кнопки напротив были эксклюзивными.

  • Наконец, реальная сделка: вы действительно хотите использовать метод прыжка с перезарядкой здесь.

    Сначала вы сделали это наоборот: Input.GetKeyDown вызывается только точно один раз именно в кадре, когда клавиша нажата. Таким образом, ваш объект «прыгает» 20 * 1/FPS, что для 60 FPS всегда около 0.33. Вы, вероятно, скорее хотели бы переместиться на определенное расстояние вверх по нескольким кадрам. После достижения определенной высоты активируйте время восстановления.

    Как уже упоминалось в комментариях, один может сделать это в Update, используя таймер, но обычно это делает код немного запутанным. Скорее используйте сопрограмму:

    private bool _canJump;
    
    private void Update()
    {
        ...
    
        // _canJump is cheaper to check so check it first
        if (_canJump && Input.GetKeyDown(KeyCode.Space)) 
        {
            StartCoroutine(JumpRoutine());
        }
    }
    
    private IEnumerator JumpRoutine()
    {
        // avoid concurrent routines
        if(!_canJump) yield break;
        // disable jumping
        _canJump = false;
    
        // Now it really depends on what you actually want to do 
        // and how your object should move now
        // you might e.g. want something like
        var jumpedHeight = 0f;
        while(jumpedHeight < 20f)
        {
            var jumpThisFrame = Vector3.up * 6f * Time.deltaTime;
            transform.Translate(jumpThisFrame);
    
            // important now! yield tells Unity to "pause" here,
            // render this frame, and continue from here int he next frame
            // without the yield statements this would again freeze your game until
            // the exit condition is fulfilled!
            yield return null;
        }
    
        // After reaching the target height this waits for 3 seconds but keeps on rendering meanwhile
        yield return new WaitForSeconds(actualcooldown);
    
        // after the cooldown allow next jump
        _canJump = true;
    }    
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...