You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何通过Bool值触发事件控制玩家样条移动启停?

解决方案

先修正现有代码的核心问题

当前代码存在逻辑漏洞,先调整才能正常工作:

  1. 事件需传递Bool状态
    原Action不带参数,无法区分“启动”和“停止”,改成带Bool参数的Action<bool>,一个事件即可处理两种状态:

    // GameController 中修改事件定义
    public event Action<bool> OnRaceStateChanged;
    
    public void SetRaceState(bool isStarted)
    {
        OnRaceStateChanged?.Invoke(isStarted);
    }
    
  2. 修复协程启停逻辑
    直接用StopCoroutine(PlayerSpeed())可能失效,Unity需要匹配协程引用才能正确停止;同时原订阅逻辑错误(未添加订阅就取消),调整响应脚本:

    private Coroutine _playerSpeedCoroutine; // 保存协程引用,确保能正确停止
    
    void Start() {
        // 订阅带状态的事件
        GameController.Instance.OnRaceStateChanged += HandleRaceStateChange;
    }
    
    // 统一处理启停
    private void HandleRaceStateChange(bool isRaceActive) {
        if (isRaceActive) {
            // 避免重复启动协程
            if (_playerSpeedCoroutine == null) {
                _playerSpeedCoroutine = StartCoroutine(PlayerSpeed());
            }
        } else {
            // 通过引用停止协程
            if (_playerSpeedCoroutine != null) {
                StopCoroutine(_playerSpeedCoroutine);
                _playerSpeedCoroutine = null;
            }
            // 立即重置速度
            Player1Speed = 0;
            Player2Speed = 0;
            Player1Follow.GetComponent<PlayerFollow>().speed = 0;
            Player2Follow.GetComponent<PlayerFollow>().speed = 0;
        }
    }
    
    public IEnumerator PlayerSpeed() {
        // 用单例获取GameController,避免重复GetComponent
        while (GameController.Instance.raceStarted) {
            Player1Follow.GetComponent<PlayerFollow>().speed = Player1Speed / SpeedAdjustmentRatio;
            Player2Follow.GetComponent<PlayerFollow>().speed = Player2Speed / SpeedAdjustmentRatio;
    
            yield return new WaitForSeconds(0.1f);
        }
        // 协程结束后清空引用
        _playerSpeedCoroutine = null;
    }
    
  3. 确保单例正确初始化
    在GameController的Awake方法里初始化单例,避免空引用:

    public static GameController Instance;
    
    void Awake() {
        Instance = this;
    }
    

添加Inspector可见的Bool触发器

有两种简单实现方式:

方式1:在GameController中加公开Bool变量+OnValidate

直接在GameController中添加公开Bool变量,利用Unity的OnValidate方法监听编辑器中的变量变化,自动触发事件:

public class GameController : MonoBehaviour
{
    public static GameController Instance;
    public event Action<bool> OnRaceStateChanged;
    
    // 这个变量会显示在Inspector面板
    public bool raceStarted;

    void Awake() {
        Instance = this;
    }

    // 编辑器中变量修改时自动调用
    void OnValidate() {
        SetRaceState(raceStarted);
    }

    public void SetRaceState(bool isStarted)
    {
        raceStarted = isStarted; // 同步变量值
        OnRaceStateChanged?.Invoke(isStarted);
    }
}

现在你在Inspector里勾选/取消raceStarted,就能直接触发启停逻辑。

方式2:单独写调试控制脚本

如果不想污染GameController的逻辑,可以写一个独立的调试脚本,挂在任意物体上:

using UnityEngine;

public class RaceDebugTool : MonoBehaviour
{
    [Header("Race Control")]
    [SerializeField] private bool startRace;
    [SerializeField] private bool stopRace;

    void OnValidate() {
        if (startRace) {
            GameController.Instance.SetRaceState(true);
            startRace = false; // 重置状态,避免重复触发
        }
        if (stopRace) {
            GameController.Instance.SetRaceState(false);
            stopRace = false;
        }
    }
}

挂好后,Inspector里会出现两个Bool选项,勾选startRace启动比赛,勾选stopRace停止,勾选后自动重置,方便重复操作。

额外优化建议

  • 把Player1Follow和Player2Follow在Inspector里直接赋值,不要每次用GetComponent,提升性能和稳定性。
  • 确保场景中只有一个GameController实例,避免单例冲突。

内容的提问来源于stack exchange,提问作者greyBow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:43:13