Unity无法从计时器经过的功能中翻转精灵
Unity Can't flip sprite from timer elapsed function
我刚刚开始探索 unity 和 c# 的协同工作,不小心遇到了下一个问题:
我有一条鱼。鱼应该从左到右,然后改变方向,从右到左。我还没有完成那个移动部分,但我打算用计时器来完成。因此计时器已激活,鱼开始移动,计时器停止,改变方向,计时器重置,鱼开始移动等。
我想翻转我的精灵,所以它会面向正确的方向。它不适用于 Elapsed 函数,我不明白为什么。如果您有任何想法,请分享
using System.Timers;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishBehavior : MonoBehaviour
{
public float moveSpeed;
private int direction; //for left -1, for right 1
private Timer timer;
private SpriteRenderer img;
private Rigidbody2D rb;
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
timer = new Timer();
timer.Elapsed += TimerElapsed;
ChangeTimerOptions();
}
private void Move()
{
//moving
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX; //Doesn't work!
//stop movement
}
private void ChangeTimerOptions()
{
System.Random rand = new System.Random();
timer.Interval = rand.Next(3000, 8000);
timer.Enabled = true;
Move();
}
private void TimerElapsed(object source, ElapsedEventArgs e)
{
ChangeDirection();
ChangeTimerOptions();
}
}
问题是 TimerElapsed
is on a different thread than that of Unity. Meaning any sort of calls you make inside of it to methods that would normally work in Unity will not. I would recommend instead using a Coroutine
or an Invoke
.
的回调
为了简要说明两者的含义,Coroutine
是一种特殊方法,可以在多个帧上完成少量工作。该方法也可以暂停一定时间以等待下线执行代码。 Invoke
或 InvokeRepeating
是在一定时间后执行方法的调用,或者在设定的开始时间和设定的时间量后连续调用方法。
如果你最终也加入了一个动作并随机化你的等待时间,我会考虑使用 Coroutine
而不是 Invoke
这样你就可以处理来自同一个的所有 movement/flip 逻辑主叫。
public float moveSpeed;
private int direction; //for left -1, for right 1
private Timer timer;
private SpriteRenderer img;
private Rigidbody2D rb;
// store the coroutine in case a duplicate call occurs somehow
private Coroutine MoveAndFlip = null;
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
// detect if any coroutine is already running
CleanUpMoveAndFlipCoroutine();
MoveAndFlip = StartCoroutine(MoveAndFlipAsset());
}
private void Move()
{
//moving
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX;
//stop movement
}
private IEnumerator MoveAndFlipAsset()
{
// instead of milliseconds, use seconds
float randomTimeInterval = Random.Range(3.0f, 8.0f);
while(true)
{
// can do movement here - depending on how you would like to apply motion it would change how
// it is implemented such as directly changing velocity, using a Vector3.Lerp, AddForce, etc.
// wait the time to flip
yield return new WaitForSeconds(randomTimeInterval);
// now flip
ChangeDirection();
}
}
private void CleanUpMoveAndFlipCoroutine()
{
if (MoveAndFlip != null)
StopCoroutine(MoveAndFlip);
}
如果您想要上述实现的 Invoke
示例,请按以下方法进行操作。
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
Invoke("ChangeDirection", RandomTimeToFlip());
}
private float RandomTimeToFlip()
{
return Random.Range(3.0f, 8.0f); ;
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX;
//stop movement
// start our method again after a set amount of time
Invoke("ChangeDirection", RandomTimeToFlip());
}
编辑: 显然,您可以通过更改计时器的 SynchronizingObject
引用来使用 TimerElapsed
,但我不确定要分配什么它到。不过,我仍然建议使用上面描述的两种方法之一。
我刚刚开始探索 unity 和 c# 的协同工作,不小心遇到了下一个问题: 我有一条鱼。鱼应该从左到右,然后改变方向,从右到左。我还没有完成那个移动部分,但我打算用计时器来完成。因此计时器已激活,鱼开始移动,计时器停止,改变方向,计时器重置,鱼开始移动等。 我想翻转我的精灵,所以它会面向正确的方向。它不适用于 Elapsed 函数,我不明白为什么。如果您有任何想法,请分享
using System.Timers;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishBehavior : MonoBehaviour
{
public float moveSpeed;
private int direction; //for left -1, for right 1
private Timer timer;
private SpriteRenderer img;
private Rigidbody2D rb;
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
timer = new Timer();
timer.Elapsed += TimerElapsed;
ChangeTimerOptions();
}
private void Move()
{
//moving
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX; //Doesn't work!
//stop movement
}
private void ChangeTimerOptions()
{
System.Random rand = new System.Random();
timer.Interval = rand.Next(3000, 8000);
timer.Enabled = true;
Move();
}
private void TimerElapsed(object source, ElapsedEventArgs e)
{
ChangeDirection();
ChangeTimerOptions();
}
}
问题是 TimerElapsed
is on a different thread than that of Unity. Meaning any sort of calls you make inside of it to methods that would normally work in Unity will not. I would recommend instead using a Coroutine
or an Invoke
.
为了简要说明两者的含义,Coroutine
是一种特殊方法,可以在多个帧上完成少量工作。该方法也可以暂停一定时间以等待下线执行代码。 Invoke
或 InvokeRepeating
是在一定时间后执行方法的调用,或者在设定的开始时间和设定的时间量后连续调用方法。
如果你最终也加入了一个动作并随机化你的等待时间,我会考虑使用 Coroutine
而不是 Invoke
这样你就可以处理来自同一个的所有 movement/flip 逻辑主叫。
public float moveSpeed;
private int direction; //for left -1, for right 1
private Timer timer;
private SpriteRenderer img;
private Rigidbody2D rb;
// store the coroutine in case a duplicate call occurs somehow
private Coroutine MoveAndFlip = null;
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
// detect if any coroutine is already running
CleanUpMoveAndFlipCoroutine();
MoveAndFlip = StartCoroutine(MoveAndFlipAsset());
}
private void Move()
{
//moving
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX;
//stop movement
}
private IEnumerator MoveAndFlipAsset()
{
// instead of milliseconds, use seconds
float randomTimeInterval = Random.Range(3.0f, 8.0f);
while(true)
{
// can do movement here - depending on how you would like to apply motion it would change how
// it is implemented such as directly changing velocity, using a Vector3.Lerp, AddForce, etc.
// wait the time to flip
yield return new WaitForSeconds(randomTimeInterval);
// now flip
ChangeDirection();
}
}
private void CleanUpMoveAndFlipCoroutine()
{
if (MoveAndFlip != null)
StopCoroutine(MoveAndFlip);
}
如果您想要上述实现的 Invoke
示例,请按以下方法进行操作。
void Start()
{
img = GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
direction = 1;
Invoke("ChangeDirection", RandomTimeToFlip());
}
private float RandomTimeToFlip()
{
return Random.Range(3.0f, 8.0f); ;
}
private void ChangeDirection()
{
direction *= -1;
img.flipX = !img.flipX;
//stop movement
// start our method again after a set amount of time
Invoke("ChangeDirection", RandomTimeToFlip());
}
编辑: 显然,您可以通过更改计时器的 SynchronizingObject
引用来使用 TimerElapsed
,但我不确定要分配什么它到。不过,我仍然建议使用上面描述的两种方法之一。