【Unity 3D】學習筆記(三)

基本操作演練


  • 下載 Fantasy Skybox FREE, 構建自己的遊戲場景

天空是任何遊戲離不開的設定,而且要按季節與時間變化,是表示時間的重要工具。天空盒是一種材料,我們可以通過六面體構建一個天空盒。

首先點擊Asset上下文菜單 -> create -> Material,命名爲sky。然後在Inspector視圖中選擇Shader -> Skybox -> 6Sided,向六面體中添加貼圖:

要使用天空盒,就要向Camera對象中添加部件Rendering -> Skybox,拖放sky即可。

查看遊戲場景,發現原始的天空場景已經改變:

也可從Asset Store下載Skybox資源使用來構建遊戲場景。

 

  • 寫一個簡單的總結,總結遊戲對象的使用

GameObjects are the fundamental objects in Unity that represent characters, props, and scenery. They do not accomplish much in themselves but they act as containers for Components, A functional part of a GameObject. A GameObject can contain any number of components. Unity has many built-in components, and you can create your own by writing scripts that inherit from MonoBehaviour.

見上面API對遊戲對象的說明,遊戲對象本身作爲組件的容器使用,可以通過向其中添加不同的組件來調用不同的功能。

例如,如下一個對象掛載了light組件,便擁有了相關的屬性。

一個遊戲對象總是有Transform這個組件。此組件是用來在遊戲空間中表示對象的位置和旋轉角度的,並且不可去除。

編寫腳本操控遊戲對象Tranform屬性的變換,即可完成對對象的運動控制。

 

編程實踐


牧師與魔鬼 動作分離版

  • 【2019新要求】:設計一個裁判類,當遊戲達到結束條件時,通知場景控制器遊戲結束

上圖是之前版本牧師與魔鬼的MVC結構,注意到場記(控制器)管的事太多,不僅要處理用戶交互事件,還要進行遊戲對象加載、遊戲規則實現、運動實現等等工作,顯得非常臃腫。對這個問題,一個最直觀的想法就是讓更多的人(角色)來管理不同方面的工作。顯然,這就是面向對象基於職責的思考,例如:用專用的對象來管理運動,專用的對象管理播放視頻,專用的對象管理規則。就和踢足球一樣,自己踢5人場,一個裁判就夠了,如果是國際比賽,就需要主裁判、邊裁判、電子裁判等角色通過消息協同來完成更爲複雜的工作。

對於新的要求,需要設計一個裁判類協同場景控制器判斷遊戲是否結束。

爲了用一組簡單的動作組合成複雜的動作,我們採用 cocos2d 的方案,建立與 CCAtion 類似的類。動作管理器結構設計如下:

設計思路如下:

  • 設計一個抽象類(SSAction)作爲遊戲動作的基類
  • 設計一個動作管理器類管理一組遊戲動作的實現類
  • 利用接口(ISSActionCallback)回調,實現動作完成時的通知,避免與動作管理者直接依賴

 

SSAction

public class SSAction : ScriptableObject {
    public bool enable = true;
    public bool destroy = false;
    public GameObject gameobj;
    public Transform trans;
    public ISSActionCallback callback;

    protected SSAction() { }
    public virtual void Start() {
        throw new System.NotImplementedException();
    }
    public virtual void Update() {
        throw new System.NotImplementedException();
    }
}

SSAction是所有動作的基類。ScriptableObject是不需要綁定GameObject對象的可編程基類,這些對象受Unity引擎場景管理。

protected 防止用戶自己 new 對象

使用 virtual 申明虛方法,通過重寫實現多態。這樣繼承者就明確使用 Start 和 Update 編程遊戲對象行爲

 

SSMoveToAction

public class SSMoveToAction : SSAction {
    public Vector3 goal;
    public float speed; 

    private SSMoveToAction() { }
    public static SSMoveToAction GetSSAction(Vector3 goal, float speed) {
        SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();
        action.goal = goal;
        action.speed = speed;
        return action;
    }

    public override void Update() {
        this.trans.position = Vector3.MoveTowards(this.trans.position, goal, speed * Time.deltaTime);
        if (this.trans.position == goal) {
            this.destroy = true;
            this.callback.SSActionEvent(this);
        }
    }

    public override void Start() { }
}

讓Unity創建動作類,確保內存正確回收。SSMoveToAction實現移動的動作,使對象以speed的速度向目的地goal移動。當此動作完成時通過callback告訴動作管理者。

 

SequenceAction

public class SequenceAction : SSAction, ISSActionCallback {
    public List<SSAction> actList;
    public int repeat = -1;
    public int start = 0;

    public static SequenceAction GetSSAcition(int rep, int st, List<SSAction> act) {
        SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();
        action.repeat = rep;
        action.actList = act;
        action.start = st;
        return action;
    }

    public override void Update() {
        if (actList.Count == 0) return;
        if (start < actList.Count) actList[start].Update();
    }

    public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null) {
        source.destroy = false;
        this.start++;
        if (this.start >= actList.Count) {
            this.start = 0;
            if (repeat > 0) repeat--;
            if (repeat == 0) {
                this.destroy = true;
                this.callback.SSActionEvent(this); 
            }
        }
    }

    public override void Start() {
        foreach (SSAction action in actList) {
            action.gameobj = this.gameobj;
            action.trans = this.trans;
            action.callback = this;
            action.Start();
        }
    }

    void OnDestroy() { }
}

SequenceAction用來實現一個動作組合序列,順序播放動作。

  • 讓動作組合繼承抽象動作,能夠被進一步組合;實現回調接受,能接收被組合動作的事件
  • 創建一個動作順序執行序列,-1 表示無限循環,start 開始動作。
  • Update方法執行執行當前動作
  • SSActionEvent 收到當前動作執行完成,推下一個動作,如果完成一次循環,減次數。如完成,通知該動作的管理者
  • Start 執行動作前,爲每個動作注入當前動作遊戲對象,並將自己作爲動作事件的接收者
  • OnDestory 如果自己被註銷,應該釋放自己管理的動作。

 

SSActionEventType

public enum SSActionEventType : int { Started, Competeted }

public interface ISSActionCallback {
    void SSActionEvent(SSAction act, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null);
}

SSActionEventType使用枚舉變量來定義事件類型,並定義了事件接口。因此,所有的事件管理者都必須實現這個接口,從而實現事件調度。組合事件和事件管理器都必須實現它。

當動作管理者繼承並實現這個接口時,每當動作完成,就會調用這個接口,發送通知告訴動作管理器對象。利用接口實現回調,可以避免與動作管理者直接依賴。

 

SSActionManager

public class SSActionManager : MonoBehaviour, ISSActionCallback {
    private Dictionary<int, SSAction> act = new Dictionary<int, SSAction>();
    private List<SSAction> add = new List<SSAction>();
    private List<int> delete = new List<int>();

    protected void Update() {
        foreach (SSAction ac in add) act[ac.GetInstanceID()] = ac;
        add.Clear();
        foreach (KeyValuePair<int, SSAction> kv in act) {
            SSAction ac = kv.Value;
            if (ac.destroy) delete.Add(ac.GetInstanceID());
            else if (ac.enable) ac.Update();
        }
        foreach (int key in delete) {
            SSAction ac = act[key];
            act.Remove(key);
            DestroyObject(ac);
        }
        delete.Clear();
    }

    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) {
        action.gameobj = gameobject;
        action.trans = gameobject.transform;
        action.callback = manager;
        add.Add(action);
        action.Start();
    }

    public void SSActionEvent(SSAction act, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null) { }
}

SSActionManager時動作對象管理器的基類,實現了所有動作的基本管理。這個類通過繼承ISSActionCallback獲取完成動作時的反饋信息,來決定遊戲對象做某個動作或是一串連續的動作。

 

checkController

public class checkController {
    public int check(int[] fromNum, int[] toNum, int[] boatNum, int direction) {
        int from_priest = 0, from_devil = 0, to_priest = 0, to_devil = 0;
        from_priest += fromNum[0];
        from_devil += fromNum[1];
        to_priest += toNum[0];
        to_devil += toNum[1];
        if (to_priest + to_devil == 6) return 2;
        if (direction == -1) {
            to_priest += boatNum[0];
            to_devil += boatNum[1];
        }
        else {
            from_priest += boatNum[0];
            from_devil += boatNum[1];
        }
        if ((from_priest < from_devil && from_priest > 0) || (to_priest < to_devil && to_priest > 0)) return 1;
        return 0;
    }
}

增加了一個裁判類,用來判定遊戲是否結束。一旦遊戲結束,UserGUI即會得到信息來打印出勝或敗的遊戲結果。

 

完成以上的動作管理框架,對之前的代碼稍作修改,即得到了動作分離版的魔鬼與牧師,成果如下:

對於這個小遊戲來說,順序動作序列也就只有一種,實現動作分離的框架看起來優點也沒有那麼明顯,但是當遊戲的功能進一步擴展、遊戲對象的動作進一步複雜化,動作管理的框架就能體現出便利性。

視頻傳送門

 

材料與渲染練習


  • 從 Unity 5 開始,使用新的 Standard Shader 作爲自然場景的渲染。

The Unity Standard Shader is a built-in shader with a comprehensive set of features. It can be used to render “real-world” objects such as stone, wood, glass, plastic and metal, and supports a wide range of shader types and combinations. Its features are enabled or disabled by simply using or not using the various texture slots and parameters in the material editor.

向場景中添加一個樹型預製和一個球體,新建Material並拖動到這兩個對象上,修改shader的屬性查看效果。

首先可以改變color屬性,效果如下:

將rendering mode勾選爲transparent,可以調整color中的A值,即調整透明度。僅修改上圖對象的透明度,效果如下:

還可以更改Metallic,效果對比如下:

修改smoothness,效果對比如下:

 

  • Unity 5 聲音
    • 閱讀官方 Audio 手冊
    • 用博客給出遊戲中利用 Reverb Zones 呈現車輛穿過隧道的聲效的案例

A game would be incomplete without some kind of audio, be it background music or sound effects. Unity’s audio system is flexible and powerful. It can import most standard audio file formats and has sophisticated features for playing sounds in 3D space, optionally with effects like echo and filtering applied. Unity can also record audio from any available microphone on a user’s machine for use during gameplay or for storage and transmission.

首先創建音源,建一個空對象,並掛載 AddComponent -> Audio -> Audio Source和Audio Reverb Zones。然後下載要用到的聲音資源,將其拖放入音源部件。

將Reverb Zone的Preset設爲Cave:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章