如何在可编写脚本的对象中调用协程 [Unity3D]
How do I call a Co-Routine in a Scriptable Object [Unity3D]
我有一个协程,我正在尝试从中制作破折号脚本(使用统一新输入系统和标准统一 CharacterController)并在可编写脚本的对象中调用协程使统一卡住。
如果我将 controller.Move() 放在 Activate() 中,它会起作用,但会闪烁而不是破折号。我尝试使用协程来避免这种情况,但我不能在 ScriptableObjects 中使用协程,所以我创建了一个名为 MonoInstance 的空白 MonoBehaviour(您可以在下面看到)。我仅使用它来调用 StartCoroutine 函数。
这让 Unity 崩溃了,现在我的头很痛。
帮助
Tl;Dr - Unity 崩溃。怎么弄不死机。伤脑筋。
能力
public class Ability : ScriptableObject
{
public new string name;
public float cooldownTime;
public float activeTime;
public virtual void Activate(GameObject parent) { }
}
冲刺能力
[CreateAssetMenu]
public class DashAbility : Ability
{
private PlayerController movement;
private CharacterController controller;
public float dashVelocity;
public override void Activate(GameObject parent)
{
movement = parent.GetComponent<PlayerController>();
controller = parent.GetComponent<CharacterController>();
MonoInstance.instance.StartCoroutine(Dashing());
}
IEnumerator Dashing()
{
float startTime = Time.time;
while(Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
}
yield return null;
}
}
单实例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonoInstance : MonoBehaviour
{
public static MonoInstance instance;
private void Start()
{
MonoInstance.instance = this;
}
}
我讨厌团结,请在下面修复和解释:
冲刺能力
IEnumerator Dashing()
{
float startTime = Time.time;
while (Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return new WaitForSeconds(0.01f);
}
yield return null;
}
Unity 试图一次做太多事情,并且每毫秒调用 time while 循环数千次,此时角色控制器(可能)甚至还没有移动(因为 Time.deltaTime 是 0,因为帧中的时间差不算什么)。这让unity哭了。这让我哭了。
添加 WaitForSeconds(?.??f) 使 unity 不再做太多事情,现在它不会崩溃。
Tl;dr - 告诉 unity 吃一颗镇静药,它就停止发作了
其实你的代码应该这样写。因为0.01秒不表示1帧的时长。
IEnumerator Dashing()
{
var startTime = Time.time;
while (Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return new WaitForEndOfFrame();
}
}
如果您不使用任何类型的新 WaitForXXX,您会得到相同的结果。
IEnumerator Dashing(Action onComplete)
{
float timer = 0f;
while (timer < activeTime)
{
timer += Time.deltaTime;
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return null
}
onComplete?.Invoke();
}
这个returns让程序在定时器大于activeTime之前就yield。
我添加了一个委托,以便在 运行 结束时调用。你可能想在执行此操作时阻止某些动作发生,比如玩家在冲刺时不应再次冲刺,如下所示:
private bool dashing;
void Update()
{
if(Input.GetKeyDown(KeyCode.Space) && dashing == false)
{
StartCoroutine(Dashing(ResetDashing));
}
}
void ResetDashing()
{
dashing = false;
}
上面是一个简单的例子,在 Dashing 协程完成循环之前你不能再次冲刺,然后将调用 ResetDashing 回调。
我有一个协程,我正在尝试从中制作破折号脚本(使用统一新输入系统和标准统一 CharacterController)并在可编写脚本的对象中调用协程使统一卡住。
如果我将 controller.Move() 放在 Activate() 中,它会起作用,但会闪烁而不是破折号。我尝试使用协程来避免这种情况,但我不能在 ScriptableObjects 中使用协程,所以我创建了一个名为 MonoInstance 的空白 MonoBehaviour(您可以在下面看到)。我仅使用它来调用 StartCoroutine 函数。
这让 Unity 崩溃了,现在我的头很痛。 帮助
Tl;Dr - Unity 崩溃。怎么弄不死机。伤脑筋。
能力
public class Ability : ScriptableObject
{
public new string name;
public float cooldownTime;
public float activeTime;
public virtual void Activate(GameObject parent) { }
}
冲刺能力
[CreateAssetMenu]
public class DashAbility : Ability
{
private PlayerController movement;
private CharacterController controller;
public float dashVelocity;
public override void Activate(GameObject parent)
{
movement = parent.GetComponent<PlayerController>();
controller = parent.GetComponent<CharacterController>();
MonoInstance.instance.StartCoroutine(Dashing());
}
IEnumerator Dashing()
{
float startTime = Time.time;
while(Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
}
yield return null;
}
}
单实例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonoInstance : MonoBehaviour
{
public static MonoInstance instance;
private void Start()
{
MonoInstance.instance = this;
}
}
我讨厌团结,请在下面修复和解释:
冲刺能力
IEnumerator Dashing()
{
float startTime = Time.time;
while (Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return new WaitForSeconds(0.01f);
}
yield return null;
}
Unity 试图一次做太多事情,并且每毫秒调用 time while 循环数千次,此时角色控制器(可能)甚至还没有移动(因为 Time.deltaTime 是 0,因为帧中的时间差不算什么)。这让unity哭了。这让我哭了。
添加 WaitForSeconds(?.??f) 使 unity 不再做太多事情,现在它不会崩溃。
Tl;dr - 告诉 unity 吃一颗镇静药,它就停止发作了
其实你的代码应该这样写。因为0.01秒不表示1帧的时长。
IEnumerator Dashing()
{
var startTime = Time.time;
while (Time.time < startTime + activeTime)
{
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return new WaitForEndOfFrame();
}
}
如果您不使用任何类型的新 WaitForXXX,您会得到相同的结果。
IEnumerator Dashing(Action onComplete)
{
float timer = 0f;
while (timer < activeTime)
{
timer += Time.deltaTime;
controller.Move(movement.move.normalized * dashVelocity * Time.deltaTime);
yield return null
}
onComplete?.Invoke();
}
这个returns让程序在定时器大于activeTime之前就yield。
我添加了一个委托,以便在 运行 结束时调用。你可能想在执行此操作时阻止某些动作发生,比如玩家在冲刺时不应再次冲刺,如下所示:
private bool dashing;
void Update()
{
if(Input.GetKeyDown(KeyCode.Space) && dashing == false)
{
StartCoroutine(Dashing(ResetDashing));
}
}
void ResetDashing()
{
dashing = false;
}
上面是一个简单的例子,在 Dashing 协程完成循环之前你不能再次冲刺,然后将调用 ResetDashing 回调。