Unity学习笔记12——打飞机战斗模块

打飞机战斗模块:

一、场景管理:

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

时间: 2024-10-11 07:51:07

Unity学习笔记12——打飞机战斗模块的相关文章

python基础教程_学习笔记12:充电时刻——模块

充电时刻--模块 python的标准安装包括一组模块,称为标准库. 模块 >>> import math >>> math.sin(0) 0.0 模块是程序 任何python程序都可以作为模块导入. $ cat hello.py #!/usr/bin/python print "Hello,signjing!" $ ./hello.py Hello,signjing! 假设将python程序保存在/home/ggz2/magiccube/mysh/p

python 学习笔记 14 -- 常用的时间模块之datetime

书接上文,前面我们讲到<常用的时间模块之time>,这次我们学习datetime -- 日期和时间值管理模块 使用apihelper 查看datetime 模块,我们可以看到简单的几项: date       ---  日期对象,结构为date(year, month, day) time       ---  时间值对象,结构为 time([hour[, minute[, second[, microsecond[, tzinfo]]]]]).时间对象所有的参数都是可选的.tzinfo 可以

python 学习笔记 13 -- 常用的时间模块之time

Python 没有包含对应日期和时间的内置类型,不过提供了3个相应的模块,可以采用多种表示管理日期和时间值: *    time 模块由底层C库提供与时间相关的函数.它包含一些函数用于获取时钟时间和处理器的运行时间,还提供了基本解析和字符串格式化工具 *    datetime 模块为日期.时间以及日期时间值提供一个更高层接口.datetime 中的类支持算术.比较和时区配置. *    calendar 模块可以创建周.月和年的格式化表示.它还可以用来计算重复事件.给定日期是星期几,以及其他基

python 学习笔记 12 -- 写一个脚本获取城市天气信息

最近在玩树莓派,前面写过一篇在树莓派上使用1602液晶显示屏,那么能够显示后最重要的就是显示什么的问题了.最容易想到的就是显示时间啊,CPU利用率啊,IP地址之类的.那么我觉得呢,如果能够显示当前时间.温度也是甚好的,作为一个桌面小时钟还是很精致的. 1. 目前有哪些工具 目前比较好用的应该是 weather-util, 之前我获取天气信息一般都是通过它. 使用起来也很简单: (1) Debian/Ubuntu 用户使用 sudo apt-get install weather-util 安装

STM32学习笔记6(TIM通用模块生成PWM)

1.     TIMER输出PWM基本概念   脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术.简单一点,就是对脉冲宽度的控制.一般用来控制步进电机的速度等等. STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出. 1.1   PWM输出模式 S

Swift学习笔记(12)--数组和字典的复制

Swift中,数组Array和字典Dictionary是用结构来实现的,但是数组与字典和其它结构在进行赋值或者作为参数传递给函数的时候有一些不同. 并且数组和字典的这些操作,又与Foundation中的NSArray和NSDictionary不同,它们是用类来实现的. 注意:下面的小节将会介绍数组,字典,字符串等的复制操作.这些复制操作看起来都已经发生,但是Swift只会在确实需要复制的时候才会完整复制,从而达到最优的性能. 字典的赋值和复制操作 每次将一个字典Dictionary类型赋值给一个

[原创]java WEB学习笔记12:一个简单的serlet连接数据库实验

本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 ---------------------------------

Unity学习笔记之五为Prefab添加材质

本次笔记中,我们将利用unity来创建并使用材质,把材质添加到我们的Prefab中去. 这一系列教程以及素材均参考自人人素材翻译组出品的翻译教程<Unity游戏引擎的基础入门视频教程>,下载链接附在第二篇学习笔记中. 继续上次笔记中所记录的东西,在Project视图中,ImportedAssets-Meshes-Materials下我们可以看到一个没有纹理的材质球,这个材质是跟随我们的3d Max模型来的默认材质.因为这里我们要添加自己的材质,所以我们直接把这个材质球删除. 删除后,我们看到本

MiZ702学习笔记12&mdash;&mdash;封装一个普通的VGA IP

还记得<MiZ702学习笔记(番外篇)--纯PL VGA驱动>这篇文章中,用verilog写了一个VGA驱动.我们今天要介绍的就是将这个工程打包成一个普通的IP,目的是为后面的一篇文章做个铺垫. 打包成一个普通的IP的目的,可以直接将这个IP粘贴到Block文件中.(和用文本实例化是一个意思).应为我们调用zynq的核的时候一般是用Block的形式,为了zynq和我们的VGA模块更方便的组织起来,就需要这种IP打包方式. 为什么是强调是普通的IP,这个主意是区分带AXI接口的IP,这个在后面介