美文网首页
《飞盘射击》案例总结

《飞盘射击》案例总结

作者: 街头顽禽 | 来源:发表于2018-01-30 00:39 被阅读46次

《飞盘射击》案例总结

第一部分:Unity组件

什么是UI?

UI就是用户操作界面

常用UI介绍

<1>NGUI

NGUI是一款使用最多的第三方软件,国内大多数的游戏界面UI,都是使用NGUI插件编写出来的

<2>

UGUI(Untiy 4.6版本后自带的一套UI系统)

<3>ONGUI

现在主要是用于Unity引擎的界面扩展,NGUI和UGUI都是“”所见即所得“,而OnGUI就像是网页编写中HTML和Css样式表

<Legacy GUI>

旧版UI,只有俩个组件,分别是GUIText组件和GUIImage组件,分别是文本和图片,公司实际游戏项目开发不会用到

GUIText组件,主要用于文字的显示

GUITexture组件

主要用于图片的显示

鼠标事件

OnMosueEnter ()   鼠标进入

OnMouseExit  ()     鼠标离开

OnMouseDown ()   鼠标按下

Color结构体

Color.red;Color.green;Color.blue;

特效组件之TrailRenderer(拖尾渲染器)

它的一个重要用途是体现物体的运动速度,它的位置是在Component->Effects->Teail Renderer

材质球丢失的颜色为粉红色

材质球的Shader为Particle/Additive(粒子/添加物)

Time 设置拖尾持续时间

美工的黑白图:“黑透白不透”

特效组件之LineRenderer(线渲染器)

游戏中常用于渲染激光特效    ,或者用于子弹瞄准

同TrailRendere一样

声音组件之AudioSource

我们导入Unity的所有声音文件,他们的资源类型都是Audio Clip类型

Unity能使用的音频格式: .aif .wav .mp3 .ogg

Audio Source音频源组件,你可以将音频源组件当成“音响”

Play On Awake 唤醒时播放

Loop 循环

Mute 静音

Volume 音量

Spatial Blend 空间混合 0是2D声音 1是3D声音

Auido Listener 组件

声音侦听器,其实就是我们在游戏世界中的耳朵,在Main Camera上会挂载一个Auido Listener组件

Auido Source 常用函数

<1>Play() 函数

播放音频剪辑

<2>Stop() 函数

停止播放音频剪辑

<3>Pause() 函数

暂停播放音频剪辑

第二部分:Unity中常用的API函数

常用API之实例化与销毁

GameObeject.Instantiate(Object,Vector3,Quaternion);

Object 是指要实例化的游戏物体

Vector3既能表示方向又能表示位置,在这里表示要实例化的位置

Quaternion[四元数]:实例化后物体的旋转状态

构造随机位置

Random.Range(min,max);

在min和max之间随机生成一个随机数

销毁游戏物体

GameObject.Destroy(Object,float);  定时销毁某个游戏物体

Object 要销毁的游戏物体

float 多少秒后自动销毁

常用API之Invoke函数调用

for循环生成宝箱

for(int i = 0,i<5,i++) {

GameObject.Instantiate(box,Vector3,Quaternion.Identity);

}

一次生成5个宝箱

Invoke(string,float) : 多少秒后执行某个函数,只会调用一次

string :要调用的函数名称,用双引号括起来

float : 多少秒后调用,注意它是浮点数,如5秒,就写成5.0f

InvokeRepeating(string,float1,float2) :重复调用函数

string : 要调用的函数名称,用双引号括起来

float1 : 多少秒后开始调用

float2 : 以后每隔多少秒调用一次

Invoke函数的家在哪?

是Class,类下的函数(方法),字段,属性都可以理解为家庭成员

Invoke函数属于MonoBehaviour类

常用API之消息发送

gameObject.SendMessage(string); 通知这个游戏物体上的脚本执行某个函数

string : 将要执行的方法名,用双引号括起来

常用API之协同程序

在脚本运行过程中,需要执行一些额外的代码,类似开启了一个线程,但协程不是线程,而且协程只能在继承自MonoBehaviour类的子类中使用

协同程序语法格式

IEnumerator Task3 () {

yield return new WaitForSeconds(2);

Debug.Log("执行任务3"):

}

IEnumerator :协同程序的返回值类型

例如接受这个返回值,private IEnumerator m_ienumerator;

yield return : 协同程序返回 xxxxx;

new WaitForSeconds(秒数) : 实例化一个对象,等待多少秒后执行

开启协同程序

StartCoroutine(“协同程序方法名”);

停止协同程序

StopCoroutine("协同程序方法名")

常用API之脚本生命周期

这些生命周期事件是由Unity事先定好的,他们全部定义在MonoBehaviour这个类中,也就意味着只有继承自MonoBehaviour类的脚本,才有这些生命周期事件

1.Awake ()

唤醒事件,只能执行一次

2.OnEnable ()

启用事件,只执行一次,当脚本组件被启用时执行一次

3.Start ()

开始事件,只执行一次

4.FixedUpdate ()

固定更新事件,执行N次,每0.02秒执行一次,Update是0.16秒左右执行一次

5.Update () 

更新事件,执行N次,每帧执行一次

6.LateUpdate ()

稍后更新事件,执行N次,在Update事件之后执行

7.OnGUI ()

GUI渲染时间,执行N次,次数是Update事件的俩倍

8.OnDisable () 

禁用事件,执行一次。在OnDestroy事件前执行

9.OnDestroy ()

销毁事件,执行一次。当脚本所挂载的游戏物体被销毁执行。

这些时间执行顺序有1-9不变。

常用API之工具类

1.Screen 屏幕类 

2.Time 时间类

3.Mathf 数学类

1.Screen 包含了与屏幕相关的数据信息,这个类中常用的属性有Screen.width 屏幕的宽度,Screen.height 屏幕的高度,这俩个值取得是Game窗口的宽度和高度,这让我想到了Camera.main.ScreenPointToWorld(Vector3),将屏幕坐标转换为世界坐标

2.Time 最常用的属性有Time.time,指的是从游戏开始到现在所用的时间,Time.timeScale,时间缩放,常用于暂停游戏,值为0,暂停游戏,值为0.5,慢放0.5倍,值为1,正常游戏状态

3.Mathf 包含了各种各样的数学运算相关的函数,常用的函数有Math.Abs() 取绝对值,Mathf.Max 取最大值,Mathf.Min() 取最小值,Mathf.Round() 四舍五入

Mathf.Lerp(float a,float b,float t) : 插值运算

基于t返回a~b之间的值,t的取值范围是0~1,t=0时,返回a,t=0.5时,返回a和b的正中间值,t=1时返回b

例如 a = Mathf.Lerp(a,10,Time.deltaTime) 

a~10的范围不断缩小,a的值固定增长,最后会无限接近于10

它的目的是实现"平滑过渡"

第三部分 物理射线

物理射线?

从屏幕的一个点发射一条无限长的射线,这根射线会与场景中的其他游戏物体身上的碰撞体组件碰撞,触发某些函数事件,射线即结束

由于射线会与物理组件Colider发生交互,所以"射线"也被称为"物理射线"

Camera.main 代表Tag标签为"Main Camera"的摄像机的Camera组件

Camera.main.ScreenPointToRay(Vecotor3)

摄像机Camera组件(对象)下的一个方法

往鼠标位置发射一条射线的完整代码:

private Ray ray;

private RaycastHit hit;

ray = Camera.main.ScreenPointToRay(Input.mousePosition);

检查射线与其他物体的碰撞

RaycastHit     用于存储射线的碰撞信息

if(Physics.Raycast(ray,out hit))

{

         要执行的代码;

}

Physics.Raycast 物理类下边有一个射线检查的方法,这个方法有16种重载方式,这是第3种

实例运用之打砖块

for循环嵌套实例化一堵墙

for(int l = 0,i < 10,i++)

{

for(int h = 0,h < 10,h++)

{

GameObject.Instantiate(object,new Vector3(l,h,0),Quaternion.Indentity);

}

}

这段代码会通过预制体实例化一堵10x10的墙

RaycastHit.point 获取射线的碰撞点

Vector3向量计算方向:

Vector3(终点) - Vector(起点) = 方向(起点像终点)

让砖块五颜六色

GameObject go = GameObject.Instantiate(object,new Vector3(l,h,0),Quaternion.Indentity);

go.GetComponent.material.color = new Color(Rndom.Range(0.0f,1.0f),Random.Range(0.0f,1.0f),Random.Range(0.0f,1.0f));

UnityRGB的取值范围是0~1;

Debug绘制射线,只能在Scene视图下看到,具体代码为:

Vector3 dir = hit.point - m_Transform.position; 

Debug.DrawRay(m_Transform.position,dir,color.red);

第四节 飞盘射击案例

飞盘射击之案例分析

1.UI展示

游戏开始UI : 游戏名称 玩法介绍 开始游戏 退出游戏 

游戏UI : 得分 倒计时

结束UI : 游戏结束 总计得分 重新开始

2.主角控制 物理射线 碰撞函数 

3.AI控制 随机生成障碍物

4.音效特效

5.调整灯光,摆放资源位置

飞盘射击案例之主角控制

手臂朝向碰撞点代码

Transform.LookAt(Vector3) : 朝向世界中的一个点

场景模型添加碰撞器

Mesh Colider组件,使用制作好的简模,降低物理运算消耗,提高游戏性能

Vertices(verts) : 顶点个数,Mesh网格是由顶点组成面,面组成体,Vertices个数越少,计算量越小

控制手臂的旋转中心

新建空物体的方法,用父物体控制子物体,将脚本挂载带父物体身上

从枪口添加激光特效

新建一个空物体,重命名,添加LineRenderer组件,设置相关属性

代码如下:

LineRenderer.SetPosition(int,Vector3) : 设置线的位置

int:0是起点,1是终点

Vector3: 位置

完整代码如下:

LineRenderer.SetPosition(0,m_transform.position);

LineRenderer.SetPosition(1,hit.point);

飞盘案例之飞盘射击

Transform.parent   属性,当前游戏物体的父物体

Transform.GetComponentsInChildren<T>(); 获取所有子物体的某个组件

GameObejct.AddComponent<T>(); 给脚本所在游戏物体添加组件

Transform.SetParent(Transform); 将当前物体设置为另一个物体的子物体

添加背景音效

主摄像机添加音效

添加射击音效 如果按下鼠标左键就播放一次

飞盘射击之游戏管理器

UI界面的搭建

StartUI:

GUIText : 开始游戏

GUIText : 退出游戏

GUIText : 玩法介绍 

GameUI:

GUIText : 总得分

GUIText : 倒计时20s

EndUI:

GUIText : 游戏结束

GUIText : 重新开始

GUIText : 得分

游戏管理器 GameManager Scripts

①创建游戏状态枚举:开始,游戏,结束

public enum GameState {

Start,

Game,

End

}

②查找获取三组UI的引用,并控制他们的显示次序

private GameObject m_startUI;                           //定义三个GameObject类型进行接收

private GameObject m_gameUI;

private GameObject m_endUI;

void Start () {

    m_startUI = GameObject.Find("StartUI");          //查找组件 GameObject.Find() ,返回值类型为GameObject

    m_gameUI = GameObject.Find("GameUI");

    m_endUI = GameObject.Find("EndUI");

}

③定义一个字段存储当前的游戏状态

private GameState gameState;

④定义一个切换游戏状态的方法

public void ChangeGameState(GameState state) //传递过来一个GameStae参数(Start,Game,End),取名state

    {

            gameState = state;                                    //存储传递过来的状态,用定义的引用gameState存储枚举的GameState(Start,Game,End)                 

        if (gameState == GameState.Start)               //开始

        {

            m_startUI.SetActive(true);                         //激活StartUI界面

            m_gameUI.SetActive(false);                     //关闭GameUI界面

            m_endUI.SetActive(false);                        //关闭EndUI界面

            m_bg_audioSource.Stop();                       //停止播放背景音乐

            m_weapon.ChangeCanMove(false);           //获取到Weapon脚本组建后,点获取它的ChangeCanMove方法,里面有俩个参数(true和false)

            m_Weapon.SetActive(false);                    //禁用Weapon对象的所有功能,不显示手臂

            m_feiPan.StopCreat();                              //调用FeiPanGameManager中的StopCreat()方法,即StopCreat方法里的CancelInvoke()

            m_guitext_score.text = "得分:" + score;  //同步重置得分的UI

        }

        else if (gameState == GameState.Game)        //游戏中

        {

            m_startUI.SetActive(false);                       //关闭StartUI

            m_gameUI.SetActive(true);                      //激活GameUI

            m_endUI.SetActive(false);                        //关闭EndUI

            m_bg_audioSource.Play();                      //播放背景音乐

            m_weapon.ChangeCanMove(true);          //激活手臂,ChangeCanMove方法里有俩个布尔值,默认为false,如果为true,默认会发射射线,检测碰撞,添加物理组件,自                                                                          动销毁

            m_Weapon.SetActive(true);                    //激活weapon对象,显示手臂

            m_feiPan.enabled = true;                        //激活FeiPanGameManager脚本组件,生成飞盘

            m_feiPan.StartCreat();                            //调用FeiPanManager脚本组件里的StartCreat()方法,即InvokeRepeating()

            StartTime();                                           //调用StartTIme() 方法

        }

        else if (gameState == GameState.End)        //结束

        {

            m_startUI.SetActive(false);                  //关闭StartUI界面

            m_gameUI.SetActive(false);                //关闭GameUI界面

            m_endUI.SetActive(true);                    //激活EndUI界面

            m_bg_audioSource.Stop();                 //停止播放背景音乐

            m_weapon.ChangeCanMove(false);     //禁用ChangeCanMove方法,包括发射射线,物理射线检测,设置LineRenderer的Position,检测碰撞,射击音效,添加物理组                                                                          件,自动销毁     

            m_Weapon.SetActive(false);              //禁用Weapon对象的所有功能,不显示手臂

            m_feiPan.StopCreat();                       //停止生成飞盘,即CancelInvoke

            m_feiPan.Disapper();                        //立即销毁场景内的所有游戏物体 transform.gameObject,GetComponentInChildren<Transform>(); 

飞盘射击案例之界面逻辑

①开始界面逻辑

          private GameManager gameManager;                    //定义一个GameManager接收脚本

void Start () 

    {

          gameManager = GameObject.Find("UI").GetComponentInChildren<GameManager>();   //获取UI对象下的GameManager脚本组件

    }

void OnMouseDown()                         //鼠标按下事件

    {     

        gameManager.ChangeGameState(GameManager.GameState.Game);          //调用GameManager下的ChangeGameState方法

    }

②游戏界面逻辑

1.新建字段存储分数

    private int score = 0;                            //定义一个int类型的字段存储分数

2.定义一个增加分数的公开方法

public void AddScore()

    {

        score += 1;                                     //分数+1

        m_guitext_score.text = "得分:" + score;      //同步GameUI下的GameScore的GUIText组件

    }

3.在武器射击时调用此方法

if (hit.collider.tag == "FeiPan" && Input.GetMouseButtonDown(0))      //碰撞道德游戏物体的Colider的Tag标签为FeiPan

            {

                    m_gameManager.AddScore();                                             //调用增加分数的方法

           }

4.控制UI显示分数

public void AddScore()

    {

        score += 1;                                                             //分数+1

        m_guitext_score.text = "得分:" + score;          //同步GameUI下的GameScore的GUIText组件的text文本

    }

5.倒计时

   private float time = 20;                //定义时间

   void Update()                               //是在Update中的方法,逐帧调用

    {

        if (satrttime)                           //bool值为True

        {

            time -= Time.deltaTime;                                                                      //倒计时效果

            m_guitext_time.text = "时间:"+ time + "s"                                      //同步倒计时UI,即GameUI下的GameTimeUI的GUIText的text文本

        }

}

飞盘射击之案例总结

结束界面逻辑

1.倒计时为0,修改游戏状态,并且将倒计时重置

if (time <= 0)

            {

                ChangeGameState(GameManager.GameState.End);                  //切换到EndUI

                m_guitext_end.text = "总计得分:" + score;                                   //同步分数

                satrttime = false;                             //重置时间和分数

                time = 20.0f;                  

                score = 0;

           ]

2.结束界面显示总分数

    m_guitext_end.text = "总计得分:" + score;

3.重新开始按钮

        private GameManager m_gamemanager;                 //定义一个GameManager类型接收GameManager脚本组件

    void Start (){

        m_gamemanager = GameObject.Find("UI").GetComponent();          //获取UI对象下的GameManager组件

       }

   void OnMouseDown()                                                     //鼠标按下事件

    {

        m_gamemanager.ChangeGameState(GameManager.GameState.Start);             //返回StarUI,即重新开始按钮

    }

4.细节调整和优化 for循环删除场景内游戏物体

public void Disapper() { 

           Transform[] fp = transform.gameObject.GetComponentsInChildren();                  //取得当前组件的对象下的所有子对象的Transform组件

           for (int i = 1; i < fp.Length; i++)                                                                                   //i = 1,防止父物体身上的FeiPanManager脚本组件被删掉

           {

            GameObject.Destroy(fp[i].gameObject);                                                               //删除所有子物体

           }

    }

本篇完~~~~~~~~~~~

相关文章

网友评论

      本文标题:《飞盘射击》案例总结

      本文链接:https://www.haomeiwen.com/subject/ghjoaxtx.html