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

技术求助:如何检查物体运动状态及优化Unity球体缩小代码

1. 如何检查物体的运动状态?
  • 通过刚体(Rigidbody)检测:若物体带有Rigidbody组件,可直接读取rigidbody.velocity属性,结合向量长度判断是否运动(需考虑浮点误差):
    Rigidbody rb = GetComponent<Rigidbody>();
    if (rb.velocity.sqrMagnitude < 0.001f) {
        // 物体静止
    } else {
        // 物体正在运动
    }
    
    注意:运动学刚体(isKinematic=true)的velocity不会自动更新,需用其他方法检测。
  • 通过位置变化检测:记录每一帧的物体位置,对比前后帧的位置差判断状态:
    private Vector3 lastPosition;
    
    void Start() {
        lastPosition = transform.position;
    }
    
    void Update() {
        bool isMoving = Vector3.Distance(transform.position, lastPosition) > 0.001f;
        lastPosition = transform.position;
    }
    
  • 通过动画状态检测:若物体由动画驱动,可读取Animator组件的状态判断是否处于运动动画:
    Animator anim = GetComponent<Animator>();
    bool isRunning = anim.GetCurrentAnimatorStateInfo(0).IsName("Run");
    
2. Unity代码优化方案

原代码存在每帧查找子弹效率低、固定位置判断状态不可靠的问题,以下是针对需求的优化实现:

核心优化思路

  • 缓存子弹引用,避免重复查找
  • 用布尔变量isBulletActive标记子弹是否处于飞行状态
  • 仅当无活跃子弹时,允许触发玩家缩小逻辑
  • 通过子弹的刚体状态或生命周期事件更新活跃标记

优化后的代码

using UnityEngine;

public class PlayerBallController : MonoBehaviour
{
    [SerializeField] private float shrinkAmount; // 每次点击缩小的量
    [SerializeField] private int healthPlayer;
    [SerializeField] private GameObject bulletPrefab;
    [SerializeField] private Transform bulletSpawnPoint;
    [SerializeField] private float bulletSpeed = 20f;
    public GameOver gameOver;

    private GameObject currentBullet;
    private bool isBulletActive = false;

    void Update()
    {
        // 更新子弹活跃状态:子弹存在但静止时标记为非活跃
        if (currentBullet != null)
        {
            Rigidbody bulletRb = currentBullet.GetComponent<Rigidbody>();
            if (bulletRb != null && bulletRb.velocity.sqrMagnitude < 0.001f)
            {
                isBulletActive = false;
            }
        }

        // 无活跃子弹时,响应点击触发缩小和子弹生成
        if (!isBulletActive && Input.GetMouseButtonDown(0))
        {
            SpawnBullet();
            ShrinkPlayer();
            healthPlayer--;

            if (healthPlayer <= 0)
            {
                Destroy(gameObject);
                gameOver.GameOverScreen();
            }
        }
    }

    void SpawnBullet()
    {
        // 清理旧子弹
        if (currentBullet != null) Destroy(currentBullet);
        
        // 生成新子弹并赋予初速度
        currentBullet = Instantiate(bulletPrefab, bulletSpawnPoint.position, bulletSpawnPoint.rotation);
        Rigidbody bulletRb = currentBullet.GetComponent<Rigidbody>();
        if (bulletRb != null)
        {
            bulletRb.AddForce(bulletSpawnPoint.forward * bulletSpeed, ForceMode.Impulse);
        }
        
        isBulletActive = true;
        // 自动销毁子弹,避免内存泄漏
        Destroy(currentBullet, 5f);
    }

    void ShrinkPlayer()
    {
        // 限制最小缩放,避免异常
        Vector3 newScale = transform.localScale - Vector3.one * shrinkAmount;
        newScale = Vector3.Max(newScale, Vector3.one * 0.1f);
        transform.localScale = newScale;
    }

    // 销毁玩家时清理子弹
    void OnDestroy()
    {
        if (currentBullet != null) Destroy(currentBullet);
    }
}

额外建议

  • 避免在Update中使用GameObject.FindWithTag,改用直接引用或事件系统传递状态
  • 若需要持续缩小(而非点击一次缩小一次),可将缩小逻辑放在Update中,并用isBulletActive做开关
  • 给子弹添加独立脚本,通过OnCollisionEnter或OnDestroy事件通知玩家控制器,状态判断会更准确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:41:07