繁体   English   中英

Unity 无法从计时器经过时翻转精灵 function

[英]Unity Can't flip sprite from timer elapsed function

我刚刚开始探索团结和 c# 一起工作,不小心遇到了下一个问题:我有一条鱼。 鱼从左到右应该是 go,然后从右到左改变它的方向和 go。 我还没有完成那个移动的部分,但我打算用计时器来做。 所以计时器处于活动状态,鱼开始移动,计时器停止,改变方向,计时器重置,鱼开始移动等。我想翻转我的精灵,所以它会面向正确的方向。 它不适用于 Elapsed function,我不明白为什么。 如果您有任何想法,请分享

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的回调与 Unity 的回调位于不同的线程上。 这意味着您在其中对通常在 Unity 中工作的方法进行的任何类型的调用都不会。 我建议改为使用CoroutineInvoke

为了简要解释两者是什么, Coroutine是一种特殊的方法,可以在多个帧上完成少量工作。 该方法也可以暂停一段时间以等待执行代码。 InvokeInvokeRepeating是在一定时间后执行方法或在设定的开始时间和设定的时间后连续调用方法的调用。

如果您最终还合并了一个动作并随机化等待时间,我会考虑在Invoke上使用Coroutine ,这样您就可以处理来自同一个主调用的所有移动/翻转逻辑。

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());
}

编辑:显然,您可以通过更改 Timer 的SynchronizingObject引用来使用TimerElapsed ,但我不确定将其分配给什么。 我仍然建议使用我上面描述的两种方法之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM