一、背景描述
牧師與魔鬼是一款益智遊戲,您將幫助牧師與魔鬼在規定時間內過河。河邊有三個牧師和三個魔鬼。他們都想去這條河的對岸,但只有一艘船,這艘船每次只能載兩個人。而且必須有一個人把船從一邊開到另一邊。在flash遊戲中,您可以單擊它們移動它們,然後單擊go按鈕將船移動到另一個方向。如果神父的人數超過了河兩邊的魔鬼,他們就會被殺死,遊戲就結束了。你可以用很多方法來嘗試。讓所有牧師都活着!祝你好運!
(圖片來源:百度百科)
二、MVC設計模式
MVC設計模式是一種軟件架構模式,它將軟件系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。模型負責封裝與業務邏輯相關的數據和方法,視圖負責顯示模型的數據,控制器負責處理用户的請求和更新模型和視圖。MVC設計模式的目的是實現一種動態的程序設計,使後續對程序的修改和擴展簡化,並且使程序某一部分的重複利用成為可能。MVC設計模式也有利於提高程序的可測試性、可維護性和可擴展性。
三、項目介紹
1、對象
| 對象 | 數量 |
|---|---|
| 牧師 | 3 |
| 魔鬼 | 3 |
| 船 | 1 |
| 陸地 | 2 |
| 河流 | 1 |
2、動作
| 動作 | 條件 | 效果 |
|---|---|---|
| 玩家點擊岸上角色 | 船上有空位 | 角色上船 |
| 玩家點擊船上角色 | 角色上岸 | |
| 玩家點擊船 | 船上有至少一個角色 | 開船 |
| 玩家點擊restart | 重新開始遊戲 |
3、代碼
4、項目展示
5、實現過程
(1)Director
public class Director : System.Object {
private static Director _instance;
public SceneController currentSceneController { get; set; }
public static Director getInstance() {
if (_instance == null) {
_instance = new Director ();
}
return _instance;
}
}
這段代碼是用C#語言實現的單例模式(Singleton Pattern)的一個例子。單例模式是一種創建型設計模式,它保證一個類只有一個實例,並提供一個全局訪問點。
這段代碼定義了一個名為Director的類,它有以下特點:
- 它有一個私有的靜態字段_instance,用來存儲唯一的實例。
- 它有一個私有的無參構造函數,防止其他類通過new關鍵字創建它的實例。
- 它有一個公共的靜態方法getInstance,用來獲取或創建唯一的實例。如果_instance為空,就創建一個新的Director對象並賦值給它;如果不為空,就直接返回它。
- 它有一個公共的屬性currentSceneController,用來設置或獲取當前的場景控制器。
(2)Controller:代碼
這段代碼定義了一個名為FirstController的類,它繼承了MonoBehaviour類,並實現了SceneController和UserAction兩個接口。它有以下特點:
public CoastController fromCoast;
public CoastController toCoast;
public BoatController boat;
private MyCharacterController[] characters;
它有一個常量water_pos,用來表示水面的位置。
它有一個UserGUI類型的字段userGUI,用來顯示用户界面。
它有兩個CoastController類型的字段fromCoast和toCoast,分別表示起始岸和目標岸。
它有一個BoatController類型的字段boat,表示船。
它有一個MyCharacterController類型的數組characters,用來存儲六個角色對象(三個牧師和三個魔鬼)。
void Awake() {
Director director = Director.getInstance ();
director.currentSceneController = this;
userGUI = gameObject.AddComponent <UserGUI>() as UserGUI;
characters = new MyCharacterController[6];
loadResources ();
}
重寫了Awake方法,在該方法中獲取Director單例對象,並將自己設置為當前的場景控制器。然後添加UserGUI組件,並初始化characters數組。最後調用loadResources方法加載資源。
public void loadResources() {
GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;
water.name = "water";
fromCoast = new CoastController ("from");
toCoast = new CoastController ("to");
boat = new BoatController ();
loadCharacter ();
}
實現了loadResources方法,在該方法中實例化水面對象,並給它命名為"water"。然後創建fromCoast、toCoast和boat對象,並調用loadCharacter方法加載角色對象。
private void loadCharacter() {
for (int i = 0; i < 3; i++) {
MyCharacterController cha = new MyCharacterController ("priest");
cha.setName("priest" + i);
cha.setPosition (fromCoast.getEmptyPosition ());
cha.getOnCoast (fromCoast);
fromCoast.getOnCoast (cha);
characters [i] = cha;
}
for (int i = 0; i < 3; i++) {
MyCharacterController cha = new MyCharacterController ("devil");
cha.setName("devil" + i);
cha.setPosition (fromCoast.getEmptyPosition ());
cha.getOnCoast (fromCoast);
fromCoast.getOnCoast (cha);
characters [i+3] = cha;
}
}
實現了loadCharacter方法,在該方法中循環創建三個牧師和三個魔鬼對象,並給它們命名為"priest0"到"priest2"和"devil0"到"devil2"。然後將它們放置在fromCoast的空位上,並讓它們上岸。同時將它們添加到fromCoast和characters數組中。
public void moveBoat() {
if (userGUI.status != 0 ) return;
if (boat.isEmpty ())
return;
boat.Move ();
userGUI.status = check_game_over ();
}
實現了moveBoat方法,在該方法中判斷遊戲狀態是否為0(未結束),如果不是則返回。然後判斷船是否為空,如果是則返回。否則調用boat的Move方法移動船,並更新遊戲狀態。
public void characterIsClicked(MyCharacterController characterCtrl) {
if (userGUI.status != 0 ) return;
if (characterCtrl.isOnBoat ()) {
CoastController whichCoast;
if (boat.get_to_or_from () == -1) { // to->-1; from->1
whichCoast = toCoast;
} else {
whichCoast = fromCoast;
}
boat.GetOffBoat (characterCtrl.getName());
characterCtrl.moveToPosition (whichCoast.getEmptyPosition ());
characterCtrl.getOnCoast (whichCoast);
whichCoast.getOnCoast (characterCtrl);
} else { // character on coast
CoastController whichCoast = characterCtrl.getCoastController ();
if (boat.getEmptyIndex () == -1) { // boat is full
return;
}
if (whichCoast.get_to_or_from () != boat.get_to_or_from ()) // boat is not on the side of character
return;
whichCoast.getOffCoast(characterCtrl.getName());
characterCtrl.moveToPosition (boat.getEmptyPosition());
characterCtrl.getOnBoat (boat);
boat.GetOnBoat (characterCtrl);
}
userGUI.status = check_game_over ();
}
實現了characterIsClicked方法,在該方法中判斷遊戲狀態是否為0(未結束),如果不是則返回。然後判斷角色對象是否在船上,如果是則執行下列操作:
聲明一個CoastController類型的變量whichCoast,用來表示目標岸。
判斷船的位置是在起始岸還是目標岸,如果是目標岸,則將whichCoast賦值為toCoast;如果是起始岸,則將whichCoast賦值為fromCoast。
調用boat的GetOffBoat方法讓角色對象下船,並傳入角色對象的名字作為參數。
調用角色對象的moveToPosition方法讓角色對象移動到whichCoast的空位上,並傳入空位座標作為參數。
調用角色對象的getOnCoast方法讓角色對象上岸,並傳入whichCoast作為參數。
調用whichCoast的getOnCoast方法讓whichCoast記錄角色對象,並傳入角色對象作為參數。
如果角色對象不在船上,則執行下列操作:
聲明一個CoastController類型的變量whichCoast,用來表示當前岸,並調用角色對象的getCoastController方法獲取當前岸。
判斷船是否已滿,如果是則返回。
判斷船的位置是否與當前岸一致,如果不是則返回。
調用whichCoast的getOffCoast方法讓角色對象下岸,並傳入角色對象的名字作為參數。
調用角色對象的moveToPosition方法讓角色對象移動到船的空位上,並傳入空位座標作為參數。
調用角色對象的getOnBoat方法讓角色對象上船,並傳入boat作為參數。
調用boat的GetOnBoat方法讓船記錄角色對象,並傳入角色對象作為參數。
最後更新遊戲狀態。
int check_game_over() { // 0->not finish, 1->lose, 2->win
int from_priest = 0;
int from_devil = 0;
int to_priest = 0;
int to_devil = 0;
int[] fromCount = fromCoast.getCharacterNum ();
from_priest += fromCount[0];
from_devil += fromCount[1];
int[] toCount = toCoast.getCharacterNum ();
to_priest += toCount[0];
to_devil += toCount[1];
if (to_priest + to_devil == 6) // win
return 2;
int[] boatCount = boat.getCharacterNum ();
if (boat.get_to_or_from () == -1) { // boat at toCoast
to_priest += boatCount[0];
to_devil += boatCount[1];
} else { // boat at fromCoast
from_priest += boatCount[0];
from_devil += boatCount[1];
}
if (from_priest < from_devil && from_priest > 0) { // lose
return 1;
}
if (to_priest < to_devil && to_priest > 0) {
return 1;
}
return 0; // not finish
}
實現了check_game_over方法,在該方法中判斷遊戲是否結束,如果結束則返回相應的狀態碼,如果未結束則返回0。判斷遊戲是否結束的邏輯如下:
聲明四個整型變量from_priest、from_devil、to_priest和to_devil,分別表示起始岸和目標岸的牧師和魔鬼數量,並初始化為0。
調用fromCoast和toCoast的getCharacterNum方法獲取各自的牧師和魔鬼數量,並分別累加到相應的變量中。
如果目標岸的牧師和魔鬼數量之和等於6,説明所有角色都過河了,遊戲勝利,返回2。
調用boat的getCharacterNum方法獲取船上的牧師和魔鬼數量,並根據船的位置累加到相應的變量中。
如果起始岸或目標岸的魔鬼數量多於牧師數量,且牧師數量大於0,説明有牧師被吃掉了,遊戲失敗,返回1。
否則遊戲未結束,返回0。
四、參考資料:
牧師與魔鬼
Unity3D遊戲編程-牧師與惡魔
Unity使用MVC架構製作牧師與魔鬼小遊戲