实践学期塔防游戏大作业功能点
编辑实践学期塔防游戏大作业功能点
姓名:张程瑞
学号:19107350111
项目名称:塔防游戏
功能点1-控制相机移动
实现方法:通过鼠标和键盘的输入,来控制摄像机的移动
可以通过WASD和按住右键拖动移动相机的位置,鼠标滚轮控制相机的缩放
实现代码:
/// <summary>
/// 调用摄像头移动
/// 通过WASD,鼠标滚轮,点击右键拖动,进行移动
/// </summary>
public void Move()
{
//通过WASD按键控制摄像机的前后左右移动
float h = Input.GetAxis("Horizontal");//读取横向操作,赋值给h
float v = Input.GetAxis("Vertical");//读取纵向操作,赋值给v
transform.Translate(new Vector3(h, 0, v) * Time.deltaTime * speed, Space.World);//使被挂载对象的坐标按照h,v的操作,在世界坐标系中移动
//通过滑轮控制摄像机的缩放
float mouse = Input.GetAxis("Mouse ScrollWheel");//读取鼠标滑轮操作,赋值给mouse
transform.Translate(new Vector3(0, 0, mouse * mousespeed) * Time.deltaTime);//使被挂载对象的坐标mouse的操作,在坐标系中移动
//通过鼠标右键按下拖动视角平移
//交换初始和结束鼠标位置
MousePositionLast = MousePositionNew;
MousePositionNew = Input.mousePosition;
MouseMoveDirection = MousePositionNew - MousePositionLast; //用两个坐标相减,得出鼠标的移动方向向量
if (Input.GetMouseButtonDown(1))//判断鼠标右键是否按下
{
whetherTheRightButtonIsPressed = true;//标记鼠标右键为按下
isItTheFirstTime = false;
}
else if (Input.GetMouseButtonUp(1))//判断鼠标右键是否按下
{
whetherTheRightButtonIsPressed = false;//标记鼠标右键为松开
}
//第一次数据识别会有错误,需要第二次以后的数据
if (isItTheFirstTime)//判断是否第一次
{
if (whetherTheRightButtonIsPressed)//判断鼠标右键是否按下
{
transform.Translate(new Vector3(-MouseMoveDirection.x, 0, -MouseMoveDirection.y) * Time.deltaTime * speed, Space.World);//跟着鼠标移动物体
}
}
else
{
isItTheFirstTime = true;
}
}
功能点2-防止相机移动超过限制
实现方法:通过限制摄像机在空间坐标系中的位置,来防止相机超出移动限制
if (transform.position.x > 100f || transform.position.x < -60f
|| transform.position.y > 100f || transform.position.y < 5f
|| transform.position.z > 70f || transform.position.z < -80f)
//判断是否超出规定范围
{//若超出范围
//超出限制后位置调整 防止相机越位
if (transform.position.x > 100f)
{
transform.Translate(new Vector3(-5f, 0, 0), Space.World);
}
if (transform.position.x < -60f)
{
transform.Translate(new Vector3(5f, 0, 0), Space.World);
}
if (transform.position.y > 100f)
{
transform.Translate(new Vector3(0, -5f, 0), Space.World);
}
if (transform.position.y < 5f)
{
transform.Translate(new Vector3(0, 5f, 0), Space.World);
}
if (transform.position.z > 70f)
{
transform.Translate(new Vector3(0, 0, -5), Space.World);
}
if (transform.position.z < -80f)
{
transform.Translate(new Vector3(0, 0, 5), Space.World);
}
}
else
{
Move();//调用摄像头移动
}
功能点3-怪物的生成以及按照路径点移动
实现方法:通过代码保存在unity中设置的路径点,并且通过跨脚本定义数组,并调用的方式,利用保存好的路径点位置,生成怪物,并让其按照路径点移动
保存路径点
public static Transform[] positions;//定义一个静态Transform数组保存位置
/// <summary>
/// Awake is called when the script instance is being loaded.
/// 在加载脚本实例时调用aware。
/// </summary>
void Awake()
{
positions = new Transform[transform.childCount];//获取子物体的数量作为positions的长度
for (int i = 0; i < positions.Length; i++)//遍历positions
{
positions[i] = transform.GetChild(i);//使positions的第i位等于子物体的索引,根据子物体的索引获取物体位置
}
}
怪物生成
/// <summary>
/// 携程函数 控制生成敌人数量与间隔
/// </summary>
/// <returns></returns>
IEnumerator SpawnEnemy()//携程函数
{
foreach (Wave wave in waves)//循环遍历Wave
{
for (int i = 0; i < wave.count; i++)
{
GameObject.Instantiate(wave.enemyPrefab, START.position, Quaternion.identity);//根据enmyPrefab在开始位置,生成无旋转的物体
CountEnemyAlive++;//使敌人数量增加
if (i != wave.count - 1)
{
yield return new WaitForSeconds(wave.rate);//暂停rate秒
}
}
while (CountEnemyAlive > 0)
{
yield return 0;//返回
}
yield return new WaitForSeconds(WaveRate);//暂停WaveRate秒
}
while (CountEnemyAlive > 0)//说明敌人还有存货
{
yield return 0;//返回
}
GameManager.instance.Win();//调用胜利
}
怪物移动
/// <summary>
/// 使怪物根据路径点移动
/// </summary>
void Move()
{
if (index > positions.Length - 1)//判断路径点序号是都大于路径点数组长度-1
{
return;//返回
}
transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * speed);//让脚本挂载物体向着 路径点位置-自身位置 的矢量方向进行移动
if (Vector3.Distance(positions[index].position, transform.position) < 0.2f)//判断脚本所挂载物体与路径点的距离是否小于0.2
{
index++;//+=1
}
if (index > positions.Length - 1)//判断是否超出路径数量
{
ReachDestination();
}
}
功能点4-炮台数据保存以及建造
实现方式:通过定义数据类的方式,定义枚举类型,保存需要建造的炮塔,并且在按下unity中设定的按键时,获取所保存的炮塔预制体,通过射线检测,检测鼠标与游戏中所设定的可以建造炮台的物体(GameObject
)的碰撞,来获取mapcube
的坐标,并通过获取的坐标与保存的炮塔预制体,在mapcube
上实例化炮台对象,从而完成炮塔的建造操作
判断鼠标是否与mapcub重合
/// <summary>
/// Start is called on the frame when a script is enabled just before
/// any of the Update methods is called the first time.
/// </summary>
void Start()
{
_renderer = GetComponent<Renderer>();//获取材质渲染器
originalMaterialColor = _renderer.material.color;//保存初始颜色
}
/// <summary>
/// Called when the mouse enters the GUIElement or Collider.
/// 当鼠标进入GUIElement或对撞机时调用。
/// </summary>
private void OnMouseEnter()
{
if (turretGo == null && EventSystem.current.IsPointerOverGameObject() == false)//判断是否为空并且鼠标不在UI上
{
_renderer.material.color = Color.red;//使材质变为红色
}
}
/// <summary>
/// Called when the mouse is not any longer over the GUIElement or Collider.
/// 当鼠标不再位于GUIElement或对撞机上时调用。
/// </summary>
void OnMouseExit()
{
_renderer.material.color = originalMaterialColor;//使材质变为原始颜色
}
炮塔的数据保存
//创建数据类保存炮塔数据
public class TurretData
{
public GameObject turretPrefab;//原始预制体
public int cost;//价格
public GameObject turretUpgradedPrefab;//升级预制体
public int cosUpgraded;//升级价格
public int dismantlingPrice;//拆解价格
public TurretType type;//定义枚举
}
/// <summary>
/// 定义枚举类型
/// 内部保存炮塔
/// </summary>
public enum TurretType//定义枚举类型
{
LasetTurret,
MissileTurret,
standardTurret,
Boom
}
按下按键获取炮塔
/// <summary>
/// 接受按键数据
/// </summary>
/// <param name="isOn">
/// 接收按钮传递的bool类型数据
/// </param>
public void OnlaserSelected(bool isOn)//接收按钮数据
{
if (isOn)//判断按钮是否按下
{
selectedTurretData = laserTurretData;//使当前炮塔等于选择的炮塔
}
}
/// <summary>
/// 接受按键数据
/// </summary>
/// <param name="isOn">
/// 接收按钮传递的bool类型数据
/// </param>
public void OnMissileSelected(bool isOn)//接收按钮数据
{
if (isOn)//判断按钮是否按下
{
selectedTurretData = mssileTurretData;//使当前炮塔等于选择的炮塔
}
}
/// <summary>
/// 接受按键数据
/// </summary>
/// <param name="isOn">
/// 接收按钮传递的bool类型数据
/// </param>
public void OnStandardSelected(bool isOn)//接收按钮数据
{
if (isOn)//判断按钮是否按下
{
selectedTurretData = standaraTurretData;//使当前炮塔等于选择的炮塔
}
}
/// <summary>
/// 接受按键数据
/// </summary>
/// <param name="isOn">
/// 接收按钮传递的bool类型数据
/// </param>
public void OnBoom(bool isOn)//接收按钮数据
{
if (isOn)//判断按钮是否按下
{
selectedTurretData = Boom;//使当前炮塔等于选择的炮塔
}
}
炮塔的建造
/// <summary>
/// Update is called every frame, if the MonoBehaviour is enabled.
/// </summary>
void Update()
{
if (Input.GetMouseButtonDown(0))//判断鼠标左键按下
{
if (EventSystem.current.IsPointerOverGameObject() == false)//判断鼠标不在UI上
{
//开发炮台开发的创造
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//创建射线
RaycastHit hit;
bool isCollider = Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("MapCube"));//定义是否指向MapCube
if (isCollider)//判断是否指向MapCube
{
MapCube mapCube = hit.collider.GetComponent<MapCube>();//得到点击的mapcube
if (selectedTurretData != null && mapCube.turretGo == null)//判断是否选择了炮台 和mapcube上是否有炮塔
{
//可以创建
if (money >= selectedTurretData.cost)//判断钱是否够
{
ChangeMoney(-selectedTurretData.cost);//消耗金钱
mapCube.BuildTurret(selectedTurretData);//调用MapCube中的函数创建炮台
}
else
{
//提示钱不够
moneyAnimator.SetTrigger("Flicker");//将动画机的Flicker激活
}
}
else if (mapCube.turretGo != null)//判断上面有炮台
{
// Debug.Log(mapCube.turretGo);
// Debug.Log(selectedMapcube);
if (mapCube.turretGo == theCurrentlySelectedTurret && upgradeCanvas.activeInHierarchy)//如果选择同一个炮台
{
StartCoroutine(HideUpgradeUI());//调用携程函数隐藏UI
// HideUpgradeUI();//隐藏UI
}
else
{
//升级处理
if (mapCube.isUpgraded)//判断是否升级过
{
ShowUpgradeUI(mapCube.transform.position, true);//调用方法实例化
}
else
{
ShowUpgradeUI(mapCube.transform.position, false);//调用方法实例化
}
}
selectedMapcube = mapCube;//更新保存炮台所在的mapCube
theCurrentlySelectedTurret = mapCube.turretGo;//更新保存的炮台
}
}
}
}
}
/// <summary>
/// 创建炮塔并播放特效
/// </summary>
/// <param name="turretData">
/// 炮塔的TurretData
/// </param>
public void BuildTurret(TurretData turretData)
{
this.turretData = turretData;//保存炮塔属性
isUpgraded = false;//定义炮塔未升级
turretGo = GameObject.Instantiate(turretData.turretPrefab, transform.position, Quaternion.identity);//实例化炮塔并赋值给turretGo
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);//实例化特效并赋值给effect
Destroy(effect, 1.0f);//一秒后销毁
}
功能点5-炮塔价格的定义,以及炮塔升级与拆解
实现方式:通过功能点4中提到的炮塔数据保存方式,保存炮塔建造与升级所需要的价格,并且通过unity
中创建的UI面板
,通过先销毁原先炮塔,再重新实例化新炮塔的方式,进行炮塔的升级。或者通过销毁原先炮塔的方式,实现炮塔的拆除
升级面板的显示
/// <summary>
/// 显示升级面板
/// </summary>
/// <param name="pos">
/// 定义面板显示位置
/// </param>
/// <param name="isDisableUpgrade">
/// 是否禁用按钮
/// </param>
void ShowUpgradeUI(Vector3 pos, bool isDisableUpgrade = false)
{
StopCoroutine("HideUpgradeUI");//暂停携程
upgradeCanvas.SetActive(false);//控制显示与隐藏
upgradeCanvas.SetActive(true);//控制显示与隐藏
upgradeCanvas.transform.position = pos;//定义显示位置
buttonUpgrade.interactable = !isDisableUpgrade;//是否禁用按钮
}
/// <summary>
/// 携程函数 隐藏升级面板
/// </summary>
/// <returns></returns>
IEnumerator HideUpgradeUI()
{
upgradeCanvasAnimator.SetTrigger("Hide");//更改状态机状态
yield return new WaitForSeconds(0.3f);//等待0.3秒
upgradeCanvas.SetActive(false);//控制显示与隐藏
}
按下升级面板的按键触发
/// <summary>
/// 按下升级按键触发
/// </summary>
public void OnUpgradeButtonDown()
{
if (money >= selectedMapcube.turretData.cosUpgraded)//判断钱够不够
{
ChangeMoney(-selectedMapcube.turretData.cosUpgraded);
selectedMapcube.UpgradeTurret();//调用升级Mapcube上的升级方法
}
else
{
//提示钱不够
moneyAnimator.SetTrigger("Flicker");//将动画机的Flicker激活
}
StartCoroutine(HideUpgradeUI());//隐藏UI
}
/// <summary>
/// 按下拆解按键触发
/// </summary>
public void OnDestroyButtonDown()
{
ChangeMoney(selectedMapcube.turretData.dismantlingPrice);//返还钱
selectedMapcube.DestroyTurret();//调用升级Mapcube上的拆解方法
StartCoroutine(HideUpgradeUI());//隐藏UI
}
升级与拆解方法
/// <summary>
/// 升级炮塔并播放特效
/// </summary>
public void UpgradeTurret()
{
if (isUpgraded == true) { return; }//若升级过就销毁
Destroy(turretGo);//拆解就得炮塔
isUpgraded = true;//定义炮塔未升级
turretGo = GameObject.Instantiate(turretData.turretUpgradedPrefab, transform.position, Quaternion.identity);//实例化炮塔并赋值给turretGo
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);//实例化特效并赋值给effect
Destroy(effect, 1.0f);//一秒后销毁
}
/// <summary>
/// 拆解炮塔并播放特效
/// </summary>
public void DestroyTurret()
{
Destroy(turretGo);//拆解炮塔
//恢复初始值
{
isUpgraded = false;
turretGo = null;
turretData = null;
}
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);//实例化特效并赋值给effect
Destroy(effect, 1.0f);//一秒后销毁
}
功能点6-控制非激光炮台的攻击
实现方式:在Unity
中对炮台添加碰撞体,并且勾选IsTrigger
选项,使用OnTriggerEnter
方法进行碰撞检测,利用Tag
检测在炮塔碰撞范围内的物体是否是怪物,若是怪物,获取怪物的位置,使炮塔朝向怪物,并且实例化子弹模型,向子弹模型上挂载的Bullet
脚本传递敌人位置,从而实现子弹追踪敌人的效果
检测敌人
public List<GameObject> enemys = new List<GameObject>();//创建列表保存
/// <summary>
/// OnTriggerEnter is called when the Collider other enters the trigger.
/// 当对撞机other进入触发器时调用OnTriggerEnter。
/// </summary>
/// <param name="col">
/// The other Collider involved in this collision.
/// 参与这次碰撞的另一个对撞机。
/// </param>
void OnTriggerEnter(Collider col)//碰撞检测
{
if (col.tag == "Enemy")//判断撞上来的物体标签是否为Enemy
{
enemys.Add(col.gameObject);//向列表中添加
}
}
/// <summary>
/// OnTriggerExit is called when the Collider other has stopped touching the trigger.
/// 当对撞机他方停止接触触发器时,调用OnTriggerExit。
/// </summary>
/// <param name="col">
/// The other Collider involved in this collision.
/// 参与这次碰撞的另一个对撞机。
/// </param>
void OnTriggerExit(Collider col)//判断是否出检测范围
{
if (col.tag == "Enemy")//判断是否为Enemy
{
enemys.Remove(col.gameObject);//从列表中删除
}
}
更改炮台朝向
if (enemys.Count > 0 && enemys[0] != null && isItABomb == false)//判断是否有攻击对象
{
//保证y轴一致
Vector3 targetPosition = enemys[0].transform.position;//定义targetPosition为数组中第0个物体的vector3
targetPosition.y = head.position.y;//保持y轴一致
head.LookAt(targetPosition);
}
实例化子弹模型
/// <summary>
/// 实例化炮弹攻击敌人
/// </summary>
void Attack()
{
if (enemys[0] == null)//判断集合第0位是否为空
{
enemys = UpdateEnemys(enemys);//更新敌人
}
if (enemys.Count > 0)//判断列表长度是否大于0
{
if (isItABomb == false)
{
GameObject bullet = GameObject.Instantiate(bulletPrefab, firPosition.position, firPosition.rotation);//实例化炮弹
bullet.GetComponent<Bullet>().SetTarget(enemys[0].transform);//调用方法传递列表中第一个物体
}
}
else
{
timer = attackRateTime;//计时器复位
}
}
功能点7-子弹对敌人的伤害
实现方式:通过获取Turret
脚本上的敌人位置,使子弹跟踪敌人进行射击,并且通过距离检测的方式,判断子弹是否撞击到敌人,从而调用敌人身上的扣血方法,对敌人进行伤害
获取Turret
脚本上的敌人位置
/// <summary>
/// 用于跨脚本传递 敌人位置
/// </summary>
/// <param name="_target">
/// 传递敌人位置
/// </param>
public void SetTarget(Transform _target)//定义方法 用来传递目标
{
this.target = _target;//传递目标
}
子弹追踪敌人射击与计算敌人距离
/// <summary>
/// Update is called every frame, if the MonoBehaviour is enabled.
/// </summary>
void Update()
{
timer += Time.deltaTime;//计时器增加
if (allEnemies != null && allEnemies.Count > 0)//判断列表长度是否大于0
{
Boom();
}
if (target == null)//判断目标不存在
{
Die();
return;
}
if (isItABomb == false)//判断是否为炸弹
{
transform.LookAt(target.position);//面向敌人
transform.Translate(Vector3.forward * speed * Time.deltaTime);//移动
Vector3 dir = target.position - transform.position;//计算与敌人的距离
if (dir.magnitude <= distanceArriveTarget)//判断是否到达敌人
{
target.GetComponent<Enemy>().TakeDamage(damage);//使敌人掉血
Die();
}
}
}
对敌人造成伤害
target.GetComponent<Enemy>().TakeDamage(damage);//使敌人掉血
Die();
/// <summary>
/// 使敌人掉血
/// </summary>
/// <param name="damage">
/// 掉血血量
/// </param>
public void TakeDamage(float damage)//收到伤害
{
if (hp <= 0)//判断是否死亡
{
return;
}
hp -= damage;//扣血
hpSlider.value = (float)hp / totahHp;//显示血条
if (hp <= 0)//判断是否死亡
{
Die();
}
}
功能点8-激光炮台的攻击
实现方式:在Unity
中对炮台添加碰撞体,并且勾选IsTrigger
选项,使用OnTriggerEnter
方法进行碰撞检测,利用Tag
检测在炮塔碰撞范围内的物体是否是怪物,若是怪物,获取怪物的位置,使炮塔朝向怪物,并且向敌人方向绘制激光,对敌人造成伤害
检测敌人:同 功能点6-控制非激光炮台的攻击
更改炮台朝向:同 功能点6-控制非激光炮台的攻击
绘制激光并对敌人造成伤害
if (useLaser == false)//判断是否为激光
{
timer += Time.deltaTime;//计时器增加
if (enemys.Count > 0)//判断敌人数量是否大于0
{
Attack("Boom");//调用攻击
}
if (enemys.Count > 0 && timer >= attackRateTime)//判断敌人数量是否大于0并且时间是否到
{
timer = 0;//时间复位
Attack();//调用攻击
}
}
else if (enemys.Count > 0)//判断是否有敌人
{
if (laserRenderer.enabled == false)
{
laserRenderer.enabled = true;
}
laserEffect.SetActive(true);//开启特效
if (enemys[0] == null)//判断集合第0位是否为空
{
enemys = UpdateEnemys(enemys);//更新敌人
}
if (enemys.Count > 0)//判断是否有敌人
{
laserRenderer.SetPositions(new Vector3[] { firPosition.position, enemys[0].transform.position });//朝向敌人绘制激光
enemys[0].GetComponent<Enemy>().TakeDamage(damageRate * Time.deltaTime);//使敌人掉血
laserEffect.transform.position = enemys[0].transform.position;//在敌人位置播放动画
Vector3 pos = transform.position;//获取当前位置
pos.y = enemys[0].transform.position.y;//锁定y轴位置保证y轴与敌人高度一致
laserEffect.transform.LookAt(pos);//定义特效播放朝向
}
}
else
{
laserEffect.SetActive(false);//关闭特效
laserRenderer.enabled = false;//关闭激光显示
}
功能点9-炸弹攻击
实现方式:在Unity
中对炮台添加碰撞体,并且勾选IsTrigger
选项,使用OnTriggerEnter
方法进行碰撞检测,利用Tag
检测在炮塔碰撞范围内的物体是否是怪物,若是怪物,获取怪物的列表,传递到Bullet
脚本,对在列表范围内的全部怪物进行伤害
获取并传递列表
/// <summary>
/// 炸弹攻击敌人
/// </summary>
/// <param name="i">
/// 没用,单纯为了重载
/// </param>
void Attack(string i)
{
if (enemys[0] == null)//判断集合第0位是否为空
{
enemys = UpdateEnemys(enemys);//更新敌人
}
if (enemys.Count > 0)//判断列表长度是否大于0
{
if (isItABomb)
{
this.GetComponent<Bullet>().EnemyList(enemys);//调用方法传递列表
}
}
}
/// <summary>
/// 用于跨脚本传递 敌人数组
/// </summary>
/// <param name="_enemys">
/// 传递敌人数组
/// </param>
public void EnemyList(List<GameObject> _enemys)//定义方法 用来传递 敌人数组
{
this.allEnemies = _enemys;//传递目标
}
对范围敌人进行伤害
/// <summary>
/// 炸弹攻击与销毁流程
/// </summary>
void Boom()
{
if (isItABomb == true)//判断是否为炸弹
{
if (timer >= attackRateTime)//判断延时爆炸
{
if (whetherItIsTriggeredForTheFirstTime)//判断是否为第一次爆炸 防止多次触发造成多次伤害
{
// Debug.Log(("敌人数量:") + allEnemies.Count);
for (int i = 0; i < allEnemies.Count; i++)
{
allEnemies = this.GetComponent<Turret>().UpdateEnemys(allEnemies);//刷新列表
allEnemies[i].GetComponent<Enemy>().TakeDamage(boomDamage);//使敌人掉血
}
whetherItIsTriggeredForTheFirstTime = false;
GameObject effect = GameObject.Instantiate(explosionEffctPrefab, transform.position, transform.rotation);//创建特效
Destroy(effect, 5.0f);//销毁特效
}
Destroy(this.gameObject, 0.2f);//销毁子弹
GameObject.Find("GameManager").GetComponent<BuildManager>().CallCtripFunction();//调用隐藏面板
}
}
}
功能点10-怪物死亡
实现方式:判断怪物的血量是否小于等于0,从而销毁怪物,并移出列表
/// <summary>
/// 使敌人掉血
/// </summary>
/// <param name="damage">
/// 掉血血量
/// </param>
public void TakeDamage(float damage)//收到伤害
{
if (hp <= 0)//判断是否死亡
{
return;
}
hp -= damage;//扣血
hpSlider.value = (float)hp / totahHp;//显示血条
if (hp <= 0)//判断是否死亡
{
Die();
}
}
/// <summary>
/// 怪物死亡后调用
/// </summary>
void Die()
{
GameObject effect = GameObject.Instantiate(exlosionEffect, transform.position, transform.rotation);//实例化
Destroy(effect, 1.5f);//销毁特效
Destroy(this.gameObject);//销毁自身
}
/// <summary>
/// This function is called when the MonoBehaviour will be destroyed.
/// 当物体被销毁后调用该函数
/// </summary>
void OnDestroy()
{
EnemySpawner.CountEnemyAlive--;//敌人数量减少
}
功能点11-怪物到达终点与全部死亡时的处理与UI显示
实现方式:怪物死亡后销毁自身,并且在全部怪物死亡后,显示游戏胜利UI
。通过检测坐标点的方式,检测怪物是否到达终点,从而停止游戏进程,并且显示游戏失败UI
怪物死亡后的处理
/// <summary>
/// 怪物死亡后调用
/// </summary>
void Die()
{
GameObject effect = GameObject.Instantiate(exlosionEffect, transform.position, transform.rotation);//实例化
Destroy(effect, 1.5f);//销毁特效
Destroy(this.gameObject);//销毁自身
}
```
``` csharp
/// <summary>
/// This function is called when the MonoBehaviour will be destroyed.
/// 当物体被销毁后调用该函数
/// </summary>
void OnDestroy()
{
EnemySpawner.CountEnemyAlive--;//敌人数量减少
}
怪物全部死亡后的处理
/// <summary>
/// 携程函数 控制生成敌人数量与间隔
/// </summary>
/// <returns></returns>
IEnumerator SpawnEnemy()//携程函数
{
foreach (Wave wave in waves)//循环遍历Wave
{
for (int i = 0; i < wave.count; i++)
{
GameObject.Instantiate(wave.enemyPrefab, START.position, Quaternion.identity);//根据enmyPrefab在开始位置,生成无旋转的物体
CountEnemyAlive++;//使敌人数量增加
if (i != wave.count - 1)
{
yield return new WaitForSeconds(wave.rate);//暂停rate秒
}
}
while (CountEnemyAlive > 0)
{
yield return 0;//返回
}
yield return new WaitForSeconds(WaveRate);//暂停WaveRate秒
}
while (CountEnemyAlive > 0)//说明敌人还有存货
{
yield return 0;//返回
}
GameManager.instance.Win();//调用胜利
}
/// <summary>
/// 游戏胜利 显示界面和文字
/// </summary>
public void Win()
{
endUI.SetActive(true);//显示界面
endMessage.text = "游戏胜利";//显示文字
}
判断怪物到达终点
if (index > positions.Length - 1)//判断是否超出路径数量
{
ReachDestination();
}
怪物到达终点后的处理
/// <summary>
/// 怪物到达终点后执行
/// </summary>
void ReachDestination()
{
GameManager.instance.Failed();//调用游戏失败
GameObject.Destroy(this.gameObject);//清除
}
```
``` csharp
/// <summary>
/// 游戏失败 显示界面和文字 并停止生成
/// </summary>
public void Failed()
{
enemySpawner.Stop();//停止生成
endUI.SetActive(true);//显示界面
endMessage.text = "游戏失败";//显示文字
}
功能点12-游戏暂停与UI显示
实现方式:使用脚本,检测是否按下esc
键,并在按下按键后,显示在Unity
中设计好的游戏暂停UI
,并将游戏的时间刻度停止,从而达到暂停游戏的目的
检测是否按下esc
并显示游戏UI
/// <summary>
/// Update is called every frame, if the MonoBehaviour is enabled.
/// </summary>
void Update()
{
PauseTheGame();
}
/// <summary>
/// 暂停游戏
/// </summary>
void PauseTheGame()
{
if (Input.GetKeyDown(KeyCode.Escape))//判断是否按下ESC
{
Time.timeScale = 0;//游戏暂停
whetherTheGameIsPaused = true;//保存游戏暂停状态
gamePauseUi.SetActive(true);//显示游戏暂停UI
}
}
游戏继续
/// <summary>
/// 继续游戏
/// </summary>
public void ContinueTheGame()
{
if (this.GetComponent<GameManager>().IsItDoubleSpeed() == false)
{
Time.timeScale = 1;//游戏继续
}
else
{
Time.timeScale = 2;//游戏继续
}
gamePauseUi.SetActive(false);//隐藏游戏暂停UI
whetherTheGameIsPaused = false;//保存游戏暂停状态
}
返回主界面
/// <summary>
/// 返回主界面
/// </summary>
public void BackToMainInterface()
{
Time.timeScale = 1;//游戏继续
this.GetComponent<GameManager>().OnButtonMenu();//返回主界面
}
功能点13-切换游戏倍速
实现方式:利用在Unity
中建立的按钮,控制游戏Time.timeScale
属性的值,从而达到控制切换游戏倍速的目的
/// <summary>
/// 使游戏倍速运行
/// </summary>
public void DoubleSpeed()
{
if (isItDoubleSpeed == false && this.GetComponent<PauseUiControl>().WhetherTheGameIsPaused() == false)//判断倍速状态与暂停状态
{
isItDoubleSpeed = true;//使其为倍速
Time.timeScale = 2;//游戏倍速
speedDisplay.text = "当前:二倍速";
}
else if (isItDoubleSpeed == true && this.GetComponent<PauseUiControl>().WhetherTheGameIsPaused() == false)//判断倍速状态与暂停状态
{
isItDoubleSpeed = false;//使其为倍速
Time.timeScale = 1;//游戏倍速
speedDisplay.text = "当前:一倍速";
}
}
功能点15-界面设计
实现方式:在Unity
中进行Ui设计
,并且利用Button
进行界面的切换
/// <summary>
/// 姓名:张程瑞
/// 学号:19107350111
/// 脚本作用:控制游戏UI
/// </summary>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public GameObject endUI;//结束界面
public Text endMessage;//文字
private bool isItDoubleSpeed;//是否为倍速
public Text speedDisplay;//倍速显示
/// <summary>
/// 从其他脚本中调用是否为倍速
/// </summary>
/// <returns>
/// 返回bool类型是否为倍速
/// </returns>
public bool IsItDoubleSpeed()
{
return isItDoubleSpeed;//返回是否为倍速
}
//单例模式
private EnemySpawner enemySpawner;
public static GameManager instance;
/// <summary>
/// Awake is called when the script instance is being loaded.
/// 在加载脚本时调用
/// </summary>
void Awake()
{
instance = this;
enemySpawner = GetComponent<EnemySpawner>();
}
/// <summary>
/// 游戏胜利 显示界面和文字
/// </summary>
public void Win()
{
endUI.SetActive(true);//显示界面
endMessage.text = "游戏胜利";//显示文字
}
/// <summary>
/// 游戏失败 显示界面和文字 并停止生成
/// </summary>
public void Failed()
{
enemySpawner.Stop();//停止生成
endUI.SetActive(true);//显示界面
endMessage.text = "游戏失败";//显示文字
}
/// <summary>
/// 按下按钮触发 重新加载场景
/// </summary>
public void OnButtonRetry()
{
Time.timeScale = 1;//游戏速度默认
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);//重新加载当前场景
}
/// <summary>
/// 按下按钮触发 返回主界面
/// </summary>
public void OnButtonMenu()
{
Time.timeScale = 1;//游戏速度默认
SceneManager.LoadScene(0);//返回主界面
}
/// <summary>
/// 使游戏倍速运行
/// </summary>
public void DoubleSpeed()
{
if (isItDoubleSpeed == false && this.GetComponent<PauseUiControl>().WhetherTheGameIsPaused() == false)//判断倍速状态与暂停状态
{
isItDoubleSpeed = true;//使其为倍速
Time.timeScale = 2;//游戏倍速
speedDisplay.text = "当前:二倍速";
}
else if (isItDoubleSpeed == true && this.GetComponent<PauseUiControl>().WhetherTheGameIsPaused() == false)//判断倍速状态与暂停状态
{
isItDoubleSpeed = false;//使其为倍速
Time.timeScale = 1;//游戏倍速
speedDisplay.text = "当前:一倍速";
}
}
}
/// <summary>
/// 姓名:张程瑞
/// 学号:19107350111
/// 脚本作用:控制游戏暂停UI
/// </summary>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PauseUiControl : MonoBehaviour
{
public GameObject gamePauseUi;
private bool whetherTheGameIsPaused = false;//游戏是否暂停
/// <summary>
/// 从其他脚本中调用是否游戏暂停
/// </summary>
/// <returns>
/// 返回游戏是否暂停
/// </returns>
public bool WhetherTheGameIsPaused()
{
return whetherTheGameIsPaused;
}
/// <summary>
/// Update is called every frame, if the MonoBehaviour is enabled.
/// </summary>
void Update()
{
PauseTheGame();
}
/// <summary>
/// 暂停游戏
/// </summary>
void PauseTheGame()
{
if (Input.GetKeyDown(KeyCode.Escape))//判断是否按下ESC
{
Time.timeScale = 0;//游戏暂停
whetherTheGameIsPaused = true;//保存游戏暂停状态
gamePauseUi.SetActive(true);//显示游戏暂停UI
}
}
/// <summary>
/// 继续游戏
/// </summary>
public void ContinueTheGame()
{
if (this.GetComponent<GameManager>().IsItDoubleSpeed() == false)
{
Time.timeScale = 1;//游戏继续
}
else
{
Time.timeScale = 2;//游戏继续
}
gamePauseUi.SetActive(false);//隐藏游戏暂停UI
whetherTheGameIsPaused = false;//保存游戏暂停状态
}
/// <summary>
/// 返回主界面
/// </summary>
public void BackToMainInterface()
{
Time.timeScale = 1;//游戏继续
this.GetComponent<GameManager>().OnButtonMenu();//返回主界面
}
}
功能点14-各种特效制作
实现方式:在Unity
中进行特效制作
游戏运行截图
开始界面
游戏界面
胜利界面
失败界面
暂停界面
- 0
- 0
-
分享