Unity武器系統的最佳化

來源:互聯網
上載者:User

標籤:

Unity武器系統的最佳化

 

射擊遊戲子彈是最基本的遊戲對象,當然使用unity開發的話,做一個子彈並不是很難的事,從發射到子彈的飛行,到銷毀,基本上入門的程式員都能寫出來。

  然而這個看似簡單的東西,有著很大的最佳化空間。這個最佳化分兩部分,一是,子彈的發射最佳化,另一個是子彈的碰撞檢測最佳化。

     對於發射時的最佳化,主要考慮到子彈這個遊戲對象使用頻率比較高,一個關卡裡,要產生和銷毀大量的遊戲對象,從記憶體載入到執行個體化,然後執行銷毀動作,速度,效能太差,而且因為unity的記憶體管理並不好,因此為產生大量的記憶體垃圾,如果遊戲時間一長,或者在安卓等低端平台運行時就會造成卡頓現象。關於解決這個問題,網上有很多方案,也有現成的外掛程式,PoolManager等,管理對象的執行個體化和銷毀。當然可以自己寫一個簡單點的東西來最佳化這一過程。怎麼做呢?

原理就是重複利用子彈。用一個數組來儲存子彈的引用,初始化的時候全部隱藏,射擊的時候按照數組下標依次啟用。一個子彈打出去後,到了回收的時候,不要銷毀,而是將其“隱藏”,並做初始化處理。這個過程還可以最佳化,例如一個彈夾的子彈數量是30,實際上你只需要預先載入15發子彈就可以了。依次啟用,重複利用。

代碼中有詳細的注釋,我就不多說了。

 

using UnityEngine;using System.Collections;using System.Collections.Generic;public class GunShot : MonoBehaviour{    public string weaponName;//武器的名稱,使用Resource載入    private List<BullectOfWeapon> weapons;//用List集合儲存子彈對象數組    public int shellCount = 20;//一個彈夾的子彈數量    public int maxShell=10;//預先載入子彈數量,因為可以迴圈利用,可以小於等於彈夾的子彈數量    private int currentShell = 0;//當前啟用的子彈        public float fireRote=0.2f;//開火時間間隔,一次射擊到下一次的時間    private float currentFireTime;//目前時間    public float loadTime = 1.5f;//上子彈的時間。    private float currentLoadTime = 0;    private int currentCount;//一個彈夾打出去的子彈數    public int chargerCount=5;//彈夾的數量    void Start() {        InitGun();//初始化武器    }    void Update() {        if (!isLoading()&&  Input.GetButton("Fire1")&&checkFire()) {//注意條件順序,寫反就不對了            Shot();//開火代碼        }    }    public void InitGun()//初始化武器    {        //武器的名稱,使用Resource載入        BullectOfWeapon _weaponModel = Resources.Load<BullectOfWeapon>(weaponName);                if (_weaponModel)        {            weapons = new List<BullectOfWeapon>();            for (int i = 0; i < maxShell; i++)            {                //執行個體化子彈對象                BullectOfWeapon _weapon = Instantiate(_weaponModel);                //將其隱藏                _weapon.gameObject.SetActive(false);                //初始化子彈,將子彈放在“彈夾裡”,將產生的子彈作為子物件                //這麼做可以方便管理                _weapon.InitWeapon(transform);                //將子彈對象的引用添加至集合                weapons.Add(_weapon);            }        }        _weaponModel = null;//釋放子彈對象,這個可以讓系統能更好多份對記憶體進行回收    }    public bool checkFire() {//根據上一次開火的時間判斷是否可以開火        currentFireTime += Time.deltaTime;        if (currentFireTime >= fireRote) {            currentFireTime = 0;            return true;        }        return false;    }    public bool isLoading() {        if (chargerCount == 0) return true;//彈夾使用完畢        if (currentCount < shellCount) { //判斷是否已經            return false;        }        currentLoadTime += Time.deltaTime;        if (currentLoadTime >= loadTime) {            currentLoadTime = 0;            chargerCount--;//減少彈夾的數量            currentCount = 0;//下一個彈夾從零計數            return false;        }        return true;    }    public void Shot() {        if (weapons!=null && weapons.Count > 0) {//先判斷子彈數組防止為空白            if (!weapons[currentShell].gameObject.activeSelf)//檢查當前子彈是否正在使用            {                weapons[currentShell].ActiveWeapon();//將子彈啟用                currentShell = (currentShell + 1) % maxShell;//移動下標                currentCount++;            }                    }    }}
public class BullectOfWeapon : MonoBehaviour{    private Transform charger;//彈夾,用來回收時將子彈對象放在父物體裡,方便資源的管理        public float lifeTime = 3;//子彈的存留時間    public float maxSpeed;//子彈移動的最大速度    private Vector3 velocity;//子彈的即時速度    private Vector3 currentPos;//子彈的當前位置    private Vector3 nextPos;//子彈的上一個位置    private bool isHit;//是否碰撞    private float distence;    private RaycastHit hit;    public void InitWeapon(Transform parent) {//初始化子彈        if (!charger) this.charger = parent;//將子彈作為子物件放在“彈夾裡”        transform.parent = charger;        //位置,角度歸零        transform.localPosition = Vector3.zero;        transform.localRotation = Quaternion.identity;            }    public void ActiveWeapon() {//啟用子彈               currentPos = nextPos = transform.position;//初始化當前位置和下一個位置        isHit = false;//        velocity = maxSpeed * transform.forward.normalized;//初始化速度        transform.parent = null;//將子彈從彈夾分離出去        gameObject.SetActive(true);        //開啟協程,lifeTime之後將物體再次隱藏        StartCoroutine(DestroyWeapon(gameObject,lifeTime));    }    public IEnumerator DestroyWeapon(GameObject desObj, float desTime) {        yield return new WaitForSeconds(desTime>0?desTime:0);        if (desObj.activeSelf)        {            desObj.SetActive(false);            //隱藏子彈後重新初始化,為下一次使用做準備            InitWeapon(charger);        }            }    void Update() {        Fire();    }    public void Fire() { //這個是子彈的被射出後的飛行與碰撞檢測代碼        if (!isHit)//沒有發生碰撞保持飛行        {            Flying();        }           }    private void Flying() {//子彈的飛行          }   }

 

 

 

以上就是槍和子彈的部分代碼。關於特效,力什麼的我就省略了。接下來來探討一下子彈的飛行與碰撞的檢測。

一般新手做子彈,使用transform+碰撞器+剛體,這樣的子彈效能不高,而且極容易發生穿牆事件。Unity官方計程車兵射擊範例就是這麼搞的,為了防止穿牆,子彈的飛行速度很慢,看起來很假。

學過射線的,估計會使用射線的碰撞檢測,判斷子彈是否擊中目標。然後在碰撞點產生火花特效等。這樣的子彈不會穿牆,但是少了子彈飛行的效果。然後就有人用發射一個粒子來展示子彈的飛行。

對於上面的兩種方案,第一種是要果斷放棄的,效能差。第二種效能比較好,我來將其最佳化一下,讓子彈看起來更像子彈,就是射線檢測+子彈飛行效果。通過修改子彈的位移,來類比飛行效果,使用射線檢測碰撞。這樣效能和效果都有了。好不多說看實現代碼。

private void Flying() {//子彈的飛行        nextPos += velocity * Time.deltaTime;//使用平滑過渡不用擔心穿牆問題                distence = (nextPos-currentPos).magnitude;        if (distence > 0) {            if (Physics.Raycast(currentPos,transform.forward,out hit,distence))            {                                isHit = true;                nextPos = hit.point;//將下一個目標點設定為碰撞點            }        }        currentPos = transform.position;//擷取當前位置        transform.position = nextPos;//將當前位置置於下一個點        if (isHit)//碰撞後將子彈隱藏回收        {            StartCoroutine(DestroyWeapon(gameObject,0));        }    }

 

關於特效我就不多說了。使用TrailRenderer可以類比子彈的軌跡,簡單實用。力效果什麼的大家自行加上。

上面就是最佳化後的武器系統,設計原理儘可能的節省記憶體,並提升自身效能,同時保證系統的正常使用。上面的方法可以同樣使用在特效上,用數組儲存火花粒子,彈殼,或者子彈貼圖,這樣在不失真的情況下還能保證系統效能。例如規定彈孔貼圖的數量,然後就是動態,每產生一個彈孔後,不是銷毀,而。當彈孔數量達到最大值時,將以前的彈孔貼圖放在新的碰撞點即可。而不是重複的執行載入執行個體和銷毀,那樣對系統的記憶體和效率影響更大。因為一個遊戲對象的初始化過程和對應指令碼的載入是很耗時的,儘管這對CPU來說是小事。

 本文的連結:http://www.cnblogs.com/jqg-aliang/p/4714750.html。轉載請申明出處,謝謝!

Unity武器系統的最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.