美文网首页
Unity官方 《Spaceshooter》学习笔记

Unity官方 《Spaceshooter》学习笔记

作者: 小海龟我们走 | 来源:发表于2016-06-11 10:57 被阅读780次

           在写学习笔记之前,我先说说为什么会做这么一个游戏DEMO吧,目前是在一家互联网广告公司任职3D设计组长一职,主要内容是CG这块,因为对AR和VR很感兴趣,并且暂时选择了Unity这款游戏引擎做为我的敲门砖,因为CG是我的优势,所以对Unity这款软件不陌生,上手很快,唯一比较陌生的是程序代码这块,但因为大学的时候学过C和游戏编程,所以倒不止于看到程序就放弃,只是工作一两年完全没接触程序了。因此我决定在上手了Unity软件后,准备啃下Unity中编程这块硬骨头。我选择了C#这门语言来学习,因为市面上大多数AR和VR教程都是用C#来写的,这样学习起来方便一些。

           我先在在网上学习了一些Unity的C#基础知识,比如GameObject,Transform,枚举,方法等,对Unity中编程的基础知识有了一些了解,接着我觉得还得跟着一些教程做练习,理解消化,跟着官方教程是一个很不错的选择,接下来就进入我的Spaceshooter笔记。                                                  

    一:教程的前5个课时讲述的是3D知识,比如相机灯光背景和特效等,表示毫无压力跳过

    二:角色控制、发射子弹

    代码如下:

    using UnityEngine;

    using System.Collections;

    public class spaceshooter : MonoBehaviour {

                 public float speed;

                 public float rt;

                 public float xMin;

                 public float xMax;

                 public float zMin;

                public float zMax;

        publicGameObjectshot;

        publicTransformshotspawn;

        publicfloatfirerate;

        privatefloatnextfire=0.0f;

    voidUpdate(){

          if(Input.GetButton("Fire1")&&Time.time>nextfire){

          nextfire=Time.time+firerate;

         Instantiate(shot,shotspawn.position,shotspawn.rotation);

    }

    }

       void FixedUpdate()   {

               float mh = Input.GetAxis ("Horizontal");

                float mv =  Input.GetAxis ("Vertical");

                Rigidbody rigidbody =GetComponent();

                Vector3 movement = new Vector3 (mh, 0.0f, mv);

                 rigidbody.velocity = movement*speed;

                 transform.rotation= Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x* rt);

                  transform.position = new Vector3 (

                 Mathf.Clamp (transform.position.x,xMin,xMax),

                 0.0F,

                 Mathf.Clamp(transform.position.z,zMin,zMax)

                 );

        }

    }

    这段代码主要实现了以下功能

    1:这段代码首先没有写在Unity默认的Update函数中,而是写在了FixedUpdate()函数中,在网上搜了一下Update和FixedUpdate的区别,Update()和FixedUpdate()在游戏中都会在更新的时候自动循环调用。但是Update是在每次渲染新的一帧的时候才会调用,也就是说,这个函数的更新频率和设备的性能有关以及被渲染的物体(可以认为是三角形的数量)。在性能好的机器上可能fps 30,差的可能小些。这会导致同一个游戏在不同的机器上效果不一致,有的快有的慢。因为Update的执行间隔不一样了。而FixedUpdate,是在固定的时间间隔执行,不受游戏帧率的影响。所以处理Rigidbody的时候最好用FixedUpdate。

    PS:FixedUpdate的时间间隔可以在项目设置中更改,Edit->Project Setting->time找到Fixed timestep。就可以修改了。

    2:关于Rigidbody调用的问题,官方案例是4.6版本,可以直接调用rigidbody,但5.0以后的版本中,Unity将C#规范了,要调用rigidbody必须要定义,比如Rigidbody r=GetComponent<Rigidebody>()来定义。

    3:通过键盘上的"W" "A" "S" "D"或者方向键来控制飞船的前后左右的移动,左右是通过Input.GetAxis ("Horizontal")和Input.GetAxis ("Vertical")来实现,它们都是Vector3类型并且值范围都是在-1到1之间 ,此时定义一个访问修饰符为public且float类型的speed来控制飞船的速度;

    4:用Math.Clamp方法来控制飞船移动边界,通过查阅官方文档知道,Math.Clamp返回的是一个float类型value的值,写法是Math.Clamp(float value,float min,float max)

    5:设定飞船的旋转边界值,rotation是一个Quaternion类型的值,用Quaternion.Euler来表示物体的旋转,物体在x和y方向上的旋转为0 ,在z方向上的旋转跟物体的速度正负值挂钩,所以用rigidbody.velovity.x来表示,这样,按下方向键,向左或者向右时,飞船就能够发生“侧翻”效果.

    6:Instantiat方法的使用,参照官方文档,Instancitate是用来实例化物体的,使用方法是Instantiate (Object Original,Vector3 position,Quaternion rotation),Object是要实例化的对象,Vector是要复制到的位置,Quaternion是设置物体的旋转。

    7:Time.time方法用来获取游戏运行的时间,在本例中用来设置按下鼠标左键后间隔多少时间发射下一发子弹。

    8:Input.GetButton("FIre1")代码块中,Fire1表示鼠标左键,Fire0表示鼠标中间,Fire2表示鼠标右键,而且Input.GetButton表示持续按下Fire1,同类型的还有Input.GetButtonDown和Input.GetButtonUp也表示按下按键,但是只能计算一次按下或者弹起。

    二:边界

    voidOnTriggerExit(Colliderother){

    Destroy(other.gameObject);

    }

    调用了Trigger中的一个方法,即离开这个边界的物体都会被“杀死”,条件就是只要触碰到了边界物体的Collider就会调用这个方法,Destroy中的参数是other.gameobjet,表明只会杀死其他的物体,而不会把自身给销毁掉,跟后面要用到的碰撞方法有区别。

    三 创建激光

    void Start() 

    {

    Rigidbodyrigidbody=GetComponent();

    rigidbody.velocity=transform.forward*speed;

    rigidbody.angularVelocity=Random.insideUnitSphere*tumble;

    }

    1:这个代码是用来表示行星的产生方向和起始随机的旋转速度,transform.forward用来表示z轴方向上的速度,为(0,0,1)

    2:rigidbody.angularVelocity用来表示物体的旋转角速度,是一个Vector3类型的,而随机的起始速度则由Random类中的insideUnitSphere来表示,它是一个半径为1的球,方向是-1到1,并且这个方法只能放在Start函数中只能调用一次,自己在做的时候,放在了Update()函数中,导致这个产生的行星都像发了疯似的旋转,因为每一帧都会更新它的角速度,而这个角速度又是随机产生的。

    四 爆炸 

    代码如下

    publicGameObjectzidanbaozha;

    publicGameObjectfeichuanbaozha;

    publicGameObjectzidanbaozhashengyin;

    publicGameObjectfeichuanbaozhashengyin;

    voidOnTriggerEnter(Colliderother){

    //自己的写法

    if(other.tag=="Boundary")//这里的if是不让边界盒子跟行星发生碰撞

    {

    return;//这里的return是返回一个空的值,表示什么也不做,也可以不写这个return

    }

    if(other.tag=="Bolt")

    {

    Destroy(other.gameObject);

    Destroy(gameObject);

    Instantiate(zidanbaozha,transform.position,Quaternion.identity);

    Instantiate(zidanbaozhashengyin,transform.position,Quaternion.identity);

    }

    if(other.tag=="Player")

    {

    Destroy(other.gameObject);

    Destroy(gameObject);

    Instantiate(feichuanbaozha,transform.position,Quaternion.identity);

    Instantiate(feichuanbaozhashengyin,transform.position,Quaternion.identity);

    }

    if(other.tag=="xingxing")

    {

    Destroy(other.gameObject);

    Destroy(gameObject);

    Instantiate(zidanbaozha,transform.position,Quaternion.identity);

    }

    //官方教程的写法

    /*if(other.tag=="Boundary")//这里的if是不让边界盒子跟行星发生碰撞

    {

    return;//这里的return是返回一个空的值,表示什么也不做,也可以不写这个return

    }

    Instantiate(zidanbaozha,transform.position,Quaternion.identity);

    if(other.tag=="Player")

    {

    Instantiate(feichuanbaozha,transform.position,Quaternion.identity);

    }

    Destroy(other.gameObject);

    Destroy(gameObject);*/

    1:这里的代码是分类子弹的collider碰撞到不同的物体的时候,会有不同的爆炸特效,判断的一句是gameobject的Tag。我的写法相比官方的想法可能会更死板,不简练,但毕竟不是写代码的老手,这样写代码方便自己理解,以后代码量上去了我相信自己还是能够养成良好的代码习惯。

    2:这里的Quaternion.identity表示物体没有旋转。

    五 生成波

    代码如下

    publicGameObjecthazard;

    publicVector3spawnwaves;

    publicinthazardcount;

    publicfloatwaittime;

    publicfloatspawntime;

    publicfloatjiangeshijian;

    voidStart(){

    StartCoroutine(SpawnWaves());

    }

    IEnumeratorSpawnWaves(){

    yieldreturnnewWaitForSeconds(waittime);

    while(true)

    {

    for(inti=0;i

    {

    floata=Random.Range(-4.76f,4.76f);

    hazard.transform.position=newVector3(a,0.0f,14.0f);

    hazard.transform.rotation=Quaternion.identity;

    Instantiate(hazard,hazard.transform.position,hazard.transform.rotation);

    yieldreturnnewWaitForSeconds(spawntime);

    }

    yieldreturnnewWaitForSeconds(jiangeshijian);

    }

    }

    1:这里的代码是让“敌人”也就是行星能够一波一波地产生,并且在每次游戏开始之前,会过1s后才开始,让玩家做好游戏准备,并且“敌人”会一波一个产生,每一波之间也会有间隔时间。

    2:这里用到了SpawnWaves()方法,其实我觉得有没有这个方法也是一样的,因为能够产生一波一波效果的主要是协同方法中的WaitForSeconds类来控制的,而且SpawnWaves()方法必须要在void Star()方法中手动调用才行。

    3:能够实现一波一波效果的,最关键是用到了协同函数,来实现延迟的效果也就是StartCoroutine(method name)方法,查看官方文档知道,StartCoroutine(方法名)就能启用Coroutine方法,并且返回值的类型不再是void,而是IEnumerator,并且用关键字yield return new WaitForSeconds (float value)来标识WaitForSeconds类,这里的value是标识延迟的时间。(http://docs.unity3d.com/ScriptReference/WaitForSeconds.html)这里插入官方文档关于如何调用Coroutine,并且使用WaitForSeconds来实现延迟效果有很好的解释

    六 结束游戏

    在这一块中,主要困惑点是在重新加载当前游戏的api,因为官方教程用的是4.2的版本,用Application.loadlevel(Application.loadlevel) 来加载当前场景,当时在5.3版本中完全不能用,在5.3版本中使用SceneManager.LoadScene(scene name or index of the scene),并且在用这个类的时候,还必须引用Scene Management,在官网文档中其实也没解释清楚,在网上搜了好久才知道这个的用法,最终,在5.3中重新加载当前场景,我的代码是

    usingUnityEngine;

    usingSystem.Collections;

    usingUnityEngine.SceneManagement;

    publicclassGameController:MonoBehaviour{

    void Update()

    {

     if (gameover)

    {

         if(Input.GetKeyDown(Keycode.R))
       {

          SceneManager.LoadScene(0);

       }

    }

    }

    }

    这样就当按下R键的时候,就会重新加载当前的场景,重新开始游戏

    相关文章

      网友评论

          本文标题:Unity官方 《Spaceshooter》学习笔记

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