Unity冷却实施

时间:2020-01-26 18:57:42

标签: c# unity3d

我正在尝试在Unity项目中实现冷却,尽管这段代码似乎很有意义,但却无法正常工作。发布的代码是全方位的基本动作脚本。

我尝试用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 个答案:

答案 0 :(得分:1)

你做

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

但是您从不在任何地方更改isCoolddown

正如评论中已经提到的,您完全根本不希望在while方法中使用Update,至少在这种情况下不希望使用!这样会在给定的冷却时间内冻结整个主线程-或永久冻结!


您的代码中还有很多其他问题,让我们逐步进行:

    在按下
  • Input.GetKey的给定键时,它们是真实的每帧。但是,这是没有意义的,只要按钮保持按下状态,就只会造成不必要的开销,将材料颜色重复设置为相同的值。您只想将其应用一次。

    →宁可使用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;
    }