3D遊戲設計 homework4

1、基本操作演練

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

1)下載 Fantasy Skybox FREE:在Unity的Asset Store中找到Fantasy Skybox FREE的材料包,然後下載並且導入自己的項目中。
在這裏插入圖片描述
導入成功後多了很多材料:
在這裏插入圖片描述
2) 構建自己的遊戲場景:
在Camera中添加Component,然後添加Skybox,再將相應的Skybox圖案添加上去,就能夠完成天空盒的創建了,得到自己喜歡的背景了。
在這裏插入圖片描述
然後創建地形,需要添加Terrain,然後可以在Terrain中創造一些自己的場景,具體方法查看下圖:
在這裏插入圖片描述
在這裏插入圖片描述

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

遊戲對象主要包括:空對象,攝像機,光線,3D物體,聲音,UI基於事件的new UI系統和粒子系統與特效,預製的材料

  • 空對象(Empty):不顯示卻是最常用的對象之一
  • 攝像機(Camara):觀察遊戲世界的窗口
  • 光線(Light):遊戲世界的光源,讓遊戲世界富有魅力
  • 3D物體 :遊戲中的重要組成部分,可以改變其網格和材質,也是很多複雜對象的初始材料
  • 聲音(Audio):遊戲中的音樂或者聲音來源
  • 預製材料:方便複雜對象的重複使用

2、編程實踐:牧師與魔鬼動作分離版

1)本次作業需要在上次作業的基礎上,將遊戲場景的動作分離出來:
即依然是採用MVC結構實現,與上一次無動作分離版的區別在於,之前對於動作的管理是實現了一個動作類,當鼠標點擊船或是人物時,相當於是控制器讓船或人物的實例調用動作類來實現運動。這次實踐中將船或人物與動作分離開來,單獨實現了一個動作管理器,鼠標點擊船或是人物時,相當於是控制器發送請求給動作管理器,動作管理器來實現船或人物的運動。
2)主要思路:按照下圖將上次的代碼進行分解:
在這裏插入圖片描述

3)接下來是動作基類的實現(課程中有):
設計要點:

  • ScriptableObject是不需要綁定GameObject對象的可編程基類。這些對象受Unity引擎場景管理
  • protected SSAction()是防止用戶自己new對象
  • 使用virtual申明虛方法,通過重寫實現多態。這樣繼承者就能明確使用Start和Update編程遊戲對象行爲
  • 利用接口實現消息通知,避免與動作管理者直接依賴
public class SSAction : ScriptableObject
{
    public bool enable = true;
    public bool destroy = false;
 
    public GameObject gameobject { get; set; }
    public Transform transform { get; set; }
    public ISSActionCallback callback { get; set; }
 
    protected SSAction() {}
 
    public virtual void Start() {
        throw new System.NotImplementedException();
    }
 
    public virtual void Update() {
        throw new System.NotImplementedException();
    }
}

4)簡單動作實現:
設計目的:遊戲中移動的動作,通過傳入遊戲對象的位置和設置好的動作,就能夠使遊戲對象移動起來

public class CCMoveToAction : SSAction {
	public Vector3 target;
	public float speed;
 
	public static CCMoveToAction GetSSAction(Vector3 target, float speed) {
		CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
		action.target = target;
		action.speed = speed;
		return action;
	}
 
	public override void Update () {
		this.transform.position = Vector3.MoveTowards(this.transform.position,target,speed);
		if(this.transform.position == target) {
			this.destroy = true;
			this.callback.SSActionEvent(this);
		}
	}
 
	public override void Start() {}
}

5)順序動作組合類實現:
代碼重點:

  • repeat的值爲-1表示動作無限循環,而start則表示動作開始
  • Update的重寫則是表示執行當前的動作
  • SSActionEvent則是一個回調通知的動作,當收到當前動作執行完成後,則推下一個動作,如果完成一次循環,則減少它的次數。如果當所有動作完成,就通知動作的管理者,將其銷燬。
  • Start的重寫則是表示,在執行動作前,爲每個動作注入當前動作的遊戲對象,並將自己作爲動作事件的接收者。
public class CCSequenceAction : SSAction, ISSActionCallback {
    public List<SSAction> sequence;
    public int repeat = -1; //repeat forever
    public int start = 0;
 
    public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence) {
        CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
        action.repeat = repeat;
        action.sequence = sequence;
        action.start = start;
        return action;
    }
 
    public override void Start() {
        foreach (SSAction action in sequence) {
            action.gameobject = this.gameobject;
            action.transform = this.transform;
            action.callback = this;
            action.Start();
        }
    }
 
    public override void Update() {
        if (sequence.Count == 0) return;
        if (start < sequence.Count)
            sequence[start].Update();
    }
 
    public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed,
     int intParam = 0, string strParam = null, Object objectParam = null) {
        source.destroy = false;
        this.start++;
        if (this.start >= sequence.Count) {
            this.start = 0;
            if (repeat > 0) repeat--;
            if (repeat == 0) {
                this.destroy = true;
                this.callback.SSActionEvent(this);
            }
            else {
                sequence[start].Start();
            }
        }
    }
 
    private void OnDestroy() {
        //destory
    }
}

6)動作事件接口定義:在定義了時間處理接口以後,所有的事件管理者都必須實現這個接口來實現事件調度。所以,組合事件需要實現它,事件管理器也必須實現它。

public enum SSActionEventType : int { Started, Completed }
 
public interface ISSActionCallback
{
    void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0, string strParam = null, Object objectParam = null);
}

7)動作管理基類 – SSActionManager:實現了所有動作的基本管理

public class SSActionManager : MonoBehaviour, ISSActionCallback {                     //action管理器

    private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();    //將執行的動作的字典集合,int爲key,SSAction爲value
    private List<SSAction> waitingAdd = new List<SSAction>();                       //等待去執行的動作列表
    private List<int> waitingDelete = new List<int>();                              //等待刪除的動作的key                

    protected void Update(){
        foreach (SSAction ac in waitingAdd){
            actions[ac.GetInstanceID()] = ac;                                      //獲取動作實例的ID作爲key
        }
        waitingAdd.Clear();

        foreach (KeyValuePair<int, SSAction> kv in actions){
            SSAction ac = kv.Value;
            if (ac.destroy) waitingDelete.Add(ac.GetInstanceID());
            else if (ac.enable) ac.Update();
        }

        foreach (int key in waitingDelete){
            SSAction ac = actions[key];
            actions.Remove(key);
            Object.Destroy(ac);
        }
        waitingDelete.Clear();
    }

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

    public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
        int intParam = 0, string strParam = null, Object objectParam = null){
        //牧師與魔鬼的遊戲對象移動完成後就沒有下一個要做的動作了,所以回調函數爲空
    }
}

8)裁判類的實現:對當前局面勝負關係的判斷

public class Judger : System.Object {
    private static Judger _instance; 
    public static Judger getInstance() { //使用單例模式
        if (_instance == null) _instance = new Judger ();
        return _instance;
    }
    public int check(CoastCon fromCoast,CoastCon toCoast,BoatCon boat) {	// 0->not finish, 1->lose, 2->win
        int fromP = 0, fromD = 0, toP = 0, toD = 0;
        int[] fromCount = fromCoast.getCharacterNum();
        fromP += fromCount[0];
        fromD += fromCount[1];

        int[] toCount = toCoast.getCharacterNum ();
        toP += toCount[0];
        toD += toCount[1];

        if (toP + toD == 6) return 2; //win
        int[] boatCount = boat.getCharacterNum ();
        if (boat.getStatus () == -1) {
            toP += boatCount[0]; toD += boatCount[1];	// boat at toCoast
        }
        else {
            fromP += boatCount[0]; fromD += boatCount[1];	// boat at fromCoast	
        }
        if (fromP < fromD && fromP > 0) return 1; //lose		
        if (toP < toD && toP > 0) return 1; //lose
        return 0;			// not finish
    }
}

9)視頻鏈接

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