WindmillBullect.cs

这个脚本定义了一种特殊的子弹------风车子弹WindmillBullect),它继承自一个通用的子弹基类 Bullect。实现直线飞行存在时间限制命中后不立即销毁的行为;带追踪 + 生命周期管理的子弹。

继承关系

  • 父类Bullect

新增声明

  • hasTarget:是否已经锁定目标并开始追踪(防止每帧重复初始化方向,只在第一次获得目标时执行一次 InitTarget。)
  • timeVal:计时器(子弹存活)

生命周期方法

OnEnable()

复制代码
private void OnEnable()
{
    hasTarget = false;  
    timeVal = 0;
}
  • OnEnable 在子弹 被激活(生成)时 调用(对象池复用场景尤为重要)。

  • 重置状态:未锁定目标、计时归零。

这样做避免了上次使用留下的脏数据。

Update()

  1. 检查游戏是否结束或超时,或者子弹的timeVal>= 2.5f → 调用timeVDestoryBullect()立即销毁子弹(调用父类 DestoryBullect 回池)。。

  2. 处理游戏暂停,不执行移动、不更新计时,子弹定在原地,直接返回

  3. 更新时间计时器,timeVal每帧累加,但不超过 2.5 秒

  4. 移动逻辑(核心)
    hasTargettrue → 沿自身 forward 方向移动(世界坐标系)。
    hasTargetfalse → 检查目标是否存在且激活→ 锁定目标(hasTargettrue) → 调用 InitTarget() 计算朝向(延迟启动:首帧不移动,只转向)。

)。

复制代码
 if (hasTarget)
    {
        transform.Translate(transform.forward * moveSpeed * Time.deltaTime, Space.World);
    }
    else
    {
        // 等待目标有效,转向并开始移动
        if (targetTrans != null && targetTrans.gameObject.activeSelf)
        {
            hasTarget = true;
            InitTarget();
        }
    }

辅助方法

private void InitTarget()

InitTarget() 的主要作用是 让子弹的正面(forward 方向)指向目标,并修正子弹的最终朝向 ,使其能够在后续飞行中沿 transform.forward 方向直线飞向目标并符合美术期望的飞行姿态。
具体步骤

  1. 根据目标的标签("Item" )计算瞄准点。

  2. 调用 transform.LookAt 让子弹的 forward 轴指向该点。

  3. 如果子弹当前的 Y 轴欧拉角为 0,则强制旋转到 90 度。


复制代码
if (targetTrans.gameObject.tag == "Item")
{
    transform.LookAt(targetTrans.position + new Vector3(0, 0, 3));
}
else
{
    transform.LookAt(targetTrans.position);
}

为什么要 + new Vector3(0, 0, 3)?

原因:

  • 物品("Item")可能是地面上的可破坏对象(如桶、箱子),它的 pivot 点(锚点)可能位于地面(Z=0 附近) 。若直接 LookAt 物品位置,子弹的朝向会指向地面,导致:

    • 子弹飞向地面,视觉上像是"扎地"而不是水平飞向物品。

    • 在 2D 游戏中,物品的碰撞体通常是一个水平放置的方形,子弹从侧面水平击中才合理。

解决办法:

对物品的瞄准点增加 (0, 0, 3) 偏移,即让子弹朝物品上方 3 个单位(沿 Z 轴)的方向瞄准。这样子弹会从物品的"正面"或"上方"掠过,配合飞行逻辑,实际碰撞可能依然有效,且视觉上更自然。


子弹为什么要强制旋转到 90 度?

  • 子弹模型(如风车叶片)可能设计为 XZ 平面内旋转,期望的飞行方向是 y 轴朝向侧面

  • LookAt 指向目标后,子弹的 Y 轴欧拉角有时会变成 0(例如子弹初始朝向和瞄准方向刚好使模型侧面朝上)。将 Y 角强制设为 90 度,能确保子弹的"正面"朝向正确的飞行方向,符合美术设计的视觉预期。

重写方法

protected override void OnTriggerEnter2D()

此脚本没有调用 base.OnTriggerEnter2D,意味着父类的通用碰撞逻辑(如销毁子弹)被覆盖。

执行流程

  1. 只关心标签为 "Monster""Item" 的对象。

  2. 确保碰撞对象处于激活状态。

  3. 防御性检查:如果目标是无效的,或当前物品目标已被清除,则提前返回。

  4. 伤害触发条件
    如果是怪物 → 直接造成伤害。
    如果是物品 → 需要判断 该物品是否为子弹当前锁定的那个目标(通过 GameController.Instance.targetTrans 对比)。这暗示游戏可能只允许破坏当前指定的某个物品(例如任务目标)
    → 调用目标的 TakeDamage 方法:向碰撞体发送 "TakeDamage" 消息,参数为 attackValue碰撞,同时播放命中特效CreateEff()

复制代码
 if (collision.gameObject.activeSelf)
        {
            if (targetTrans.position == null || (collision.tag == "Item" && GameController.Instance.targetTrans == null))
            {
                return;
            }
            if (collision.tag == "Monster" || (collision.tag == "Item" && GameController.Instance.targetTrans == collision.transform))
            {
                collision.SendMessage("TakeDamage", attackValue);
                CreateEffect();
            }
        }
相关推荐
郑州光合科技余经理18 小时前
海外版外卖系统:如何快速搭建国际化外卖平台
java·开发语言·前端·人工智能·小程序·系统架构·php
小雨下雨的雨18 小时前
蜡笔小画家鸿蒙PC用Electron框架 - 儿童学画蜡笔画技术实现详解
前端·javascript·华为·electron·前端框架·交互·鸿蒙系统
天蓝色的鱼鱼18 小时前
别只拿 Playwright 写测试,这三个野路子用法才是真香
前端
SoaringHeart18 小时前
Flutter进阶|源码修改:DecorationImage 添加网络图片占位图
前端·flutter
小新11018 小时前
vue 实战项目 天气查询
前端·javascript·vue.js
7yue18 小时前
用 TypScript 学习 Claude Code
前端·typescript·claude
Rain50918 小时前
实战:搭建 AI Code Review 自动化流水线
前端·人工智能·git·ci/cd·自动化·ai编程·代码复审
Nian_Baikal18 小时前
从零搭建离线地图服务:Nginx + Cesium/Leaflet 实战指南
前端
问心无愧051318 小时前
ctf show web入门99
android·前端·笔记