打飞机战斗模块:
一、场景管理:
1.双方进入场景效果(例如:依次飞入)
关于动画,这里我们使用的是DoTween组件,具体的使用方法可以看我之前的博客:
http://blog.csdn.net/linshuhe1/article/details/51331569
2.战斗结束到下次战斗开始过度效果(例如:屏幕渐黑,胜利一方的飞机飞出屏幕显示范围)
黑幕效果:也是使用Plane组件,但是此时使用的材质所绑定的Shader类型,我们需要自行编写Shader文件,然后在Plane上绑定一个脚本,用于控制Shader中Color属性的透明度值的渐变效果
3.背景图效果(轮滚)
实现方式:两个Plane绑定一个脚本,Update方法中渐变坐标,到达某个阈值时重置坐标,两者轮流在屏幕中,Plane的大小至少要大于屏幕显示范围(防止背景不连续),创建一个Legacy Shaders/Diffuse类型的材质球Material,并拖过拖拽绑定材质上的图片,将材质球通过拖拽填充到Plane中的Mesh Renderer的Material属性上
切换背景图:通过Resources.Load<Texture>("路径")加载Resources文件夹下面指定路径的Texture属性的图片文件,将Texture复制给Mesh Renderer组件的material.mainTexture属性,即可切换背景图
二、技能系统:
1.被动技能:也是自动战斗的AI
首先是攻击对象的选择逻辑,按照设计来说,攻击顺序是:先攻击对位上的对手,对位没有对手就攻击附近距离最近的,距离一样的话选择血量较高的。
2.Buff:伤害、回血等
新建一个BaseBuffer脚本,所有的Buff消息都发送的这个脚本是统一进行处理,Buff消息必须包含几个基本的信息:Buff的影响对象、Buff类型、Buff属性值、Buff的发出对象的属性(只是属性,并非对象实体,反正Buff还没还没作用完之前其发出对象就已经被销毁了,这样容易导致空对象引用的错误)
3.血量条:
关于血条实现的方式主要有两种,一种是直接把血条设计成3D场景中的一个对象绑定在英雄身上,并设置血条实时对准相机方向;另一种就是通过将3D空间中英雄的坐标转换为2D空间上的坐标,然后使用2D组件建立血条,并在Update中实时获取英雄的3D坐标转换后的2D坐标,并赋值给血条。
4.子弹系统:
先在Hierarchy中右键Create Empty建立一个空对象命名为Bullet,然后在其下创建一个2D对象Sprite(用于显示子弹的图片)命名为BulletSprite:
由于子弹进行攻击行为实际上就是与攻击对象发生碰撞事件,所以子弹需要添加碰撞组件Box Collider,可以根据子弹图片或者模型的大小调整碰撞框的大小:
每个子弹我们都需要绑定一个脚本用于定义子弹的一些基本属性、处理碰撞事件以及控制子弹的运动和消失等,这里我们创建了一个Bullet.cs脚本,关键在于重写OnTriggerEnter(Colliderother)方法,这是发生碰撞事件时会触发的方法,即我们所有关于碰撞事件的处理都写在这里即可,其中other为被碰撞的目标对象:
/// <summary> /// 子弹与飞机发生碰撞框事件 /// </summary> /// <param name="other">Other.</param> protected void OnTriggerEnter(Collider other) { //对自己战队无效 if (this.tag == other.tag) return; //子弹消失 Destroy(gameObject); //发生buff消息 DataStructs.DemageData demage_data = new DataStructs.DemageData(); demage_data.target = other.transform; demage_data.type = 0; demage_data.num = power; BaseBuff.ReceiveDemage(demage_data); }
至于子弹的运动,即子弹空间位置的变化,在Update中进行动态修改localPosition来实现,具体思路可以是设定一个方向向量,即一个Vector3类型的数据,用速度向量乘以速度值再乘以时长,即得到空间位移量,再叠加到子弹原位置上即可得到新的位置,也可以限定超过某个范围时子弹自动销毁(提高效率):
/// <summary> /// 子弹位置变化 /// </summary> void Update () { //游戏暂停 if (BattleManager.Instance.IsPause == true || IsPause == true) return; //mDirection为方向向量,speed为速度值 var position = mTransform.localPosition + mDirection * speed * Time.deltaTime; if (position.z <= -7.11) { Destroy(gameObject); return; } mTransform.localPosition = position; }
5.主动技能:大招(例如:突进、换位、长按)
手势识别:OnMouseDown、OnMouseUp、OnMouseDrag
using UnityEngine; using System.Collections; public class ActorHandleComponent : MonoBehaviour { private Vector3 _vec3TargetScreenSpace;// 目标物体的屏幕空间坐标 private Vector3 _vec3TargetWorldSpace;// 目标物体的世界空间坐标 private static Transform Original_Trans;//未拖动前的位置 private Transform _trans;// 目标物体的空间变换组件 private Vector3 _vec3MouseScreenSpace;// 鼠标的屏幕空间坐标 private Vector3 _vec3Offset;// 偏移 private Camera[] mycamer; private Camera selfCamer; /// <summary> /// 三种手势识别 /// </summary> public enum HandleType { SlideUp, //上滑 ChangePosition, //换位 LongPress //长按 } void Awake( ) { _trans = transform; } // Use this for initialization void Start() { mycamer = new Camera[5]; self = transform.GetComponent<Actor>(); Original_Trans = BattleManager.Instance.M_Pos[0]; Camera.GetAllCameras(mycamer); foreach (Camera a in mycamer) { if (a != null) { if (a.tag == "UICamera") { //获取UICamera selfCamer = a; } } } } IEnumerator OnMouseDown( ) { Debug.Log("鼠标消息*****************************OnMouseDown"); // 把目标物体的世界空间坐标转换到它自身的屏幕空间坐标 _vec3TargetScreenSpace = selfCamer.WorldToScreenPoint(_trans.position); // 存储鼠标的屏幕空间坐标(Z值使用目标物体的屏幕空间坐标) _vec3MouseScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _vec3TargetScreenSpace.z); // 计算目标物体与鼠标物体在世界空间中的偏移量 _vec3Offset = _trans.position - selfCamer.ScreenToWorldPoint(_vec3MouseScreenSpace); // 鼠标左键按下 while ( Input.GetMouseButton(0) ) { // 等待固定更新 yield return new WaitForFixedUpdate(); } } IEnumerator OnMouseUp() { Debug.Log(_trans.localPosition+"鼠标消息*****************************OnMouseUp:"+Original_Trans.localPosition); if ((_trans.localPosition.z - Original_Trans.localPosition.z >= 0.7) && Mathf.Abs(_trans.localPosition.x - Original_Trans.localPosition.x) <= 0.5) { Debug.Log("OnMouseUp==============上滑"); } // 等待固定更新 yield return new WaitForFixedUpdate(); } IEnumerator OnMouseDrag() { Debug.Log("鼠标消息*****************************OnMouseDrag"); // 存储鼠标的屏幕空间坐标(Z值使用目标物体的屏幕空间坐标) _vec3MouseScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _vec3TargetScreenSpace.z); // 把鼠标的屏幕空间坐标转换到世界空间坐标(Z值使用目标物体的屏幕空间坐标),加上偏移量,以此作为目标物体的世界空间坐标 _vec3TargetWorldSpace = selfCamer.ScreenToWorldPoint(_vec3MouseScreenSpace) + _vec3Offset; // 更新目标物体的世界空间坐标 _trans.position = _vec3TargetWorldSpace; // 等待固定更新 yield return new WaitForFixedUpdate(); } // Update is called once per frame void Update () { } }
三、对象池:
由于在战斗场景中,我们需要频繁地创建飞机对象和子弹对象以及各种特效,假如不使用对象池,那么如此频繁的对象创建和销毁操作势必导致内存占用过高,在一些移动设备上也会出现设备发热严重以及闪退现象,为了避免这样的事情发生,我们就需要创建战斗场景中的对象池,对象销毁时放到对象池中,下次使用时直接从池子中获取对象进行复用,对象不够时再创建新对象,这样能大大提高游戏性能。我在这里使用第三方插件PoolManager来设计自己的对象池:
1.获取对象池:
private SpawnPool mActors_Pool;
mActors_Pool = PoolManager.Pools["ActorsAndBullets"];
2.获取对象的方法:
Transform bulletPrefab = mActors_Pool.prefabs["Bullet"];
Transform bullet = mActors_Pool.Spawn(bulletPrefab);
3.销毁对象的方法:
mActors_Pool.Despawn(bullet);