EasyAR實踐開發(fā)案列之太空戰(zhàn)機游戲


原創(chuàng)文章查蓉,請勿轉(zhuǎn)載。感謝Q酱颉矢赁!

適合人群

必須會Unity3D引擎基礎(chǔ),對C#腳本編程有一定經(jīng)驗


使用插件

本案列使用前還必須導入以下這些插件
DoTween
優(yōu)秀的動畫插件
FairyGUI
本案例用的是FairyGUI系統(tǒng)贬丛,基礎(chǔ)知識可以到FairyGUI官網(wǎng)學習撩银,當然你可以將UI改造為UGUI系統(tǒng)。


游戲介紹

太空戰(zhàn)機是一款通過識別對應(yīng)的AR游戲卡片結(jié)合實景的敏捷躲避AR游戲豺憔,游戲采用UNITY3D引擎和EasyAR聯(lián)合開發(fā)额获。游戲主要操作方法是利用手機重力感應(yīng)來控制飛機左右移動躲避障礙物,并且有各種各樣的道具輔助玩家獲得高分數(shù)排名恭应。


游戲前期策劃

游戲初期策劃是占一個重要成分抄邀,前期策劃做得好,后期游戲的制作流程會更加明了昼榛,我們可以先坐下來境肾,用筆或紙記錄自己的一點一點的創(chuàng)意,最后整理集合成一個游戲策劃方案。
對于太空戰(zhàn)機這個游戲奥喻,由于玩法比較簡單驼抹,所以策劃方案也不會太復雜定续,游戲策劃大概列出下面這幾點:

  • 利用EasyAR識別圖片后,出現(xiàn)開始界面奔垦,并且出現(xiàn)飛機绣硝,此時飛機不可以被玩家控制
  • 點擊開始按鈕后進入倒數(shù)界面插龄,倒數(shù)5秒上遥,出現(xiàn)游戲界面辩诞,此時飛機可以被玩家控制
  • 用重力感應(yīng)控制飛機左右移動
  • 圓環(huán)和道具從遠處不斷向飛機直線移動,碰到圓環(huán)損失1血酒朵,從圓環(huán)中心通過桦锄,獎勵1分
  • 道具分別是能量包和隕石扎附,能量包用于恢復生命蔫耽,隕石碰撞到后損失2血
  • 當血量為0時,游戲結(jié)束留夜,出現(xiàn)排行版

當然這個初期策劃方案的功能并不是十分完善匙铡,例如后期會增加飛機選擇界面,增加購買飛機商城碍粥,增加更多的道具鳖眼,這些需由你自己去完4善策劃內(nèi)容,這樣你會從中學習到更多的策劃經(jīng)驗嚼摩。


游戲素材準備

通常我們做游戲前钦讳,都需要準備制作該游戲的一些美術(shù)資源,音效資源枕面,如果平時有收集整理自己的素材庫愿卒,那素材的問題很快可以解決,如果平時沒有這個習慣潮秘,可以到UNITY官方資源商店購買下載合適的素材琼开,本案例中的資源包都會通過百度盤共享,可以直接拿來使用枕荞。


申請AppKey

我們首先要到EasyAR官網(wǎng)注冊賬號柜候,然后進入開發(fā)中心,創(chuàng)建一個新應(yīng)用躏精,應(yīng)用名為ARSpaceShip渣刷,注意Bundle ID(iOS) Package Name(Android)這一列,其格式通常為com.公司名.項目名矗烛,所以我們這里按照自己的實際需求來填寫飞主,本案例填寫為com.game4u.arspaceship,最后點擊顯示按鈕,出現(xiàn)AppKey碌识。

申請AppKey


如何制作識別度高的識別圖

識別圖如果識別度比較高碾篡,那么識別后,模型相對會穩(wěn)定筏餐,并且不會出現(xiàn)抖動現(xiàn)象开泽,那么我們應(yīng)該怎樣制作識別度高得識別圖呢?以下我總結(jié)出來幾點經(jīng)驗:

  • 避免重復元素大量出現(xiàn):大量圓圈魁瞪、方形穆律、菱形或者其他相同的形狀,容易出現(xiàn)識別錯誤
  • 避免圖案元素分布不均勻:圖案有區(qū)域出現(xiàn)大片空白导俘、單一顏色或者分布不均勻峦耘,會導致識別錯誤
  • 避免圖案元素過于簡單:識別跟蹤更喜歡“雜亂無章”的圖案,太簡單的圖案旅薄,有可能會導致掃描錯誤
  • 避免圖案全是文字:圖案全部都是文字辅髓,掃描識別圖有可能會出現(xiàn)識別錯誤
  • 避免圖案明暗對比度不明顯:如果圖案全是亮色或者暗色,有可能會導致識別錯誤
  • 避免圖案模糊:圖案需要清晰的細節(jié)才能掃描少梁,如果細節(jié)很模糊洛口,識別圖有可能掃描出錯
  • 避免圖案高度反光: :如果圖案反光嚴重,很容易導致識別圖掃描出錯
  • 避免圖案上印有二維碼:請將二維碼區(qū)域設(shè)置為空白凯沪。當識別圖提供給用戶掃描的時候第焰,可以在空白區(qū)域補充二維碼,不影響識別結(jié)果
  • 避免使用png格式圖

同樣妨马,本案例的識別圖可以在資源包里找到挺举。


制作識別圖數(shù)據(jù)

我們先來制作一下數(shù)據(jù)文件。這個數(shù)據(jù)文件是一個json數(shù)據(jù)烘跺,我們輸入以下內(nèi)容湘纵,并保存文件為targets.json。

{"images" :
  [
    {
      "image" : "arspaceship.jpg",
      "name" : "arspaceship"
    }
  ]
}```
****
#游戲框架初步搭建
素材準備好了后液荸,我們開始制作太空戰(zhàn)機AR游戲瞻佛,打開Unity引擎并創(chuàng)建一個新項目,首先將下載好的EasyAR的unity package導入到項目里娇钱,如圖
![導入EasyAR unity package](http://upload-images.jianshu.io/upload_images/3353184-8b068541ebb29051.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

導入完成后伤柄,我們右鍵Asset文件夾,新建一個自己的游戲文件夾文搂,命名為ARSpaceShip适刀,在這個文件夾里再分別建立Scene(用于放置場景文件),Scripts(用于放置腳本)煤蹭,Modles(用于放置模型)笔喉,Textures(用于放置貼圖)取视,Materials(用于放置材質(zhì)),Prefabs(用于放置預置物)常挚。
如果項目里沒有StreamingAssets和Resources文件夾作谭,我們也應(yīng)該右鍵新建此文件夾,如圖
![建立文件夾](http://upload-images.jianshu.io/upload_images/3353184-335eb2b33ecb7823.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

現(xiàn)在我們在Scene文件夾里新建一個場景奄毡,命名為GameScene折欠,雙擊打開該場景,刪除掉里面的MainCamera和Diretorly Light吼过,找到EasyAR的Prefab目錄锐秦,將EasyAR_Startup組件拖到場景里,然后填寫在官網(wǎng)里注冊的AppKey盗忱,如圖
![填寫AppKey](http://upload-images.jianshu.io/upload_images/3353184-cf736ee08088efdf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
此時我們還需修改一下EasyAR_Startup里面的RenderCamera相機組件的視野屬性酱床,將Clipping Planes的Near和Far分別修改為 0.01和2000,如下圖:

![RenderCamera屬性](http://upload-images.jianshu.io/upload_images/3353184-2f4eba3c7c6da899.png)

我們將識別圖和target.json一起放到StreamingAssets文件夾里趟佃,EasyAR會通過腳本訪問此文件夾獲得資源和數(shù)據(jù)扇谣。接下來同樣在EasyAR的Prefab目錄下的Primitives里將ImageTarget組件拖到場景里,并且將ImageTargetBehaviour腳本移除揖闸。
![5.png](http://upload-images.jianshu.io/upload_images/3353184-f72b8da11a91a2c9.png)

然后在我們的項目文件夾的Scripts目錄右鍵揍堕,新建一個EasyImageTargetBehaviour腳本料身,輸入以下代碼:

using UnityEngine;

namespace EasyAR
{
public class EasyImageTargetBehaviour : ImageTargetBehaviour
{
protected override void Awake()
{
base.Awake();
TargetFound += OnTargetFound;
TargetLost += OnTargetLost;
}

    protected override void Start()
    {
        base.Start();
        HideObjects(transform);
    }

    void HideObjects(Transform trans)
    {
        for (int i = 0; i < trans.childCount; ++i)
            HideObjects(trans.GetChild(i));
        if (transform != trans)
            gameObject.SetActive(false);
    }

    void ShowObjects(Transform trans)
    {
        for (int i = 0; i < trans.childCount; ++i)
            ShowObjects(trans.GetChild(i));
        if (transform != trans)
            gameObject.SetActive(true);
    }

    void OnTargetFound(ImageTargetBaseBehaviour behaviour)
    {
        ShowObjects(transform);
    }

    void OnTargetLost(ImageTargetBaseBehaviour behaviour)
    {
        HideObjects(transform);
    }
}

}

把這段代碼拖到ImageTarget中汤纸,這段代碼的作用是EasyAR如果識別到圖片后,控制ImageTarget里面的所有子物體的顯示和隱藏芹血。然后填寫一下ImageTarget屬性面版里面的一些屬性贮泞,注意Storage需要選擇為Asset模式,如圖:
![輸入識別圖信息](http://upload-images.jianshu.io/upload_images/3353184-d059e9bd65273eb6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**Storages說明**
>**App**
app路徑幔烛,對于不同設(shè)備會有不同路徑啃擦。
Android: 程序持久化數(shù)據(jù)目錄(注意,這個目錄與Unity的Application.persistentDataPath可能不同)
iOS: 程序沙盒目錄
Windows: 可執(zhí)行文件(exe)目錄
Mac: 可執(zhí)行文件目錄(如果app是一個bundle饿悬,這個目錄在bundle內(nèi)部)

>**Assets**
StreamingAssets路徑

>**Absolute**
絕對路徑(json/圖片路徑或視頻文件路徑)或url(僅視頻文件)

>**Json**
表示json string的標志位令蛉,在Target.Load中使用

大家有沒發(fā)現(xiàn)上面的ImageTarget沒有材質(zhì),不太好看狡恬,那么我們可以在自己項目文件夾里的Matertials文件夾右鍵新建一個材質(zhì)ImageTargetMat珠叔,然后拖到ImageTarget的MeshRenderer組件的Materials里面,改變材質(zhì)為Legacy Shaders/Self-Illumin/Diffuse弟劲,把識別圖復制一份到Textures文件夾里拖到材質(zhì)里面祷安,如圖:
![改變ImageTarget材質(zhì)](http://upload-images.jianshu.io/upload_images/3353184-389f13a88fbbbad5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后,我們在ImageTarget里建立一個空的GameObject兔乞,命名為GameWorld汇鞭,此時游戲初步框架完成凉唐。

![建立GameWorld](http://upload-images.jianshu.io/upload_images/3353184-4ccb4e200f0173b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
****
#制作游戲地面
在GameWorld里新建一個GameObject命名為Map,然后在里面新建一個Quad物體命名為Ground霍骄,調(diào)整他的Rotation X軸為90台囱,目的是讓它平放。我們再在Materials文件夾里新建一個GroundMat材質(zhì)读整,將這個材質(zhì)拖動到Ground物體玄坦,最后將識別圖作為貼圖賦值給材質(zhì),并調(diào)整合適大小绘沉,如圖:
![制作游戲地面](http://upload-images.jianshu.io/upload_images/3353184-88b533980c89fcf0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
****
#制作太空戰(zhàn)機
在GameWorld里新建一個GameObject命名為SpaceShipCotroller煎楣,并設(shè)置tag為Player,然后在素材包里面找到太空戰(zhàn)機的模型的文件夾车伞,將它復制到Modles文件夾里择懂,將模型文件拖動到SpaceShipCotroller里作為子物體并將模型的Scale調(diào)為0.008,0.008,0.008,如圖:

![飛機模型](http://upload-images.jianshu.io/upload_images/3353184-f4a1dfde696b34c9.png)
此時如果沒有材質(zhì)另玖,可以將材質(zhì)重新拖到飛機模型上關(guān)聯(lián)即可困曙。我們再調(diào)整一下SpaceShipController的物體的Y軸位置為0.13,Z軸位置為-0.28谦去,如圖:
![調(diào)整飛機大小位置](http://upload-images.jianshu.io/upload_images/3353184-bc747c92e1faf963.png)

在Scripts文件夾里新建一個腳本慷丽,命名為SpaceShipController,拖動到SpaceShipController物體處鳄哭,輸入以下代碼:

using System;
using UnityEngine;

public class SpaceShipController : MonoBehaviour
{
//移動速度
public float Speed = 20f;
//方向
private Vector3 _dir = Vector3.zero;

void Start()
{
}

void Update()
{
    Move();
}

/// <summary>
/// 飛機移動邏輯
/// </summary>
void Move()
{
    _dir.x = Input.acceleration.x;
    if (_dir.sqrMagnitude > 1) _dir.Normalize();
    transform.Translate(Time.deltaTime * _dir * Speed);
}

}


這段代碼的作用是用來控制太空戰(zhàn)機要糊。我們策劃的時候是要通過手機重力感應(yīng)來控制戰(zhàn)機左右移動,UnityAPI提供了移動設(shè)備重力感應(yīng)方法`Input.acceleration`妆丘,只需要通過x值來判斷左右移動锄俄。我們還需要在SpaceShipController的屬性面板中輸入Speed的值,并且調(diào)試一下是否是自己想要的戰(zhàn)機移動速度勺拣,本案例的速度填寫為500奶赠,然后在手機上發(fā)布看看實際效果。此時你掃描識別圖后药有,左右搖動手機毅戈,戰(zhàn)機也跟著左右移動了。
現(xiàn)在看起來戰(zhàn)機移動沒問題愤惰,但是給人感覺有點生硬苇经,需要加一個左右移動的時候機身會跟著側(cè)飛,那么我們選中場景中的SpaceShipController物體羊苟,右鍵新建一個GameObject命名為RotateObject塑陵,然后把我們的模型拖到RotateObject里作為子物體,如下圖:
![RotateObject](http://upload-images.jianshu.io/upload_images/3353184-374aab3aee1d63b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

雙擊SpaceController腳本蜡励,給它增加兩個屬性:

//旋轉(zhuǎn)速度
public float RotateSpeed = 20f;
//需要旋轉(zhuǎn)的物體
public Transform RotateObject;

然后增加多一個側(cè)飛的方法:

/// <summary>
/// 側(cè)飛
/// </summary>
void Rotate()
{
//根據(jù)方向判斷是左旋轉(zhuǎn)還是右旋轉(zhuǎn)
if (_dir.x < 0)
{
RotateObject.localRotation = Quaternion.Lerp(RotateObject.localRotation,Quaternion.Euler(new Vector3(0, 0, 30f)), Time.deltaTime * RotateSpeed);
}
else
{
RotateObject.localRotation = Quaternion.Lerp(RotateObject.localRotation,Quaternion.Euler(new Vector3(0, 0, -30f)),Time.deltaTime * RotateSpeed);
}
}

然后在Update方法處令花,添加Rotate方法:

void Update()
{
Move();
Rotate();
}


最終的SpaceController腳本應(yīng)該如下:

using System;
using UnityEngine;

public class SpaceShipController : MonoBehaviour
{
//移動速度
public float Speed = 20f;
//方向
private Vector3 _dir = Vector3.zero;
//旋轉(zhuǎn)速度
public float RotateSpeed = 20f;
//需要旋轉(zhuǎn)的物體
public Transform RotateObject;

void Start()
{
}

void Update()
{
    Move();
    Rotate();
}

/// <summary>
/// 飛機移動邏輯
/// </summary>
void Move()
{
    _dir.x = Input.acceleration.x;
    if (_dir.sqrMagnitude > 1) _dir.Normalize();
    transform.Translate(Time.deltaTime * _dir * Speed);
}

/// <summary>
/// 側(cè)飛
/// </summary>
void Rotate()
{
    if (_dir.x < 0)
    {
        RotateObject.localRotation = Quaternion.Lerp(RotateObject.localRotation, Quaternion.Euler(new Vector3(0, 0, 30f)),
            Time.deltaTime * RotateSpeed);
    }
    else
    {
        RotateObject.localRotation = Quaternion.Lerp(RotateObject.localRotation, Quaternion.Euler(new Vector3(0, 0, -30f)),
            Time.deltaTime * RotateSpeed);
    }
}

}

寫完代碼后阻桅,再次點擊場景中的SpaceShipController物體,會發(fā)現(xiàn)多了RotateSpeed和RotateObject屬性兼都,先設(shè)置RotateSpeed為2嫂沉,再將場景中的RotateObject拖動到RotateObject屬性l里,如圖:
![設(shè)置屬性](http://upload-images.jianshu.io/upload_images/3353184-6d8e6e4a247ff9a9.png)

現(xiàn)在飛機看起來沒有倒影顯得不是那么真實扮碧,我們可以再素材庫將SpaceShipShadow.png復制到Textures文件夾下趟章,在場景中的SpaceShipController物體右鍵新建一個Quad物體命名為Shadow,去掉組件MeshCollider慎王,在Materials文件夾中新一個SpaceShipShadow材質(zhì)蚓土,將SpaceShipShadow.png拖到材質(zhì)里然后再設(shè)置為透明材質(zhì),設(shè)置完成后將材質(zhì)關(guān)聯(lián)給場景中Shadow物體赖淤,最后調(diào)整Shadow物體的Position Y軸為-0.2蜀漆, Rotation X軸為90度,Scale為0.16,0.16,0.16咱旱,效果如下圖:
![調(diào)整效果](http://upload-images.jianshu.io/upload_images/3353184-f3d41697a4b26de0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

飛機飛行的時候還需要有個噴射效果确丢,在Modles文件夾的SpaceShip文件夾找到SpaceShipEngines的模型,拖動到場景中的SpaceShip模型里面吐限,設(shè)置好大小和材質(zhì)關(guān)聯(lián)鲜侥,效果如圖:
![噴射效果制作](http://upload-images.jianshu.io/upload_images/3353184-4de7afc8fe8b0c6e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

現(xiàn)在讓我們用DoTween來模擬飛行噴射粒子動畫,在場景中的SpaceShip里找到Ship_1_Engines 1物體诸典,添加DoTweenAnimation組件描函,輸入合適的參數(shù),如下圖:
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3353184-803953d748f6bdcd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后我們在Prefab文件夾下新建一個Prefab命名為SpaceShipController搂赋,將場景里的SpaceShipController拖動到這個預置物完成飛機的制作赘阀。
****
#制作圓環(huán)敵人
在GameWorld這個GameObject里益缠,新建一個GameObject命名為RingController脑奠,然后在素材包里面找到圓環(huán)的模型,拖動到RingEnemy里作為子物體調(diào)整好合適的大小幅慌,將Rotation的Y值變?yōu)?80度宋欺,然后在Scripts文件夾里新建一個腳本命名為RingController,拖動到RingController物體處胰伍,輸入以下代碼:

using UnityEngine;
using System.Collections;

public class RingController : MonoBehaviour
{
//移動速度
public float Speed = 20f;

void Start()
{
}

void Update()
{
    Move();
}

/// <summary>
/// 移動邏輯
/// </summary>
void Move()
{
    transform.Translate(Vector3.forward * Speed * Time.deltaTime);
    if (transform.localPosition.z < -1f)
    {
        Destroy(gameObject);
    }
}

}```

這段代碼的作用是用來控制圓環(huán)的齿诞,程序會控制它不斷向前移動,如圖:


圓環(huán)屬性

最后在Prefab文件夾下骂租,新建一個Prefab祷杈,命名為RingController,將場景里的RingController拖動到這個預置物渗饮,刪掉場景中的RingController但汞,后面我們要動態(tài)創(chuàng)建圓環(huán)宿刮。


完善游戲框架

制作好游戲模型的預制物后,我們開始通過程序動態(tài)創(chuàng)建圓環(huán)私蕾。在Scripts文件夾右鍵僵缺,新建SimpleSpawn腳本,輸入以下代碼:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class SimpleSpwan : MonoBehaviour
{
    //敵人Prefab列表
    public List<GameObject> monsterList = new List<GameObject>();
    //敵人生成的Delegate事件
    public delegate void CreateObjectDelegate(GameObject spawnObject);
    public CreateObjectDelegate CreateObjectEvent;
    //生成的間隔時間
    public float spawnTimer;
    //生成的最大數(shù)量
    public int limitSpawn = 1;

    //記錄復制出來的敵人列表
    private GameObject[] spawnList = new GameObject[] { };
    //計數(shù)生成數(shù)量
    private int coutnSpawn = 0;
    //容器
    private Transform _container;

    void Start()
    {
        spawnList = new GameObject[limitSpawn];
        _container = transform;
    }

    public void DoSpawn()
    {
        InvokeRepeating("Spawn", 0.5f, spawnTimer);
    }

    /// <summary>
    /// 生成怪物
    /// </summary>
    public void Spawn()
    {
        for (int i = 0; i < spawnList.Length; i++)
        {
            if (spawnList[i] == null)
            {
                GameObject monsterSpawn = (GameObject)GameObject.Instantiate(monsterList[Random.Range(0, monsterList.Count)]);
                monsterSpawn.transform.SetParent(_container, false);
                SpwanObject ss = monsterSpawn.AddComponent<SpwanObject>();
                ss.spawnerOwner = gameObject;
                spawnList[i] = monsterSpawn;
                coutnSpawn++;
                if (coutnSpawn >= limitSpawn)
                {
                    //生成敵人超過指定數(shù)量踩叭,停止執(zhí)行函數(shù)
                    CancelInvoke("Spawn");
                }

                if (CreateObjectEvent != null)
                {
                    CreateObjectEvent(monsterSpawn);
                }
                return;
            }

        }
    }

    /// <summary>
    /// 偵聽物體Destroy事件
    /// </summary>
    /// <param name="spwanObject"></param>
    public void OnSpawnerObjectDestory(GameObject spwanObject)
    {
        for (int i = 0; i < spawnList.Length; i++)
        {
            if (spawnList[i] == spwanObject)
            {
                spawnList[i] = null;
                //敵人死亡后磕潮,通知事件,如果已經(jīng)是最大值容贝,那么就回復時間繼續(xù)生成
                if (coutnSpawn >= limitSpawn)
                {
                    Debug.Log("less then limitspawn , restart Invoke");
                    InvokeRepeating("Spawn", spawnTimer, spawnTimer);
                }
                coutnSpawn--;
                return;
            }
        }
    }

    /// <summary>
    /// 停止所有生成并清空
    /// </summary>
    public void DespawnAllAndStop()
    {
        for (int i = 0; i < spawnList.Length; i++)
        {
            if (spawnList[i] != null)
            {
                Destroy(spawnList[i]);
                spawnList[i] = null;

            }
            coutnSpawn = 0;
            CancelInvoke("Spawn");

        }
    }

    /// <summary>
    /// 暫停生成
    /// </summary>
    public void Stop()
    {
        coutnSpawn = 0;
        CancelInvoke("Spawn");
    }
}

這段代碼作用是通過計時器控制程序每隔指定秒數(shù)生成一個圓環(huán)物體自脯。核心代碼在public void Spawn(),通過檢測spawnList的元素是否有數(shù)據(jù)斤富,如果沒有數(shù)據(jù)就開始生成一個新的敵人冤今。

接著繼續(xù)在Scripts文件夾右鍵,新建SimpleSpawnObject腳本茂缚,輸入以下代碼:

using UnityEngine;
using System.Collections;

public class SpwanObject : MonoBehaviour
{
    //物體所有者
    public GameObject spawnerOwner;

    void OnDestroy()
    {
        //物體Destroy后發(fā)送事件給SimpleSpwan
        if (spawnerOwner != null)
        {
            spawnerOwner.SendMessage("OnSpawnerObjectDestory", gameObject, SendMessageOptions.DontRequireReceiver);
        }
    }
}```

這段代碼是在物體Destory后戏罢,發(fā)送消息通知SimpleSpawn腳本刪除該物體的引用。

最后脚囊,我們將SimpleSpawn掛到ImageTarget里的GameWorld物體里龟糕,給SimpleSpawn的monsterList的size改為1,然后將RingController預置物拖到屬性里悔耘,將SpawnTimer設(shè)置為3秒讲岁,LimitSpawn設(shè)置為5,如圖:

![設(shè)置SimpleSpawn屬性](http://upload-images.jianshu.io/upload_images/3353184-a73a4c863a783077.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

那么我們?nèi)绾慰刂七@個SimpleSpawn生成物體呢衬以?在場景里右鍵建立一個GameObject命名為Controllers缓艳,然后在Controllers右鍵再建立一個GameObject命名為GameController。然后再Scripts文件夾新建一個GameController腳本看峻,拖動到場景里的GameController物體處阶淘,輸入以下代碼:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GameController : MonoBehaviour
{
//飛機控制器
public SpaceShipController _ShipController;
//生成物體系統(tǒng)
public SimpleSpwan SpwanSystem;
//物體的線路位置
public List<float> ItemPostion = new List<float>();

void Start()
{
    Init();
}

/// <summary>
/// 游戲初始化
/// </summary>
void Init()
{
    SpwanSystem.DoSpawn();
    //SpwanSystem每生成一個物體,都會發(fā)送通知,并且返回這個物體
    SpwanSystem.CreateObjectEvent = (GameObject spawnObject) =>
    {
        Vector3 newpos = spawnObject.transform.localPosition;
        newpos.x = ItemPostion[Random.Range(0, ItemPostion.Count)];
        newpos.z = 1.2f;
        spawnObject.transform.localPosition = newpos;
    };
}

}

我們在屬性面板處將SpaceShipController拖到SpaceShipController屬性里,將GameWorld物體拖動到SpawnSystem屬性里互妓,設(shè)置ItemPostion的值為3溪窒,如圖:
![設(shè)置GameController屬性](http://upload-images.jianshu.io/upload_images/3353184-31c948c6ed52f382.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

發(fā)布到手機運行測試后,你會發(fā)現(xiàn)圓環(huán)會在前方復制冯勉,并且不停移動澈蚌,但是圓環(huán)并不會自動消失,因為我們還沒有給圓環(huán)限制一個范圍灼狰。雙擊RingController腳本宛瞄,我們改寫一下Move方法,給Move方法增加一個移動判斷交胚,代碼如下:

/// <summary>
/// 移動邏輯
/// </summary>
void Move()
{
transform.Translate(Vector3.forward * Speed * Time.deltaTime);
if (transform.localPosition.z < -1f)
{
Destroy(gameObject);
}
}

這段代碼的作用是當圓環(huán)的Z軸到-1后Destory自身份汗,在手機上發(fā)布我們會看到伐厌,圓環(huán)移動到Z軸為-1的位置后消失了,并且SimpleSpawn會重新生成新的圓環(huán)裸影。
****
#添加碰撞
**飛機增加剛體**
給場景中的SpaceShipController物體增加BoxCollider組件和Rigidbody組件挣轨,Rigidbody組件不需要使用重力,參數(shù)調(diào)整如下圖:
![設(shè)置碰撞屬性](http://upload-images.jianshu.io/upload_images/3353184-1e7e9b1e2bec1198.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)將剛體調(diào)整到只有機身部分點擊Apply按鈕即可轩猩,當然你可以擴大剛體范圍卷扮,不過這樣游戲會增大難度。

**圓環(huán)增加剛體**
將Prefabs文件夾的RingController物體拖動到GameWorld里均践,給圓環(huán)整體增加一個BoxCollider組件晤锹,參數(shù)調(diào)整如下圖:
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3353184-cb4663877502ed83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

考慮到飛機可以從圓環(huán)中間穿過,所以我們需要一點技巧來制作多一個剛體彤委,在RingController右鍵建立一個新的GameObject命名為CrossCollider鞭铆,增加一個BoxCollider組件,移動這個BoxCollider的位置焦影,讓這個BoxCollider比圓環(huán)的BoxCollider更加靠前车遂,這樣做的目的是當飛機碰撞到CrossCollider物體后,取消圓環(huán)的剛體碰撞斯辰,讓飛機可以順利穿越舶担,具體參數(shù)調(diào)整如下圖:
![CrossCollider](http://upload-images.jianshu.io/upload_images/3353184-1826228c7539711a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最終效果如下圖:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/3353184-f67773ac880545be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
****
#未完待續(xù)占坑
#
#
#
#
#
#
#
#
****
#制作游戲UI
#發(fā)布游戲
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市彬呻,隨后出現(xiàn)的幾起案子衣陶,更是在濱河造成了極大的恐慌,老刑警劉巖闸氮,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剪况,死亡現(xiàn)場離奇詭異,居然都是意外死亡蒲跨,警方通過查閱死者的電腦和手機译断,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來财骨,“玉大人镐作,你說我怎么就攤上這事÷÷幔” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵羔杨,是天一觀的道長捌臊。 經(jīng)常有香客問我,道長兜材,這世上最難降的妖魔是什么理澎? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任逞力,我火速辦了婚禮,結(jié)果婚禮上糠爬,老公的妹妹穿的比我還像新娘寇荧。我一直安慰自己,他們只是感情好执隧,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布揩抡。 她就那樣靜靜地躺著,像睡著了一般镀琉。 火紅的嫁衣襯著肌膚如雪峦嗤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天屋摔,我揣著相機與錄音烁设,去河邊找鬼。 笑死钓试,一個胖子當著我的面吹牛装黑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弓熏,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼曹体,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了硝烂?” 一聲冷哼從身側(cè)響起箕别,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滞谢,沒想到半個月后串稀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡狮杨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年母截,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橄教。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡清寇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出护蝶,到底是詐尸還是另有隱情华烟,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布持灰,位于F島的核電站盔夜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喂链,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一返十、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧椭微,春花似錦洞坑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瓢剿,卻和暖如春逢慌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背间狂。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工攻泼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鉴象。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓忙菠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纺弊。 傳聞我的和親對象是個殘疾皇子牛欢,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容