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

Unity 2D塔防游戏中塔楼近距离Y轴相邻时无法正常锁定敌人问题

问题分析与解决方案

核心问题

  1. 2D旋转逻辑错误:使用3D的Quaternion.LookRotation处理2D场景旋转,导致方向计算混乱,多塔同时触发检测时旋转状态被错误覆盖。
  2. 碰撞检测逻辑不可靠:OnCollisionStay2D依赖碰撞体持续接触,多塔靠近时易出现检测冲突,且无法精准控制目标选择优先级。
  3. 旋转代码冗余冲突:连续两次赋值transform.rotation,逻辑重复且破坏正确的旋转计算。

分步解决方案

1. 替换为2D专属旋转逻辑

在2D游戏中,物体仅需绕Z轴旋转,直接通过方向向量计算角度即可,替代3D旋转方法:

// 计算指向敌人的2D方向向量(忽略Z轴)
Vector3 direction = target.transform.position - transform.position;
direction.z = 0;
// 计算Z轴旋转角度,减90度适配Sprite默认向上方向
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 90f;
transform.rotation = Quaternion.Euler(0, 0, angle);

2. 改用触发器+范围目标列表(替代OnCollisionStay2D)

OnCollisionStay2D触发逻辑不可控,改用触发器维护范围内敌人列表,在Update中主动选择目标,避免多塔冲突:

修改后的完整代码:

using UnityEngine;
using System.Collections.Generic;

public class BaseTowerScript : MonoBehaviour
{
    public float FireCooldown;
    private float FireTimer;
    public GameObject TowerBullet;
    private List<GameObject> enemiesInRange = new List<GameObject>();
    private GameObject currentTarget;

    private void Update()
    {
        // 帧率适配的冷却更新
        if (FireTimer < FireCooldown)
        {
            FireTimer += Time.deltaTime;
        }

        // 筛选有效目标(优先列表中第一个存活敌人)
        currentTarget = null;
        foreach (var enemy in enemiesInRange)
        {
            if (enemy != null)
            {
                currentTarget = enemy;
                break;
            }
        }

        // 有目标则执行锁定与射击
        if (currentTarget != null)
        {
            RotateToTarget(currentTarget);
            TryShoot();
        }
    }

    private void RotateToTarget(GameObject target)
    {
        Vector3 direction = target.transform.position - transform.position;
        direction.z = 0;
        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg - 90f;
        transform.rotation = Quaternion.Euler(0, 0, angle);
    }

    private void TryShoot()
    {
        if (FireTimer >= FireCooldown)
        {
            GameObject nBullet = Instantiate(TowerBullet, transform.position, transform.rotation);
            // 给子弹添加足够的向前推力
            nBullet.GetComponent<Rigidbody2D>().AddForce(transform.up * 15f, ForceMode2D.Impulse);
            FireTimer = 0;
        }
    }

    // 敌人进入范围时加入列表
    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Enemy"))
        {
            enemiesInRange.Add(other.gameObject);
        }
    }

    // 敌人离开范围时移除列表
    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Enemy"))
        {
            enemiesInRange.Remove(other.gameObject);
        }
    }
}

3. 正确配置图层碰撞忽略

确保塔楼之间不会互相触发检测:

  • 创建Tower专属图层,将所有塔楼设置为该图层
  • 打开Edit > Project Settings > Physics 2D
  • 在Layer Collision Matrix中,取消Tower图层与自身的碰撞勾选

4. 额外优化建议

  • 用Time.deltaTime更新冷却,保证不同帧率下冷却速度一致
  • 可扩展目标选择逻辑(如选择最近敌人、血量最低敌人)
  • 给子弹预设添加Rigidbody2D并设置合适的质量,避免飞行异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:05:54