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

Unity 2D游戏Sprite高速移动并穿透物体问题求助

Unity 2D 敌人穿透Tilemap地面后快速下坠的解决方法

在带有Tilemap Collider组件的Tilemap方块上方放置虫子模型,启动游戏后虫子初始移动正常,但几秒后轻微陷入地面,随后以极快速度下坠。虫子使用的脚本如上,已设置两个正确的Vector3位置点。

问题原因

  • 直接修改transform.position绕过物理引擎:当前用transform.position = Vector3.MoveTowards(...)直接修改物体位置,这种方式完全跳过Unity的2D物理系统,Tilemap Collider的碰撞检测无法正确拦截物体移动。随着时间推移,物体位置会慢慢穿透碰撞体,当物理引擎发现位置异常时,会强制修正导致物体快速下坠。
  • 浮点数精度导致的位置判断失效:用transform.position == positions[indexPosition]判断是否到达目标点,由于浮点数的精度误差,这个条件可能永远不会触发,导致敌人卡在移动状态,进一步加剧穿透问题。

解决方案

  1. 用Rigidbody2D控制移动:确保虫子物体挂载Rigidbody2D组件,通过物理引擎处理移动,让碰撞检测正常工作:
    • 若敌人不需要重力,将Rigidbody2D设为Kinematic类型,用MovePosition()方法移动
    • 若需要重力影响,设为Dynamic类型,通过设置velocity控制移动
  2. 修正位置到达判断逻辑:用Vector3.Distance()或Vector3.sqrMagnitude(性能更优)判断是否接近目标点,规避浮点数精度问题
  3. 检查物理组件设置:确保Rigidbody2D的重力缩放(Gravity Scale)合理,若不需要下落可设为0;BoxCollider2D(或其他碰撞体)的大小和位置完全覆盖虫子模型

修改后的代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Enemy : MonoBehaviour
{
    public float speed = 5f;
    public Vector3[] positions;
    private int indexPosition;
    private Rigidbody2D rb;
    private SpriteRenderer sr;
    // 目标点判定阈值,可根据场景调整
    public float reachThreshold = 0.1f;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        sr = GetComponent<SpriteRenderer>();
        // 初始化位置到第一个目标点,避免偏移
        if(positions.Length > 0)
            transform.position = positions[0];
    }

    // 物理相关逻辑放在FixedUpdate中,保证稳定
    void FixedUpdate()
    {
        // 翻转Sprite逻辑
        Vector3 playerPos = GameObject.Find("Player").transform.position;
        sr.flipX = transform.position.x > playerPos.x;

        // 计算移动方向
        Vector3 targetPos = positions[indexPosition];
        Vector3 moveDir = (targetPos - transform.position).normalized;

        // Kinematic类型Rigidbody2D的移动方式
        rb.MovePosition(transform.position + moveDir * speed * Time.fixedDeltaTime);

        // 判断是否到达目标点
        float distanceToTarget = Vector3.Distance(transform.position, targetPos);
        if (distanceToTarget < reachThreshold)
        {
            indexPosition = (indexPosition + 1) % positions.Length;
        }
    }

    private void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            Destroy(gameObject);
        }
    }
}

额外说明

  • 移动逻辑从Update移到FixedUpdate,匹配物理引擎的固定更新帧率,避免移动抖动
  • 移除了原代码中speed/1000的缩放,可直接通过调整speed参数控制移动速度
  • 提前缓存Rigidbody2D和SpriteRenderer组件,避免每帧调用GetComponent损耗性能
  • 用取余运算简化了目标点循环逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:26:18