Unity3D塔防游戏开发——学习笔记(下)
在上一次学习中我们完成了炮台创建以及出售的响应函数绑定,并进行了简单测试,下面我们完成实际的创建与出售操作。
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();
}
然后就是效果,生成四个炮台然后卖掉其中一个:
10、炮塔的攻击制作
接下来炮台创建好了之后我们需要给炮台添加攻击的特性,我们分别对我们的炮台预制体设置组件Sphere Collider和Rigidbody,勾选好相关属性,设置攻击的半径。
这样设置半径后可能会造成在攻击范围内无法创建炮台,因为射线碰到触发器也会直接返回触发器的信息而不是地基的信息,这时我们需要打开菜单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();
}
下面是结果显示:
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);//生成子弹
//给子弹挂脚本
}
最后是效果,因为没有加子弹的一个射出动作,所以停留在原地:
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);
}
}
下面是整个游戏的一个效果,炮台发射子弹,消灭怪物:
上一篇: 实习集锦2
下一篇: K -近邻算法 -- 鸢尾花案例讲解