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

Unity台球克隆开发:如何在球体移动时禁止玩家输入?

解决台球游戏中球体移动时禁止玩家击球的问题

看起来你卡在了台球游戏里“球体移动时禁止操作”这个点上,我来帮你梳理下问题并给出可行的解决方案——毕竟全局控制所有球体的状态,确实不能只靠单个Player脚本搞定。

1. 为什么isSleeping()会导致球体完全无法移动?

你的Update方法里手动把速度清零的逻辑,直接破坏了Unity刚体的睡眠机制:

private void Update() { 
    speed = rb.velocity.magnitude; 
    if (speed < 0.5) { 
        rb.velocity = new Vector3(0, 0, 0); 
    } 
}

刚体进入睡眠需要速度低到阈值且保持一段时间,你手动强制速度为0,会让Unity认为球体一直处于“被干预”的状态,永远无法自然进入睡眠,所以调用isSleeping()会一直返回false,甚至直接锁死球体移动。

修改成让刚体自然进入睡眠的逻辑:

private void Update() { 
    speed = rb.velocity.magnitude; 
    // 当速度足够低时,主动让刚体进入睡眠,而不是手动清零
    if (speed < 0.1f) { 
        rb.Sleep(); 
    }
}

更省心的方式是直接在Rigidbody2D组件的Inspector面板里调整Sleep Threshold(默认0.005),让Unity自动处理睡眠,不需要手动写代码干预。

2. 全局判断所有球体是否静止(核心解决方案)

你需要所有球体都静止后才能操作,单个Player脚本里的局部判断肯定不够,必须把全局状态管理放到GameManager里:

第一步:创建GameManager单例来管理所有球体

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;
    public List<Rigidbody2D> allBalls; // 在Inspector里把所有球体的Rigidbody2D拖进这个列表

    private void Awake()
    {
        Instance = this;
    }

    // 检查所有球体是否静止:要么处于睡眠状态,要么速度极低
    public bool AreAllBallsStationary()
    {
        foreach (var ballRb in allBalls)
        {
            if (!ballRb.IsSleeping() && ballRb.velocity.magnitude > 0.1f)
            {
                return false;
            }
        }
        return true;
    }
}

第二步:修改Player脚本,使用全局判断

把你原来OnMouseDrag和OnMouseUp里的speed == 0判断,替换成GameManager的全局检查:

void OnMouseDrag() { 
    // 只有所有球体都静止时,才允许拖动瞄准
    if (GameManager.Instance.AreAllBallsStationary()) { 
        mousePointB.GetComponent<SpriteRenderer>().enabled = true; 
        currDistance = Vector3.Distance(mousePointA.transform.position, transform.position); 
        spaceLimit = currDistance <= 3f ? currDistance : maxDistance;
        shootPower = Mathf.Abs(spaceLimit) * shootPowervar; 
        
        Vector3 dimxy = mousePointA.transform.position - transform.position; 
        float difference = dimxy.magnitude; 
        mousePointB.transform.position = transform.position + ((dimxy / difference) * currDistance * -1); 
        mousePointB.transform.position = new Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y, -0.8f); 
        shootDirection = Vector3.Normalize(dimxy); 
    } 
}

void OnMouseUp() { 
    if (GameManager.Instance.AreAllBallsStationary()) { 
        mousePointB.GetComponent<SpriteRenderer>().enabled = false; 
        arrow.GetComponent<SpriteRenderer>().enabled = false; 
        circle.GetComponent<SpriteRenderer>().enabled = false; 
        
        Vector3 push = shootDirection * shootPower * -1; 
        GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse); 
        
        // 击球后主动唤醒所有球体,防止部分睡眠的球没被触发运动
        foreach(var ballRb in GameManager.Instance.allBalls)
        {
            ballRb.WakeUp();
        }
    } 
}

3. 额外优化小技巧

  • 给所有球体的Rigidbody2D勾选Use Auto Mass,或者设置合适的质量值,让台球的物理运动更贴近真实感
  • 如果担心AreAllBallsStationary()频繁调用影响性能,可以改成用协程每隔0.1秒检查一次,或者在球体碰撞结束时触发状态检查
  • 尽量避免在Update里手动修改刚体速度,让Unity物理引擎自然处理,这样睡眠机制才能正常工作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:57:45