Unity2D 禁用玩家移动 X 秒
Unity2D Disable player movement for X seconds
我试图在玩家与特定对象发生碰撞时将其移动禁用 1 秒。对象发生碰撞,它检测到一切正常,但目前整个游戏都冻结了,没有 return。
我已经使用计时器为 X 和 Y 运动实现了 0 值(如在其他示例中所见)。这会完全冻结游戏,我必须终止进程并重新打开 Unity。
public Boolean frozen = false;
float shipDisabledTimer = 1f;
// Start is called before the first frame update
void Start()
{
SetUpMoveBoundaries();
gameSession = FindObjectOfType<GameSession>();
}
// Update is called once per frame
void Update()
{
Move(frozen);
Fire();
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("Game"))
{
if (Input.GetKey(KeyCode.Escape))
SceneManager.LoadScene("Game Over");
}
}
public void Move(Boolean Frozen)
{
UnityEngine.Debug.Log("Update1 - " + Frozen);
var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
transform.position = new Vector2(newXPos, newYPos);
if (frozen == true)
{
float timer = 0f;
timer += Time.deltaTime;
UnityEngine.Debug.Log(frozen);
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
disableship(frozen = false);
}
}
public Boolean disableship(Boolean frozen)
{
return frozen;
}
private void OnTriggerEnter2D(Collider2D other)
{
UnityEngine.Debug.Log(other.gameObject.name);
if (other.gameObject.name.Equals("Orb Shot(Clone)"))
{
UnityEngine.Debug.Log("Orb hit player");
//StartCoroutine(countdownTimer());
disableship(frozen = true);
}
}
单独的船应该冻结。没有其他游戏对象应该冻结。所有分数、计数器、敌人都应该继续前进。只有玩家 X,Y 被禁用 1 秒。
这个
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
完全阻塞游戏的主线程,因为 timer
和 shipDisabledTime
都不会在循环中更改,因此它永远不会结束。
这里有几种方法。
调用
Invoke
允许您在一定延迟后调用方法,这样您就可以轻松地执行类似
的操作
public void Freeze()
{
frozen = true;
Invoke("Unfreeze"; shipDisabledTime);
}
private void Unfreeze()
{
frozen = false;
}
协程
A Coroutine is like a temporary Update
method. Simplest way in your case is using WaitForSeconds
并做类似
的事情
public void Freeze()
{
StartCoroutine (FreezeRoutine());
}
private IEnumerator FreezeRoutine()
{
frozen = true;
yield return new WaitForSeconds(shipDisabledTime);
frozen = false;
}
简单的计时器
或者您可以使用一个简单的计时器,但在 Update
(不是 while 循环)中,例如
private float timer = -1;
public void Freeze()
{
frozen = true;
timer = shipDisabledTime;
}
private void Update()
{
if(timer > 0)
{
timer -= Time.deltaTime;
if(timer <= 0)
{
timer = -1;
frozen = false;
}
}
...
}
然后无论哪种方式,您都不会在此期间进行任何移动输入
public void Move()
{
if(frozen) return;
...
}
除了 Invoke
解决方案,您还可以扩展它们并决定是否要,例如堆叠多个冻结,在已经冻结时忽略它们或简单地重新启动计时器。
一般注意事项:在 c# 中,只需使用 bool
它基本相同但更易于阅读和编写 ;)
还要注意这个调用
disableship(frozen = false);
...
public Boolean disableship(Boolean frozen)
{
return frozen;
}
很奇怪...首先,这个方法除了 return 与您作为参数传入的相同值之外什么都不做。您 隐藏 frozen
字段具有相同的命名参数,所以这什么都不做!
第二个你的方法 returns a Boolean
但你没有将它分配给任何东西。
如果您想更改该值,只需使用 frozen = XY
进行设置即可,但不要进一步将其作为参数传递。
Aa 并避免在每一帧调用 Debug.Log
.. 即使在您甚至看不到日志的构建中,它也会降低您的应用程序的速度!
我试图在玩家与特定对象发生碰撞时将其移动禁用 1 秒。对象发生碰撞,它检测到一切正常,但目前整个游戏都冻结了,没有 return。
我已经使用计时器为 X 和 Y 运动实现了 0 值(如在其他示例中所见)。这会完全冻结游戏,我必须终止进程并重新打开 Unity。
public Boolean frozen = false;
float shipDisabledTimer = 1f;
// Start is called before the first frame update
void Start()
{
SetUpMoveBoundaries();
gameSession = FindObjectOfType<GameSession>();
}
// Update is called once per frame
void Update()
{
Move(frozen);
Fire();
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("Game"))
{
if (Input.GetKey(KeyCode.Escape))
SceneManager.LoadScene("Game Over");
}
}
public void Move(Boolean Frozen)
{
UnityEngine.Debug.Log("Update1 - " + Frozen);
var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
transform.position = new Vector2(newXPos, newYPos);
if (frozen == true)
{
float timer = 0f;
timer += Time.deltaTime;
UnityEngine.Debug.Log(frozen);
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
disableship(frozen = false);
}
}
public Boolean disableship(Boolean frozen)
{
return frozen;
}
private void OnTriggerEnter2D(Collider2D other)
{
UnityEngine.Debug.Log(other.gameObject.name);
if (other.gameObject.name.Equals("Orb Shot(Clone)"))
{
UnityEngine.Debug.Log("Orb hit player");
//StartCoroutine(countdownTimer());
disableship(frozen = true);
}
}
单独的船应该冻结。没有其他游戏对象应该冻结。所有分数、计数器、敌人都应该继续前进。只有玩家 X,Y 被禁用 1 秒。
这个
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
完全阻塞游戏的主线程,因为 timer
和 shipDisabledTime
都不会在循环中更改,因此它永远不会结束。
这里有几种方法。
调用
Invoke
允许您在一定延迟后调用方法,这样您就可以轻松地执行类似
public void Freeze()
{
frozen = true;
Invoke("Unfreeze"; shipDisabledTime);
}
private void Unfreeze()
{
frozen = false;
}
协程
A Coroutine is like a temporary Update
method. Simplest way in your case is using WaitForSeconds
并做类似
public void Freeze()
{
StartCoroutine (FreezeRoutine());
}
private IEnumerator FreezeRoutine()
{
frozen = true;
yield return new WaitForSeconds(shipDisabledTime);
frozen = false;
}
简单的计时器
或者您可以使用一个简单的计时器,但在 Update
(不是 while 循环)中,例如
private float timer = -1;
public void Freeze()
{
frozen = true;
timer = shipDisabledTime;
}
private void Update()
{
if(timer > 0)
{
timer -= Time.deltaTime;
if(timer <= 0)
{
timer = -1;
frozen = false;
}
}
...
}
然后无论哪种方式,您都不会在此期间进行任何移动输入
public void Move()
{
if(frozen) return;
...
}
除了 Invoke
解决方案,您还可以扩展它们并决定是否要,例如堆叠多个冻结,在已经冻结时忽略它们或简单地重新启动计时器。
一般注意事项:在 c# 中,只需使用 bool
它基本相同但更易于阅读和编写 ;)
还要注意这个调用
disableship(frozen = false);
...
public Boolean disableship(Boolean frozen)
{
return frozen;
}
很奇怪...首先,这个方法除了 return 与您作为参数传入的相同值之外什么都不做。您 隐藏 frozen
字段具有相同的命名参数,所以这什么都不做!
第二个你的方法 returns a Boolean
但你没有将它分配给任何东西。
如果您想更改该值,只需使用 frozen = XY
进行设置即可,但不要进一步将其作为参数传递。
Aa 并避免在每一帧调用 Debug.Log
.. 即使在您甚至看不到日志的构建中,它也会降低您的应用程序的速度!