Unity学习笔记(九):打飞机战斗模块

发表于2017-09-30
评论0 2.1k浏览

本篇文章以一个打飞机类型的游戏为例,给大家介绍下打飞机战斗模块。


一、场景管理:


1.双方进入场景效果(例如:依次飞入)

关于动画,这里我们使用的是DoTween组件,


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);

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引