【Unity】U3D TD游戏制作实例(一)创建敌人、加载预制件


前言

TD(炮台防守)类游戏是比较经典的游戏类型,当年在 War3 中有很多 TD 类地图,还有类似《保卫萝卜》这种 2D 炮台防守游戏也曾火爆一时。

本次实例将使用 Unity 实现此类游戏,功能包含地图创建、敌人创建、敌人导航、炮台创建与升级、炮台攻击、敌人攻击等功能。

本章实现效果

在这里插入图片描述

场景和敌人

场景的创建使用 MTE 插件,该插件的使用方法可以参考另两篇文章:
【Unity】Unity插件:地形编辑器MTE(Mesh Terrain Editor)
【Unity】Unity寻路系统讲解及Navigation实际应用

敌人的模型及动画可以在 Unity Assets Store 中下载。后续章节我也会讲解如何使用模型和动画来生成预制件。

导航的功能可以参考另外几篇文章:
【Unity】Unity寻路系统讲解及Navigation实际应用
【Unity】导航基本组件:Nav Mesh Agent、Off Mesh Link、Nav Mesh Obstacle
【Unity】导航 Navigation 设置:窄桥、隧道、斜坡、台阶、坠落、跳跃
【Unity】Navigation 选择性寻路:Area Mask

动画播放可以参考另一篇文章:
【Unity】U3D ARPG游戏制作实例(二)人物基本动作切换

文件目录结构

在这里插入图片描述
如上图所示,目录结构基本按照以下原则:

  • Data:用于存放所有的模型、材质、纹理、动画控制器,其目录结构按照防御塔、敌人、基地、地形划分,每个目录下有相应的文件夹,以第一个敌人为例,在Enemy目录下创建一个名为Enemy_0001的目录,该目录下包含3D(模型及动画文件)、AnimatorController(动画控制器)、Materials、Textures四个目录。注意,敌人的Prefab预制体不应被存放到此文件夹中,因为预制体需要放到Resources文件夹中,以便后续动态加载。
  • Plugins:存放所有插件,例如EasyTouch、MTE等。
  • Resources:该文件夹中的内容可以被动态加载,所以我们做好的Prefab预制件要放到此文件夹中。注意,不要把所有的文件都放到此文件夹中,这会影响性能。
  • Secenes:场景文件。
  • Scripts:存放脚本文件。目前脚本暂时分为 Control(控制)、Defense(防御塔)、Enemy(敌人)、Game(游戏主程序)、Level(关卡)、Nav(导航),相应的脚本放入相应的文件夹下。

场景层次结构(Hierarchy)

在这里插入图片描述

如上图,场景 Hierarchy 结构大致如下:

  • Directional Light:直接光源,其后两个为测试光源,请忽略。
  • Main Camera:主相机。目前只提供一个主相机,后续可能会提供地图相机。
  • Easytouch:Easytouch、InputManager、EasyTouchControlsCanvas、EventSystem等都是用于处理输入事件的,在此不做过多处理。
  • Canvas:UI界面画布。
  • EnemyGeneratePoint:敌人出生点,所有敌人都要以出生点为父节点创建出来。一个场景内可能会有多个出生点,后续在加载 Level 时统一做处理。
  • TerrainParent:地图父节点,通过预制件加载的地图就放在此节点下。
  • GameScript:游戏脚本挂载处,用于挂载游戏核心脚本。

目前文件和场景结构设定如下,后续可能会有小范围更改。

处理模型

先将模型放到场景中,给模型创建好动画控制器,具体操作方式请见:【Unity】U3D ARPG游戏制作实例(二)人物基本动作切换

给模型指定导航代理以及自定义脚本:
在这里插入图片描述
将模型从场景中拖拽到文件夹中:
在这里插入图片描述

指定GameScript脚本

给 GameScript 节点指定两个脚本,代码如下:

using TDGameDemo.Nav;
using UnityEngine;

namespace TDGameDemo.Enemy
{
    
    

    /// <summary>
    /// 敌人创建器
    /// </summary>
    public class EnemyGenerator : MonoBehaviour
    {
    
    

        /// <summary>
        /// 生成敌人
        /// </summary>
        /// <param name="parent">父对象</param>
        /// <param name="enemy">敌人配置对象</param>
        /// <param name="target">导航目标</param>
        /// <returns></returns>
        public bool GenerateEnemy(Transform parent, string enemy, Transform target)
        {
    
    
            try
            {
    
    
                GameObject enemyPrefab = Resources.Load<GameObject>(enemy);
                GameObject o = Instantiate(enemyPrefab, parent, true);
                o.GetComponent<NavTest>().target = target;
            }
            catch (System.Exception)
            {
    
    
                return false;
                throw;
            }
            return true;
        }
    }
}

using TDGameDemo.Enemy;
using UnityEngine;

namespace TDGameDemo.Game
{
    
    

    /// <summary>
    /// 游戏主程序
    /// 加载关卡、游戏的开始、暂停、通关、失败
    /// </summary>
    public class GameMain : MonoBehaviour
    {
    
    
        private EnemyGenerator _enemyGenerator;
        public Transform _generatePoint;
        public Transform _target;

        void Start()
        {
    
    
            _enemyGenerator = GetComponent<EnemyGenerator>();
        }

        void Update()
        {
    
    
            if (Input.GetKeyDown(KeyCode.A))
            {
    
    
                _enemyGenerator.GenerateEnemy(_generatePoint, "Enemy/Prefab/Prefab_Enemy_10001", _target);
            }
        }
    }
}

此处路径暂时写死,后续要根据配置文件读取。

将出生点和基地的节点给到 GameMain 脚本:
在这里插入图片描述

运行游戏

使用 A 键来生成敌人。效果如下:
在这里插入图片描述


更多内容请查看总目录【Unity】Unity学习笔记目录整理

猜你喜欢

转载自blog.csdn.net/xiaoyaoACi/article/details/127049075