AR開發實戰Vuforia項目之守護森林消滅伐木工(塔防游戲)

一、主要框架

二、模型

三、關鍵代碼

Bullet

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

public class Bullet : MonoBehaviour {

    //防御塔的引用
    public GameObject tower;

    //所有敵人的引用;
    private EnemyController[] enemys;

    //開始發射子彈的距離;
    private float distance;

    //最近的敵人;
    private EnemyController nearestEnemy;

    //判斷塔與敵人的距離;
    private float dis;


    //子彈傷害值;靜態的一般公開的才方便調用
    public  static float bulletDamage;

    void Start () {


        //定義傷害值
        bulletDamage = 10f;
    }
    

    void Update () {
        //尋找敵人的方法
        //--------------------------------------------------------------

        //設置最近距離;
        distance = 500f;
        //獲取所有子物體;
        enemys = FindObjectsOfType<EnemyController>();
        //遍歷所有子物體 以獲取最近敵人;
        for (int i = 0; i < enemys.Length; i++)
        {
            //獲取兩物體間的距離
            dis = Vector3.Distance(tower.transform.position, enemys[i].transform.position);
            //判斷是否是防御距離二發射子彈;
            if (dis < distance)
            {
                distance = dis;
                nearestEnemy = enemys[i];
                Debug.Log("最近敵人");
            }

        }
        //--------------------------------------------------------------

        //判斷如果最近敵人不為空 就發射子彈;
        if (nearestEnemy!=null)
        {
           
            //子彈的位置 從塔的位置移向到敵人的位置;
            this.transform.position = Vector3.MoveTowards(this.transform.position,nearestEnemy.transform.position,10f); //參數3:移動速度;
           //塔的方向 朝向 最近敵人的位置;
           tower.transform.LookAt(nearestEnemy.transform);
            if (this.transform.position==nearestEnemy.transform.position)
            {
                //判斷子彈到達最近敵人時候 銷毀子彈
                Destroy(this.gameObject);
                Debug.Log("子彈銷毀");
                //釋放資源
                Resources.UnloadUnusedAssets();
            }
            else
            {
                Destroy(this.gameObject,1f);
            }
        }

        //如果敵人為空 那就把子彈銷毀掉,不要停在半空中;
        if (nearestEnemy==null)
        {
            Destroy(this.gameObject);
            //釋放資源
            Resources.UnloadUnusedAssets();
        }
    }
}

EnemyAnimation

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

/// <summary>
/// 控制敵人動畫
/// </summary>
public class EnemyAnimation : MonoBehaviour {

    //獲取 動畫 組件
    private Animator anim;

    //獲取EnemyController的工具狀態 避免實例化就開始攻擊;
    EnemyController enemyController;


    //播放音效
    private AudioSource mAudioSource;

    void Start () {
        //獲取敵人身上的動畫組件
        anim = this.GetComponent<Animator>();

        //獲取腳本組件;
        enemyController = this.GetComponent<EnemyController>();

        //獲取音效的音頻;
        mAudioSource = this.GetComponent<AudioSource>();
    }
    

    void Update () {

        //判斷塔銷毀的狀態
        if (TowerController.isDamage==false)
        {
            //獲取EnemyControoler腳本上的布爾值 是否可以攻擊
            if (enemyController.isAttack == true)
            {
                //設置動畫狀態的布爾值
                anim.SetBool("Attack", true); //參數1:動畫條件 參數文2:動畫值             
                anim.SetBool("Walk", true);
                anim.SetBool("Idle", false);

            
            }
           
        }
        else if (TowerController.isDamage == true)
        {          
                //設置動畫狀態的布爾值
                anim.SetBool("Attack", false); //參數1:動畫條件 參數文2:動畫值
                anim.SetBool("Walk", false);
                anim.SetBool("Idle",true);
          
        }

    }

    /// <summary>
    /// 播放砍塔的聲音 只需在動畫中插入這個事件就好,不要加括號
    /// </summary>
    public void KanTa() {
        //播放砍塔音效;
        mAudioSource.Play();
    }

}

EnemyController

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

/// <summary>
/// 敵人控制腳本
/// </summary>
public class EnemyController : MonoBehaviour {

    //防御塔的引用
    public GameObject towerPrefab;

    //敵人移動速度;
    private float speed=2f;
    //用來判斷敵人與塔的距離;
    private  float distance;

    //設置布爾值;必須是公開的,方便調用
    public  bool isAttack;

    //設置敵人的攻擊力度 設置靜態方便調用 不用實例化出來
    public static float damage=10f;

    //設置敵人的生命值;
    public  float enemyLife = 80f;


    //獲取畫布的組件以及敵人血條image;
   private  Canvas canvas;
   private  Image blood;

 

    void Start () {

        //剛開始時 不攻擊
        isAttack = false;

        //獲取畫布的組件;
        canvas = this.GetComponentInChildren<Canvas>();
        //獲取血條顯示圖片;
        blood = canvas.GetComponentInChildren<Image>();

    
    }
    
    
    void Update () {

        //只有塔還沒被摧毀的時候才執行這個移動
        if (TowerController.isDamage==false)
        {
            //移動到防御塔
            //  this.transform.position = Vector3.MoveTowards(this.transform.position,towerPrefab.transform.position,2f); //參數1:當前位置 參數2:目標位置 參數3:移動時間
            this.transform.position = Vector3.MoveTowards(this.transform.position, towerPrefab.transform.position, speed);
            //測試
            //if (this.transform.position==towerPrefab.transform.position)
            //{
            //    Debug.Log("兵臨城下");
            //} 

            //返回2點之間的距離;
            distance = Vector3.Distance(this.transform.position, towerPrefab.transform.position);
            //判斷距離停止移動 并且播放攻擊的動畫;設置攻擊為真
            if (distance <= 120f)
            {
                speed = 0;
                isAttack = true;
              
            }
        }
    }

    /// <summary>
    ///子彈與敵人碰撞
    /// </summary>
    /// <param name="other"></param>
    private void OnTriggerEnter(Collider collider)
    {
        if (collider.gameObject.tag=="bullet")
        {
            Debug.Log("敵人被攻擊了");
            //敵人受傷害
            enemyLife -= Bullet.bulletDamage;
            //測試敵人生命值;
            Debug.Log("敵人生命值:"+enemyLife);

            //顯示血條的圖片;
            blood.fillAmount = enemyLife / 80;
            if (enemyLife<=0)
            {
                Destroy(this.gameObject);
                Debug.Log("敵人消滅了!");
              //  enemyLife = 80;
            }

        }
    }


}


MyTrackableEventHandler

using UnityEngine;

namespace Vuforia
{
    /// <summary>
    /// A custom handler that implements the ITrackableEventHandler interface.
    /// </summary>
    public class MyTrackableEventHandler : MonoBehaviour,
                                                ITrackableEventHandler
    {
        //防御塔預制體的引用
        public GameObject towerPrefab;

        //敵人的預制體的引用 數組 隨機生成
        public GameObject[] enemyPrefab;

        //敵人的位置
        // public Transform enemyPoint1;
        public Transform[] enemyPoint;


        //定時器 每隔2秒鐘就生成一個敵人
        public float timeGo = 3f;
        //用來接收輸入時間的
        private  float startTime ;
        //避免update中的方法不斷識別 定義一個標志位
        bool isFoundEnemy;
        #region PRIVATE_MEMBER_VARIABLES

        private TrackableBehaviour mTrackableBehaviour;
    
        #endregion // PRIVATE_MEMBER_VARIABLES



        #region UNTIY_MONOBEHAVIOUR_METHODS
    
        void Start()
        {
            //給時間賦值
            startTime = timeGo;

            //剛開始不可識別;
            isFoundEnemy = false;

            mTrackableBehaviour = GetComponent<TrackableBehaviour>();
            if (mTrackableBehaviour)
            {
                mTrackableBehaviour.RegisterTrackableEventHandler(this);
            }
        }

        #endregion // UNTIY_MONOBEHAVIOUR_METHODS



        #region PUBLIC_METHODS

        /// <summary>
        /// Implementation of the ITrackableEventHandler function called when the
        /// tracking state changes.
        /// </summary>
        public void OnTrackableStateChanged(
                                        TrackableBehaviour.Status previousStatus,
                                        TrackableBehaviour.Status newStatus)
        {
            if (newStatus == TrackableBehaviour.Status.DETECTED ||
                newStatus == TrackableBehaviour.Status.TRACKED ||
                newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
            {
                //事件中識別防御塔的方法;
                OnTrackingFound();
                //重新識別之后塔沒有被破壞
                TowerController.isDamage = false;
                //事件中是識別敵人的方法;
                OnTrackingEnemyFound();
            }
            else
            {
                OnTrackingLost();
            }
        }

        #endregion // PUBLIC_METHODS

        //不斷識別敵人
         void Update()
        {

            //判斷塔的狀態 只有不被銷毀的時候才實例化敵人
            if (TowerController.isDamage==false)
            {
                //時間遞減
                timeGo -= Time.deltaTime;
                //如果時間歸零并且滿足條件為真
                if (timeGo <= 0 && isFoundEnemy == true)
                {
                    OnTrackingEnemyFound();
                    //時間回到初始化值
                    timeGo = startTime;
                }

            }


        }



        #region PRIVATE_METHODS


        private void OnTrackingFound()
        {

            //識別防御塔時候實例化
            GameObject Tower = GameObject.Instantiate(towerPrefab) as GameObject;
            //設置父類
            Tower.transform.parent = this.transform;
            //設置位置
            Tower.transform.position = this.transform.position;


            ////識別敵人
            //GameObject Enemy = GameObject.Instantiate(enemyPrefab[Random.Range(0,3)]) as GameObject;
            //Enemy.transform.parent = this.transform;
            //// Enemy.transform.position = this.transform.position+new Vector3(3,0,3);  //加個位置
            ////敵人的位置
            //Enemy.transform.position = enemyPoint[Random.Range(0, 3)].position;

            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " found");
        }

        /// <summary>
        /// 識別敵人的方法
        /// </summary>
        private void OnTrackingEnemyFound() {

            //找到了設置為真
            isFoundEnemy = true;
            //識別敵人
            GameObject Enemy = GameObject.Instantiate(enemyPrefab[(int)Random.Range(0, 3)]) as GameObject;
            Enemy.transform.parent = this.transform;
            // Enemy.transform.position = this.transform.position+new Vector3(3,0,3);  //加個位置
            //敵人的位置
            // Enemy.transform.position = enemyPoint1.position;
            //位置信息隨機
            int random = (int)Random.Range(0, 3);
            Enemy.transform.position = enemyPoint[random].position;
            //敵人的朝向 第一種方法
            //if (random == 0)
            //{
            //    Enemy.transform.rotation = Quaternion.AngleAxis(120, Vector3.up);
            //}
            //if (random==1)
            //{
            //    Enemy.transform.rotation = Quaternion.AngleAxis(240,Vector3.up);
            //}
            //if (random==2)
            //{
            //    Enemy.transform.rotation = Quaternion.AngleAxis(320,Vector3.up);
            //}
            //敵人的朝向 第二種方法
            Enemy.transform.LookAt(towerPrefab.transform);

        }

        private void OnTrackingLost()
        {
            //沒找到 設置為false
            isFoundEnemy = false;
            //防御塔沒找到的時候
            TowerController tower = GetComponentInChildren<TowerController>();
            //判斷一下沒找的時候銷毀
            if (tower!=null)
            {
                //銷毀
                DestroyImmediate(tower.gameObject);
                //釋放資源
                Resources.UnloadUnusedAssets();
            }


            //同樣 識別丟失的時候敵人銷毀
            //EnemyController enemy = GetComponentInChildren<EnemyController>();
            EnemyController[] enemy = GetComponentsInChildren<EnemyController>();
            if (enemy!=null)
            {
                //for  循環 逐個銷毀、第一種方法
                //for (int i = 0; i < enemy.Length; i++)
                //{
                //    EnemyController E = enemy[i];
                //    Destroy(E.gameObject);
                //}

                foreach (EnemyController E in enemy)
                {
                    DestroyImmediate(E.gameObject);
                    Resources.UnloadUnusedAssets();
                }

                //DestroyImmediate(enemy.gameObject);
                //Resources.UnloadUnusedAssets();
            }

            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost");
        }

        #endregion // PRIVATE_METHODS
    }
}

TowerController

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

public class TowerController : MonoBehaviour {


    //設置塔的生命值
    private float towerLife = 100f;

    //判斷塔是否銷毀(生命值為零時) 公開的 方便敵人停止攻擊動畫的控制
    public static bool isDamage=false;


    //獲取畫布的引用
    private Canvas canvas;

    //獲取畫布下的image;
    private Image blood;


    //子彈的預制體
    public GameObject bulletPrefab;

    //子彈生成時間 計時器
    //  private float timeGo = 0;

    //播放音效
    private AudioSource mAudioSource;

    void Start () {

        //給畫布和血條賦值;
        canvas = GetComponentInChildren<Canvas>();
        blood = canvas.GetComponentInChildren<Image>();

        //獲取子彈發射的音頻;
        mAudioSource = this.GetComponent<AudioSource>();

    }

    void Update () {
        //發射子彈的時間
        //timeGo += Time.deltaTime;
        //if (timeGo>0.3f)
        //{
        //    //執行子彈生成的方法;
        //    CreateBullet();
        //    timeGo = 0f;
        //}
        //以上代碼是測試時用
        //--------------------------
        //點擊屏幕時調用
        if (Input.GetMouseButtonDown(0))
        {
            CreateBullet();

            //播放子彈發射音效;
            mAudioSource.Play();
        }
    }

     void OnTriggerEnter(Collider collider)
    {
        if (collider.gameObject.tag== "weapon")
        {
            towerLife -= EnemyController.damage; //調用敵人的破壞力
            //測試塔的防御值
            Debug.Log(towerLife);

            //顯示血條 畫布下的屬性
            blood.fillAmount = towerLife / 100;

            //判斷生命力小于零的時候 銷毀塔和設置為真
            if (towerLife<=0)
            {
                Destroy(this.gameObject);
                isDamage = true;
            }
        }
    }

    /// <summary>
    /// 實例化子彈的方法
    /// </summary>
    void CreateBullet() {

        //實例化子彈
        GameObject bullet = GameObject.Instantiate(bulletPrefab) as GameObject;
        //設置父類關系
        bullet.transform.parent = this.transform;
        //設置位置
        bullet.transform.position = this.transform.position+new Vector3(0,200,0);
        //設置子彈的隨機顏色
        bullet.GetComponent<MeshRenderer>().material.color = new Color(Random.Range(0f,1f),Random.Range(0f,1f),Random.Range(0f,1f));

        Debug.Log("1111111111111");

    }



}

四、展示效果

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容