游戏 魔鬼与牧师
游戏规则:
1,你要运用智慧帮助3个牧师(方块)和3个魔鬼(圆球)渡河。
船最多可以载2名游戏角色。
2,船上有游戏角色时,你才可以点击这个船,让船移动到对岸。
3,当有一侧岸的魔鬼数多余牧师数时(包括船上的魔鬼和牧师),魔鬼就会失去控制,吃掉牧师(如果这一侧没有牧师则不会失败),游戏失败。
4,当所有游戏角色都上到对岸时,游戏胜利。
游戏设计
使用了MVC架构。
1,场景中的所有GameObject就是Model,它们受到Controller的控制,比如说牧师和魔鬼受到MyCharacterController类的控制,船受到BoatController类的控制,河岸受到CoastController类的控制。
2,View就是UserGUI和ClickGUI,它们展示游戏结果,并提供用户交互的渠道(点击物体和按钮)。
3,Controller:除了刚才说的MyCharacterController、BoatController、CoastController以外,还有更高一层的Controller:FirstController(场景控制器),FirstController控制着这个场景中的所有对象,包括其加载、通信、用户输入。最高层的Controller是Director类,一个游戏中只能有一个实例,它控制着场景的创建、切换、销毁、游戏暂停、游戏退出等等最高层次的功能。
Director
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;
}
}
public interface SceneController {
void loadResources ();
}
public interface UserAction {
void moveBoat();
void characterIsClicked(MyCharacterController characterCtrl);
void restart();
}
Moveable
GameObject挂载上Moveable以后,Controller就可以通过setDestination()方法让GameObject移动起来。
public class Moveable: MonoBehaviour {
readonly float move_speed = 10;
// change frequently
int moving_status; // 0->not moving, 1->moving to middle, 2->moving to dest
Vector3 dest;
Vector3 middle;
void Update() {
if (moving_status == 1) {
transform.position = Vector3.MoveTowards (transform.position, middle, move_speed * Time.deltaTime);
if (transform.position == middle) {
moving_status = 2;
}
} else if (moving_status == 2) {
transform.position = Vector3.MoveTowards (transform.position, dest, move_speed * Time.deltaTime);
if (transform.position == dest) {
moving_status = 0;
}
}
}
public void setDestination(Vector3 _dest) {
dest = _dest;
middle = _dest;
if (_dest.y == transform.position.y) { // boat moving
moving_status = 2;
}
else if (_dest.y < transform.position.y) { // character from coast to boat
middle.y = transform.position.y;
} else { // character from boat to coast
middle.x = transform.position.x;
}
moving_status = 1;
}
public void reset() {
moving_status = 0;
}
}
MyCharacterController
MyCharacterController封装了一个GameObject,表示游戏角色(牧师或恶魔)。
public class MyCharacterController {
readonly GameObject character;
readonly Moveable moveableScript;
readonly ClickGUI clickGUI;
readonly int characterType; // 0->priest, 1->devil
// change frequently
bool _isOnBoat;
CoastController coastController;
BoatController
封装了船GameObject
public class BoatController {
readonly GameObject boat;
readonly Moveable moveableScript;
readonly Vector3 fromPosition = new Vector3 (5, 1, 0);
readonly Vector3 toPosition = new Vector3 (-5, 1, 0);
readonly Vector3[] from_positions;
readonly Vector3[] to_positions;
// change frequently
int to_or_from; // to->-1; from->1
MyCharacterController[] passenger = new MyCharacterController[2];
CoastController
河岸GameObject
public class CoastController {
readonly GameObject coast;
readonly Vector3 from_pos = new Vector3(9,1,0);
readonly Vector3 to_pos = new Vector3(-9,1,0);
readonly Vector3[] positions;
readonly int to_or_from; // to->-1, from->1
// change frequently
MyCharacterController[] passengerPlaner;
UserAction
public interface UserAction {
void moveBoat();
void characterIsClicked(MyCharacterController characterCtrl);
void restart();
}
这个接口实际上使用了门面模式。
FirstController必须要实现这个接口才能对用户的输入做出反应。
门面模式的好处是通过一套接口(UserAction)来定义Controller与GUI交互的渠道,这样实现Controller类的程序员只需要实现UserAction接口,他的代码就可以被任何支持这个接口的GUI类所使用;实现GUI类的程序员也不需要知道Controller的实现方式,它只需要调用接口中的方法。