ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

UE4蓝图实现3D塔防:士兵进驻与Spline路径全解析

UE4蓝图实现3D塔防:士兵进驻与Spline路径全解析 简介基于UE4.22制作的3D塔防游戏学习项目面向UE4初学者、游戏开发爱好者以及需要完成课程设计或毕设参考的读者可快速搭建塔防原型。项目完整演示了塔防游戏的核心循环玩家需要在地图周边的岩石上放置炮塔抵抗一波又一波入侵士兵敌人共11波数量与血量逐波递增稍有不慎防线即被突破玩法融合了RTS布防与生存防守的思路也适合作为独立游戏的战斗原型进行二次改造。资源以ZIP压缩包交付容量约1.01GB内含UE4工程相关文件、场景配置、敌人角色网格以及外部获取的音频素材可直接打开运行方便学习者对照查看炮塔放置、波次生成、数值增长等关键逻辑的工程组织方式。由于包体较大运行前建议先阅读附带的运行说明其中记录了播放或启动时崩溃的排错技巧——先到项目设置中将地图切换为其他地图再重新选回正确地图即可避免此类初始化问题这一提示对理解UE4的地图引用与关卡加载机制很有帮助。目前已有647人学习下载无论你是刚接触UE4还是想深入研究塔防玩法都能通过这套项目获得从关卡设计、资源导入到运行排查的完整参考。1. 士兵-塔-防御-UE4一句话说清这个3D塔防在做什么想做塔防结果打开UE4拖了一个Cube就卡住这是我见过最多的开场。标题“士兵-塔-防御-UE4”其实已经把这类项目的核心模块点破了士兵是可移动、可调度的肉盾或火力塔是固定位置、自动索敌的防御单位防御则代表敌人入侵路线与波次压力。用UE4做3D塔防第一步不是堆美术场景而是先把这三件事串成一个能完整打完一局的循环敌人沿路推进塔自动攻击士兵手动进驻补强。这套路线适合独立开发者和学生项目也适合想转战斗策划的UE4从业者。读完你会得到一条不依赖付费资产的蓝图实现路径以及一份可以直接照抄的避坑清单。2. 把塔防玩法拆成四要素为什么“士兵塔”比纯塔更能撑住关卡先别碰引擎把玩法拆开再决定怎么写代码。一个塔防关卡无论做得多花哨底层都是四个要素敌人从哪来、沿什么路走、防御单位怎么打、玩家在什么节点做决策。纯塔防的问题在于玩家放下塔以后就只能看波次体验会变成“数值检验”局中缺少主动干预。加一个士兵单位之后玩家有了可操作资源战斗参与度会明显不一样。下面从玩法选型、寻路规划和碰撞规模三个角度展开这些决定了你后面蓝图脚本怎么写。2.1 士兵与塔的分工从玩法驱动力看选型塔的核心词是“自动”进入索敌范围就开火玩家只负责放位置。士兵的核心词是“调度”玩家把它拖到某个塔位或者让它直接挡在敌人路线上都是一种局中决策。常见做法有两种士兵作为独立拦截单位在路径上手动放置或操控另一种是士兵进驻塔位把塔的火力数值按士兵属性加成。两种方案我都试过独立拦截的参与感最高但代码量也最大——你需要处理士兵的移动寻路、拦截判定、被敌人碰撞后如何撤离稍不留神就会出现士兵把敌人堵在出生点的翻车现场。我更推荐“进驻塔位”的变体士兵跑到指定塔位后自身隐藏塔的攻击从“单一火力”变成“塔士兵”的叠加火力。这样做的好处是塔的索敌逻辑完全复用士兵只需要处理移动和进驻判定整体代码复杂度降了一个量级。新手的做法是先做进驻方案跑通以后再考虑独立拦截。下表是三者的取舍选型时可以直接对照方案玩家参与度代码复杂度主要平衡风险纯塔对照低最低玩家中后期无事可做士兵独立拦截高高士兵可能堵死刷新点士兵进驻塔位中低加成数值容易溢出选型后需要确定的第一个参数表是士兵属性和塔属性的拆分。士兵我一般用三个浮点MaxHealth、MoveSpeed、AttackBonusPercent塔用四个AttackRange、AttackInterval、BaseDamage、TargetChannel。AttackBonusPercent是进驻后加在塔BaseDamage上的百分比比如30%表示塔的攻击乘以1.3。这样士兵和塔的数值各自独立调起来不会互相拉扯。2.2 敌人路径与波次设计Spline还是NavMesh塔防寻路有两条常见路线全图NavMesh和固定Spline。NavMesh的好处是敌人能智能绕障坏处是“防御路线”完全不可控玩家会困惑为什么敌人从侧面绕过来Spline相反敌人沿着编辑器里画好的路走塔放哪里、哪里有拐弯一眼就能看明白。塔防游戏我基本只选Spline因为“关卡压力”是设计出来的不是让AI自己跑出来的。用Spline做路径敌人蓝图上的核心逻辑有两步沿Spline取位置和朝向下一点转向。UE4的Spline组件提供了GetLocationAtDistanceAlongSpline和GetRotationAtDistanceAlongSpline两个现成函数敌人Tick里维护一个累计距离每帧推进distance MoveSpeed * DeltaTime然后直接把Actor SetWorldLocation和SetWorldRotation。注意转向不要用Spline自带旋转直接赋值否则过弯时会因为切线突变出现瞬间甩头后面避坑章再展开。波次表的做法是用DataTable配置。右键创建“Miscellaneous DataTable”行结构体字段如下字段类型说明WaveIDint32波次编号EnemyTypeTSubclassOf出生的敌人蓝图类Countint32本波敌人数SpawnIntervalfloat每个敌人的生成间隔秒InitialDelayfloat本波开始前的等待时间这样波次配置从蓝图里抽出来改数值不用进蓝图重新编译。后期换敌人种类、调密度都直接在数据表里改不用写死逻辑。2.3 场景单位与碰撞规划攻击范围的目测标尺场景里的单位尺寸比例直接决定攻击判定的手感。敌人胶囊体半径如果设得太大塔的攻击范围看起来没碰到敌人却已经开火了太小则敌人会从塔的攻击圈边缘滑过去。我常用的标尺是敌人胶囊体半径取塔攻击范围的1/10到1/5塔的攻击范围在蓝图里画成一个半透明球体方便直接在编辑器里目测覆盖区域。塔位之间的间距按攻击范围半径的一半排布这样既能覆盖路径又不至于两座塔火力重叠过高。碰撞规划上有一个容易踩的坑索敌不要用物理碰撞的OnOverlap。物理碰撞触发量大、调试困难而且塔和敌人如果用同一套碰撞Channel放置塔的时候鼠标会不断被敌人阻挡。常见做法是敌人的Collision Preset设成Pawn塔蓝图里单独配一个SearchSphere组件用SphereOverlapActors做范围查询。塔本身的BoxCollision只负责被鼠标点击放置不参与索敌。这样攻击判定和交互判定彻底分离后续加士兵进驻判定也不会互相干扰。3. 用UE4蓝图跑出一个可玩的塔防闭环敌人生成、寻路与攻击判定这一章把最小闭环的蓝图逻辑完整串起来。目标不是做一个成品关卡而是让敌人生成、沿路走、塔能打、士兵能进驻这四件事在编辑器里跑通。下面三段分别对应敌人生成器、塔攻击、士兵进驻按顺序抄完就能得到一个能玩的原型。3.1 敌人生成器用Spline把敌人源源不断送出来第一步做生成器。新建一个Actor蓝图叫BP_EnemySpawner放一个SplineComponent作为敌人路径再放一个ArrowComponent指向出生方向。生成逻辑写在Event Tick里用计时器驱动。下面是这个生成器蓝图的逻辑伪代码实际操作时照着在蓝图里搭节点即可# BP_EnemySpawner 的 Event Tick 逻辑蓝图伪代码 # current_wave 从 DataTable 按 WaveID 取行 spawn_count 0 if current_wave is None: return # DeltaTime 由 Event Tick 提供 spawn_timer delta_time if spawn_timer current_wave.spawn_interval: # 生成敌人并赋路径 enemy spawn_actor( actor_classcurrent_wave.enemy_type, locationget_spline_start_location(), rotationget_spline_start_rotation() ) enemy.initialize(current_wave.wave_id, self.spline) spawn_count 1 spawn_timer 0.0 # spawn_count 达到 current_wave.count 后自动切换到下一波这段逻辑里有两个参数需要重点理解。spawn_interval控制的是敌人密度0.5秒生成一个和2秒生成一个对塔的压榨完全不同initialize是敌人蓝图里自定义的函数入参是波次ID和Spline引用敌人拿到Spline后才能去路径上取点移动。生成位置取Spline的起点旋转取Spline的起始旋转这样敌人一出生就正好对着路径方向不会先来一个转身。DataTable驱动的好处在这个节点就体现出来了你不需要为了调试某一波敌人密度去改蓝图里硬编码的间隔直接在数据表里把SpawnInterval从2.0改成0.5重新加载一下表即可。我一般调试时会先在数据表里把敌人的初始血量调成999999让它们走完全程确认路径点取点正常后再调回正常数值。3.2 塔的攻击判定Overlap检测加上冷却时间塔的攻击逻辑放在塔蓝图里核心是SearchSphere的Overlap事件。敌人进入范围时触发攻击但一定要加冷却判断不然敌人一进范围就会被持续扣血一秒掉几十次数值全乱。用蓝图节点搭的逻辑伪代码如下# BP_Tower 的 SearchSphere OnComponentBeginOverlap 事件 if not can_attack: return if other_actor 有 Tag Enemy: final_damage base_damage if has_garrison_soldier: final_damage base_damage * (1.0 soldier_attack_bonus) other_actor.receive_damage(final_damage, self) can_attack False # AttackInterval 秒后调用 EnableAttack 事件 start_timer( durationattack_interval, onceTrue, finish_eventEnableAttack )这里receive_damage是敌人蓝图里定义的接口函数塔不直接修改敌人血量只负责调用接口。好处是后续加特效、加击退、加伤害飘字都只需要在敌人的receive_damage里扩展不需要回头改塔。attack_interval是攻击间隔塔防原型里我起步用1.0秒这样手感和数值都能看清如果要做机关枪塔把它降到0.15秒同时把BaseDamage压到原来的十分之一。还有一个容易漏的参数是攻击范围的可视化。SearchSphere的Radius要把ShapeColor调成半透明绿色并且勾选“Hidden In Game”关闭运行时渲染。调试时如果想看范围在编辑器中选中塔就能看到球体运行时关闭不影响游戏画面。如果敌人已经进了范围但塔不攻击先检查SearchSphere的Overlap事件有没有正确绑定到敌人蓝图的碰撞预设上。3.3 士兵进驻塔位一个“移动判定”的最简实现士兵进驻是本项目最能体现“士兵”价值的部分也是最容易写复杂的一个点。这里刻意用最短路径实现塔位点单独做成ActorBP_PlacePoint士兵只朝它移动进入判定半径后直接触发进驻。士兵蓝图的关键逻辑如下# BP_Soldier 的 Event Tick # 目标塔位点由鼠标点击后在蓝图上赋值 if target_placepoint is None: return distance_to_point get_distance(self, target_placepoint) if distance_to_point accept_radius: # 到达塔位通知塔位点隐藏自己 target_placepoint.on_soldier_arrived(self) self.set_actor_hidden(true) # 塔在 receive_damage 里读取是否存在士兵加成 else: # 继续朝塔位点移动 move_to_location(target_placepoint.get_actor_location(), move_speed)accept_radius是进驻判定半径必须大于士兵的胶囊体半径否则士兵会一直卡在塔位边缘抖动。塔位点在on_soldier_arrived里要做两件事记录士兵引用并调高塔的has_garrison_soldier标记。然后塔攻击时的伤害计算公式里就会自动带上加成这就是前面代码里soldier_attack_bonus的来源。这套方案的好处是士兵只需要知道“走到点”不需要知道塔的任何内部逻辑塔只需要知道“有没有人入驻”不需要关心士兵是怎么来的。两者通过塔位点解耦后期要改成士兵可以在多个塔位间换防只需要给士兵增加一个“目标塔位点切换”的逻辑塔位点和塔本身都不需要动。4. UE4构建光照后发黑先从这四个排查点下手原型逻辑跑通以后下一步是关卡观感。塔防场景里大量静态墙体、地面、塔模型绝大多数团队会选用静态光照烘焙这样运行时几乎没有光照性能开销。但光照烘焙在UE4里有一个极常见的现象构建光照后场景发黑、墙面出现大片黑斑甚至整个场景比构建前暗了好几档。这一章先把关卡尺寸和灯光选型说清楚再给出发黑问题的排查顺序。4.1 关卡尺寸与防线的“护栏”设计在触碰光照之前先规划好关卡的基本几何。塔防关卡的最小测试模板是一条直道、一个拐弯、一个终点。Spline路径两侧不要贴着可放置区域至少留出3到4个塔位的宽度否则塔放下去会压住敌人生成点。防线的“护栏”用静态墙体模型拼不需要添加碰撞体以外的逻辑但墙体必须把路径围满不然敌人会因为物理碰撞细节卡在墙角和路之间抖动。常见做法是把墙体底部加一个不可见BlockVolume宽度比墙体厚一点保证所有Pawn都过不去。关卡尺寸决定了Lightmass Importance Volume的摆放范围这一步直接影响后面光照烘焙。生成体积必须在编辑器的放置Actor面板里手动拖一个Lightmass Importance Volume把它拉大到覆盖所有玩家可到达区域。如果不放这个体积烘焙时Lightmass会用默认范围计算场景边缘和塔位区域经常出现没能算到光照而发黑的情况。这是“构建光照后发黑”的最常见原因没有之一。4.2 静态光照为主塔防项目里动态光的取舍塔防关卡里会有大量移动单位——敌人、士兵、炮弹特效如果这些物体都参与动态光照运行时开销会非常难看。常见做法是场景静态模型、地面、墙体全部设为Static移动性方向光只负责烘焙光照不投射实时阴影敌人和士兵设为Movable但它们不参与烘焙只接收间接光。这个组合能兼顾画面和帧数也是我跑原型时用的标准配置。这里注意一个很容易混淆的概念Movable物体在烘焙光照下的阴影。静态烘焙完成后场景中的墙体已经有了烘焙阴影但Movable的敌人走过去默认不会在墙面和地面上产生动态阴影。这不是Bug是引擎的运行逻辑——你需要在敌人的项目设置里勾选“Cast Dynamic Shadow”代价是每个敌人多一笔阴影Pass。塔防敌人数量一多这个开销会指数级上涨。我的起步建议是原型阶段直接关掉敌人的动态阴影只保留塔和士兵的动态阴影视觉影响并不大帧数却能稳住。4.3 构建光照后发黑的四个排查点“UE4构建光照后发黑”是我在塔防项目里翻车最多的一个环节而且表现形式很玄学有时候只有一面墙发黑有时候整个地面黑一块。按顺序排查以下四个点基本能覆盖大部分情况。第一Lightmass Importance Volume是否覆盖场景。这是首要排查项。很多新手搭场景时只拖了模型忘了放这个体积烘焙后场景边缘必然发黑。解决在放置面板里搜索Lightmass Importance Volume拖出来拉大到覆盖场景所有可到达区域然后重新Build Lighting。第二World Settings里的Indirect Lighting Quality是否太低。这个值默认在1.0左右如果被调低到0.5以下间接光的采样密度不足墙面就会出现大面积黑块或黑斑。解决打开World Settings面板找到Lightmass分区把Indirect Lighting Quality调到2.0或4.0重新构建。这个值越高构建越慢但场景越干净。原型阶段用2.0足够。第三模型UV是否重叠或超出[0,1]范围。光照烘焙依赖模型的Lightmap UV如果UV重叠烘焙器会把多块区域算成同一块光照结果就是模型表面出现诡异的黑色渐变或亮斑。解决在模型资源的“Build Settings”里打开“Generate Lightmap UVs”并确认第二个UV通道非重叠。实在不行把模型的Lightmap Resolution调低试一试很多时候是分辨率太高导致烘焙器算爆了。第四动态物体被烘焙阴影“吃”掉。如果你把士兵和敌人设成了Static移动性它们也会参与烘焙移动后就留在原地变成黑影子。解决选中所有会移动的单位在Details面板里把Mobility改成Movable然后重新构建。这通常能解释为什么构建前画面正常、构建后物体周围出现大片黑色残影。5. 塔防项目常见坑4个翻车现场与排查顺序蓝图跑通、光照正常之后剩下的是大量运行时问题。这一章收录塔防原型里最常见、最消耗时间的4个坑每条按“现象→原因→解决”的顺序写可以直接当排查手册用。5.1 敌人到弯道就抖动甚至会冲出路径现象敌人在Spline直线段走得好好的一到拐弯点就开始左右抽搐或者转弯半径过大直接冲出路径。原因蓝图里敌人朝向直接用Spline的GetRotationAtDistanceAlongSpline这个函数返回的是Spline切线方向的瞬时旋转。在拐弯点Spline切线的方向会瞬间切变敌人每一帧都试图立刻转向新方向于是表现为猛甩头、抖动如果MoveSpeed调得高还会因为朝向和位移不同步冲出去。解决不要直接SetWorldRotation到Spline旋转。每帧用FindLookAtRotation(CurrentLocation, NextLocation)计算目标朝向再通过RInterpTo做旋转插值插值速度控制在每秒6到10弧度。位移仍然沿Spline推进但朝向是平滑的。代码上只需要在敌人Tick里把原来的直接旋转改成两句先取下一帧位置再计算朝向插值。5.2 波次结束但场上有幽灵单位现象当前波次的所有敌人都已经生成完毕也全部到达终点或被击杀但游戏里仍然显示还有敌人在场下一波迟迟不触发。原因敌人死亡时只销毁了自己的Actor但没有通知生成器更新“存活计数”。生成器只用spawn_count判断生成了多少个没有统计场上存活数导致波次结束条件永远无法满足。解决生成器里维护一个alive_count敌人生成时1敌人蓝图在ReceiveDamage生命值归零后调用生成器的OnEnemyDestroyed接口把alive_count减1。波次结束条件改为spawn_count wave.count AND alive_count 0。这个逻辑必须在生成器和敌人蓝图上分别实现不能只在生成器里判断生成数。5.3 烘焙光照后移动单位边缘出现黑色闪烁现象静态光照构建完成后敌人和士兵移动时模型边缘不停闪过黑色细线或黑点尤其靠近墙体时更明显。原因移动单位虽然设成了Movable但它们的Lightmap设置仍残留静态烘焙数据移动时引擎尝试采样已经烘焙在场景上的光照导致黑色斑块闪烁。另一种可能是敌人模型的Lightmap UV没有正确生成边缘像素被烘焙器判成黑色。解决选中所有移动单位蓝图里的默认 StaticMesh 组件把“Lighting Cast Shadow”保持开启但把“Lighting Mobility”确认为Movable然后在Model资产设置里重新生成Lightmap UV。如果还有黑斑直接把移动单位的“Affect Dynamic Indirect Lighting”关掉让它们不参与间接光照采样只接收直接光照和球谐光照。5.4 外接手柄没反应输入映射没配全现象USB手柄插上以后项目里无论怎么按方向键士兵都不移动但键盘操作完全正常。原因UE4默认项目模板虽然支持Gamepad但输入映射是在项目设置里单独配置的。很多新手只在“项目设置 输入”里配了键盘的WASD没给Gamepad方向轴添加映射引擎自然收不到手柄输入。解决打开项目设置的Input映射添加Gamepad Left Thumbstick X/Y和Gamepad Face Button Bottom等映射并绑定到对应的输入动作IA_Move / IA_Attack。这里有一个常见玄学点映射名称不要用中文也不要以数字开头否则打包后外接设备映射经常失效。配置完成后用控制台指令showdebuginput可以实时看到手柄轴输入是否被引擎捕获这个指令在调试外接设备映射时非常好用。6. 收尾技巧用控制台指令和数据表把验证做扎实原型能跑只是开始后面真正的成本在验证。我自己的习惯是先不做任何UI用控制台指令和打印日志把数值逻辑验一遍再回头补界面。这样能避免做完一个大菜单发现塔的伤害计算不对然后退回蓝图里改了半小时的痛苦。打开游戏后在UE4控制台输入stat unit可以立刻看到Frame、Game、Draw、GPU四个耗时。塔防原型里Frame耗时高优先检查塔和敌人的碰撞检测Draw耗时高优先检查模型面数和动态阴影。输入stat FPS看帧数波动如果敌人一多帧数就跳水重点把敌人的碰撞预设改成“OverlapAllDynamic”别让它们参与复杂物理查询。验证塔的伤害是否正确我通常不盯着血条看而是给敌人蓝图加一个PrintString每次ReceiveDamage时把实际伤害值和来源打印到屏幕。两座塔同时打同一个敌人时屏幕上的日志能直观看出伤害是否叠加、攻击间隔是否生效。这一步做完再上DataTable把波次密度从0.5秒改成2.0秒重复跑同一关验证数值调整是否真正映射到游戏内。使用控制台验证完毕以后再回头写配置。把士兵的AttackBonusPercent和塔的AttackInterval都收进数据表或CurveTable不要在蓝图里留硬编码。我踩过的教训是蓝图里硬编码一个“1.3”倍加成半个月后自己都忘了这个数是从哪来的。写成配置以后调平衡只需改表不需要动蓝图。至于外接手柄映射和光照问题这些事最好在开发第一天就固定成检查清单。我现在的习惯是每做一个新关卡先跑半局把Spline路径从头到尾看一遍确认所有塔位点都在可放置区域再开始堆UI和特效。希望帮到你。本文还有配套的精品资源点击获取
返回列表