欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity3D塔防游戏开发——学习笔记(下)

程序员文章站 2024-01-25 08:02:52
...

在上一次学习中我们完成了炮台创建以及出售的响应函数绑定,并进行了简单测试,下面我们完成实际的创建与出售操作。

9、具体创建炮塔及出售

我们在GameManage脚本中加入一个新的transform变量basePos用来存放地基的信息,然后在该地基上面创建炮台,我们需要更改SelectBase()函数和CreateTower()函数。

    private void SelectBase()//选择创建炮台的地基
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 200) && EventSystem.current.IsPointerOverGameObject() ==false)
        {
            if(hit.transform.tag=="TowerBase")//点击了地基就进行创建
            {
                //调用显示方法
                ShowSelectPanel(hit.transform);
                basePos = hit.transform;//将选中的地基存入basePos变量中
            }
        }
    }

    public void CreateTower()//创建炮台
    {
        if (selectTower == null)
            return;
        Debug.Log("创建炮台");
        GameObject tempTower = Instantiate(selectTower);//创建炮台
        tempTower.transform.SetParent(basePos, false);//设置炮台位地基的子节点,继承位置信息
        tempTower.transform.localPosition = Vector3.up * 2.6f;//对炮台设置相对地基的z方向偏移量
        //加炮塔的攻击脚本
        InitUI();
    }

    public void SellTower()//出售炮台
    {
        if (basePos.childCount < 2)
            return;
        Debug.Log("出售炮台");
        string tempname=basePos.GetChild(0).name;
        int desi = 0;
        if (tempname == "SelectCanvas")
            desi = 1;
        Destroy(basePos.GetChild(desi).gameObject);//毁掉炮台
        InitUI();
    }

然后就是效果,生成四个炮台然后卖掉其中一个:

Unity3D塔防游戏开发——学习笔记(下)

Unity3D塔防游戏开发——学习笔记(下)

10、炮塔的攻击制作

接下来炮台创建好了之后我们需要给炮台添加攻击的特性,我们分别对我们的炮台预制体设置组件Sphere Collider和Rigidbody,勾选好相关属性,设置攻击的半径。

Unity3D塔防游戏开发——学习笔记(下)

 这样设置半径后可能会造成在攻击范围内无法创建炮台,因为射线碰到触发器也会直接返回触发器的信息而不是地基的信息,这时我们需要打开菜单Edit->Project Settings->Physics->Queries Hit Triggers,找到该属性,取消勾选即可。

然后我们新建一个脚本TowerAI用来控制炮台进行攻击。

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

public class TowerAI : MonoBehaviour
{
    private List<GameObject> enemys;//存放带攻击的怪物列表
    private GameObject tarEnemy;//攻击的目标怪物

    // Start is called before the first frame update
    void Start()
    {
        enemys = new List<GameObject>();//初始化可攻击列表
        tarEnemy = null;//初始化目标怪物为空
    }

    // Update is called once per frame
    void Update()
    {
        Debug.Log(enemys.Count);
    }

    public void OnTriggerEnter(Collider other)//检测怪物是否进入攻击范围
    {
        if(other.tag=="Enemy")//检测碰撞的物体是否标签为怪物
        {
            if(!enemys.Contains(other.gameObject))//检测当前怪物是否已经存放进列表
            {
                enemys.Add(other.gameObject);//添加怪物到攻击列表
            }
        }
    }

    public void OnTriggerExit(Collider other)//检测怪物是否离开攻击范围
    {
        if (other.tag == "Enemy")//检测碰撞的物体是否标签为怪物
        {
            if (enemys.Contains(other.gameObject))//检测当前怪物是否已经存放进列表
            {
                enemys.Remove(other.gameObject);//将怪物从攻击列表移除
            }
        }
    }
}

我们先用脚本测试一下炮台是否检测到了进入攻击范围的怪物,输出进入范围的怪物数量信息,并且在GameManage里面创建炮台时将TowerAI脚本挂载到上面。

    public void CreateTower()//创建炮台
    {
        if (selectTower == null)
            return;
        Debug.Log("创建炮台");
        GameObject tempTower = Instantiate(selectTower);//创建炮台
        tempTower.transform.SetParent(basePos, false);//设置炮台位地基的子节点,继承位置信息
        tempTower.transform.localPosition = Vector3.up * 2.6f;//对炮台设置相对地基的z方向偏移量

        tempTower.AddComponent<TowerAI>();//加炮塔的攻击脚本
        InitUI();
    }

 下面是结果显示:

Unity3D塔防游戏开发——学习笔记(下)

11、炮塔的实际攻击

炮台攻击需要实现选择攻击目标,将炮台瞄准攻击的目标,然后最终实现攻击。

    private float dis;//距离比较
    private Transform turret;//可以旋转的炮台组件

    private float times;//计时器
    private GameObject bulletPrefab;//子弹预制体
    private Transform firePos;//炮口位置

    void Start()
    {
        dis = 10000;
        times = 0;
        enemys = new List<GameObject>();//初始化可攻击列表
        tarEnemy = null;//初始化目标怪物为空
        turret = transform.GetChild(0);//获取炮台的旋转组件
        firePos = turret.GetChild(0);//获取炮口信息
        bulletPrefab = Resources.Load<GameObject>("Prefabs/Bullet");//动态加载子弹预制体
    }

    void Update()
    {
        //Debug.Log(enemys.Count);
        if (enemys.Count > 0)//如果当前有怪物可以攻击
        {
            if (tarEnemy == null)//如果没有目标怪物
            {
                tarEnemy = SelectEnemey();
            }
        }

        if (tarEnemy != null)
        {
            //对怪物进行瞄准攻击
            AimEnemy();
        }
    }

    public void OnTriggerExit(Collider other)//检测怪物是否离开攻击范围
    {
        if (other.tag == "Enemy")//检测碰撞的物体是否标签为怪物
        {
            if (tarEnemy!=null && other.name == tarEnemy.name)//如果当前离开怪物为正在攻击目标
                tarEnemy = null;
            if (enemys.Contains(other.gameObject))//检测当前怪物是否已经存放进列表
            {
                enemys.Remove(other.gameObject);//将怪物从攻击列表移除
            }
        }
    }

    private void AimEnemy()//瞄准敌人
    {
        Vector3 pos = tarEnemy.transform.position;
        pos.y = turret.position.y;
        turret.LookAt(pos);
        times += Time.deltaTime;
        if(times>=1)
        {
            //产生实际的攻击
            AttackEnemy();
            times = 0;
        }
    }

    private void AttackEnemy()
    {
        GameObject bullet = Instantiate(bulletPrefab,firePos.position,Quaternion.identity);//生成子弹
        //给子弹挂脚本
    }

最后是效果,因为没有加子弹的一个射出动作,所以停留在原地:

Unity3D塔防游戏开发——学习笔记(下)

12、子弹攻击目标的速度

最后我们设置一下子弹让他可以飞出去命中怪物与参数。我们这里新建一个脚本BulletMove用来控制子弹的移动与攻击。

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

public class BulletMove : MonoBehaviour
{
    private float times;//子弹存活时间
    public GameObject targetEnemy = null;//攻击对象
    public TowerAI scripts=null;//获取炮台的脚本

    // Start is called before the first frame update
    void Start()
    {
        times = 0;
    }

    // Update is called once per frame
    void Update()
    {
        times += Time.deltaTime;
        if (times >= 3)
            Destroy(gameObject);//销毁子弹
        transform.Translate(Vector3.forward * Time.deltaTime * 40);//子每单位时间平移20单位
        Attack();//子弹进行攻击

    }

    private void Attack()
    {
        if (targetEnemy != null)//如果有攻击的对象
        {
            if(Vector3.Distance(transform.position,targetEnemy.transform.position)<2f)//如果子弹打中了对象
            {
                Destroy(targetEnemy);//消灭怪物
                scripts.enemys.Remove(targetEnemy);//将怪物从攻击列表移除
                Destroy(gameObject);//自毁
                Debug.Log("怪物已消灭");
            }
        }
        else
            Destroy(gameObject);
    }
}

 下面是整个游戏的一个效果,炮台发射子弹,消灭怪物:

Unity3D塔防游戏开发——学习笔记(下)