牧师与魔鬼——Unity MVC架构小游戏

一、游戏介绍与要求

河的一侧有三个牧师与三个魔鬼,你需要帮助他们过河。但是只有一条小船,小船每次最多只能载两个人,且至少需要一个人来开船。注意同一侧的魔鬼数量不能大于牧师数量,否则牧师将会被魔鬼杀死。

  • 将游戏中对象做成预制
  • 在场景控制器 LoadResources 方法中加载并初始化长方形、正方形、球及其色彩代表游戏中的对象。
  • 使用 C# 集合类型有效组织对象
  • 整个游戏仅主摄像机和一个 Empty 对象,其他对象必须代码动态生成!整个游戏不许出现 Find 游戏对象,SendMessage 这类突破程序结构的通讯耦合语句。
  • 使用MVC架构

二、准备工作

游戏中的物体

GameObject表达方式
牧师白色球
魔鬼红色球
棕色长方体
河岸灰色长方体

玩家动作表

动作事件
牧师上船船所在一侧的牧师上船
牧师下船船上的牧师到船所在一侧的河岸
恶魔上船船所在一侧的恶魔上船
恶魔下船船上的恶魔到船所在一侧的河岸
开船船及船上的物体移动到另一侧

预制对象

在这里插入图片描述

MVC架构设计

在这里插入图片描述

  • Model
    定义Boat模型,包含船所在一侧、船上物体数量、船上物体及位置等信息。
    (因为在FirstController中使用Stack组织牧师与恶魔对象,且该对象无需返回对象信息,故不定义其Model)
  • View
    SSDirector:获取当前场景、控制场景转换等。(该游戏只有一个场景)
    UserGUI:绘制用户交互界面,实现用户交互。
  • Controller
    FirstController:控制当前场景下各个Model的行为。

三、游戏实现代码

Model

  • Boat
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Boat
{
    public GameObject role;
    public bool boat_state;
    public int boat_num;
    public GameObject[] object_on_boat = new GameObject[2];
    public Vector3 boat_object_position = new Vector3(-4f, 0.05f, 0);

    public Boat(){
        boat_state = false;
        boat_num = 0;
    }
}

View

  • SSDirector
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SSDirector : System.Object {
	// singlton instance
	private static SSDirector _instance;

	public ISceneController currentSceneController { get; set;}

	// get instance anytime anywhare!
	public static SSDirector getInstance() {
		if (_instance == null) {
			_instance = new SSDirector ();
		}
		return _instance;
	}

	public int getFPS() {
		return Application.targetFrameRate;
	}

	public void setFPS(int fps) {
		Application.targetFrameRate = fps;
	}

	public void NextScene(){
		Debug.Log ("Waiting next Scene now...");
		#if UNITY_EDITOR  
		UnityEditor.EditorApplication.isPlaying = false;
		//UnityEditor.EditorApplication.Exit(0);
		#else  
		Application.Quit();  
		#endif  
	}
}

  • UserGUI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour {

	private IUserAction action;

	void Start () {
		action = SSDirector.getInstance ().currentSceneController as IUserAction;
	}

	void OnGUI() {  
		if(!action.isMoving()){
			float width = Screen.width / 5;  
			float height = Screen.height / 12; 

			if (GUI.Button(new Rect(0, 0, width, height), "牧师上船")) {  
				action.priest_on(); 
			} 

			if (GUI.Button(new Rect(width, 0, width, height), "牧师下船")) { 
				action.priest_off();
			} 

			if (GUI.Button(new Rect(width * 2, 0, width, height), "开船")) { 
				action.move_boat();
			} 

			if (GUI.Button(new Rect(width * 3, 0, width, height), "恶魔下船")) { 
				action.devil_off();
			} 

			if (GUI.Button(new Rect(width * 4, 0, width, height), "恶魔上船")) { 
				action.devil_on();
			} 

			if (action.getResult() != "Continue") {
				GUI.Box(new Rect(width, height, width * 3, height * 3), action.getResult());
				if (GUI.Button(new Rect(width, height * 3, width * 3, height), "结束游戏")) {
					action.GameOver();
				}
			}
		}
	}
}

Controller

  • FirstController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// Scene Controller
/// Usage: host on a gameobject in the scene   
/// responsiablities:
///   acted as a scene manager for scheduling actors.log something ...
///   interact with the director and players
public class FirstController : MonoBehaviour, ISceneController, IUserAction {

	Boat boat = new Boat();
	bool moving = false;
	string result = "Continue";
	Stack<GameObject> priest_left = new Stack<GameObject>();
	Stack<GameObject> priest_right = new Stack<GameObject>();
	Stack<GameObject> devil_left = new Stack<GameObject>();
	Stack<GameObject> devil_right = new Stack<GameObject>();
	static Vector3 priest_left_position = new Vector3(-5.5f, 1.5f, 0);
	static Vector3 priest_right_position = new Vector3(5.5f, 1.5f, 0);
	static Vector3 devil_left_position = new Vector3(-10f, 1.5f, 0);
	static Vector3 devil_right_position = new Vector3(10f, 1.5f, 0);
	static Vector3 boat_left_position = new Vector3(-3, -0.7f, 0);
	static Vector3 boat_right_position = new Vector3(3, -0.7f, 0);
	Vector3[] relative_position = new Vector3[2];
	//船移动相关
	static private float moveTime = 0.25f;
	private float startTime;
	static private float length = Vector3.Distance(boat_left_position, boat_right_position);
	private float speed = length / moveTime;

	// the first scripts
	void Awake () {
		SSDirector director = SSDirector.getInstance ();
		director.setFPS (60);
		director.currentSceneController = this;
		director.currentSceneController.LoadResources ();
	}
	 
	// loading resources for the first scence
	public void LoadResources () {
		Debug.Log ("load resource ...\n");
		Instantiate(Resources.Load("Prefabs/shore"), new Vector3(-10, 0, 0), Quaternion.identity);
		Instantiate(Resources.Load("Prefabs/shore"), new Vector3(10, 0, 0), Quaternion.identity);
		boat.role = Instantiate(Resources.Load("Prefabs/boat"), boat_left_position, Quaternion.identity) as GameObject;
		for(int i = 0; i < 3; i++){
			GameObject p = Instantiate(Resources.Load("Prefabs/priest"), priest_left_position, Quaternion.identity) as GameObject;
			priest_left_position.x -= 1.5f;
			p.name = "priest";
			priest_left.Push(p);
			GameObject d = Instantiate(Resources.Load("Prefabs/devil"), devil_left_position, Quaternion.identity) as GameObject;
			devil_left_position.x -= 1.5f;
			d.name = "devil";
			devil_left.Push(d);
		}
	}

	string check(){
		int priest_num;
		int devil_num;
		if(boat.boat_state){
			priest_num = 3 - priest_left.Count;
			devil_num = 3 - devil_left.Count;
			if(priest_num == 3 && devil_num == 3) return "Win";
			if((devil_num > priest_num && priest_num != 0) || (devil_left.Count > priest_left.Count && priest_left.Count != 0)) return "Lose";
			return "Continue";
		}
		else{
			priest_num = 3 - priest_right.Count;
			devil_num = 3 - devil_right.Count;
			if((devil_num > priest_num && priest_num != 0)|| (devil_right.Count > priest_right.Count && priest_right.Count != 0)) return "Lose";
			return "Continue";
		}
	}

	#region IUserAction implementation
	 public void priest_on(){
		if(boat.boat_num < 2){
			if(boat.boat_state){
				if(priest_right.Count == 0) return;
				boat.object_on_boat[boat.boat_num] = priest_right.Pop();
				priest_right_position.x += 1.5f;
			}
			else{
				if(priest_left.Count == 0) return;
				boat.object_on_boat[boat.boat_num] = priest_left.Pop();
				priest_left_position.x += 1.5f;
			}
			boat.object_on_boat[boat.boat_num].transform.position = boat.boat_object_position;
			boat.boat_object_position.x += 2f;
			boat.boat_num++;
		}
	}

	public void priest_off(){
		for(int i = boat.boat_num - 1; i >= 0; i--){
			if(boat.object_on_boat[i].name == "priest"){
				boat.boat_num--;
				boat.boat_object_position.x -= 2f;
				if(boat.boat_state){
					priest_right.Push(boat.object_on_boat[i]);
					boat.object_on_boat[i].transform.position = priest_right_position;
					priest_right_position.x += 1.5f;
				}
				else{
					priest_left.Push(boat.object_on_boat[i]);
					boat.object_on_boat[i].transform.position = priest_left_position;
					priest_left_position.x -= 1.5f;
				}
				return;
			}
			if(boat.boat_num == 2 && boat.object_on_boat[0].name == "priest"){
				boat.boat_num--;
				boat.boat_object_position.x -= 2f;
				if(boat.boat_state){
					priest_right.Push(boat.object_on_boat[0]);
					boat.object_on_boat[0].transform.position = priest_right_position;
					priest_right_position.x += 1.5f;
				}
				else{
					priest_left.Push(boat.object_on_boat[0]);
					boat.object_on_boat[0].transform.position = priest_left_position;
					priest_left_position.x -= 1.5f;
				}
				boat.object_on_boat[1].transform.position = new Vector3(boat.object_on_boat[1].transform.position.x - 2f, boat.object_on_boat[1].transform.position.y, boat.object_on_boat[1].transform.position.z);
				boat.object_on_boat[0] = boat.object_on_boat[1];
				return;
			}
		}
	}

	public void devil_on(){
		if(boat.boat_num < 2){
			if(boat.boat_state){
				if(devil_right.Count == 0) return;
				boat.object_on_boat[boat.boat_num] = devil_right.Pop();
				devil_right_position.x -= 1.5f;
			}
			else{
				if(devil_left.Count == 0) return;
				boat.object_on_boat[boat.boat_num] = devil_left.Pop();
				devil_left_position.x += 1.5f;
			}
			boat.object_on_boat[boat.boat_num].transform.position = boat.boat_object_position;
			boat.boat_object_position.x += 2f;
			boat.boat_num++;
		}
	}

	public void devil_off(){
		for(int i = boat.boat_num - 1; i >= 0; i--){
			if(boat.object_on_boat[i].name == "devil"){
				boat.boat_num--;
				boat.boat_object_position.x -= 2f;
				if(boat.boat_state){
					devil_right.Push(boat.object_on_boat[i]);
					boat.object_on_boat[i].transform.position = devil_right_position;
					devil_right_position.x += 1.5f;
				}
				else{
					devil_left.Push(boat.object_on_boat[i]);
					boat.object_on_boat[i].transform.position = devil_left_position;
					devil_left_position.x -= 1.5f;
				}
				return;
			}
			if(boat.boat_num == 2 && boat.object_on_boat[0].name == "devil"){
				boat.boat_num--;
				boat.boat_object_position.x -= 2f;
				if(boat.boat_state){
					devil_right.Push(boat.object_on_boat[0]);
					boat.object_on_boat[0].transform.position = devil_right_position;
					devil_right_position.x += 1.5f;
				}
				else{
					devil_left.Push(boat.object_on_boat[0]);
					boat.object_on_boat[0].transform.position = devil_left_position;
					devil_left_position.x -= 1.5f;
				}
				boat.object_on_boat[1].transform.position = new Vector3(boat.object_on_boat[1].transform.position.x - 2f, boat.object_on_boat[1].transform.position.y, boat.object_on_boat[1].transform.position.z);
				boat.object_on_boat[0] = boat.object_on_boat[1];
				return;
			}
		}
	}

	public void move_boat(){
		if(boat.boat_num != 0){
			for(int i = 0; i < boat.boat_num; i++){
				relative_position[i] = boat.object_on_boat[i].transform.position - boat.role.transform.position;
			}
			if(boat.boat_state){
				boat.boat_object_position.x -= 6.0f;
			}
			else{
				boat.boat_object_position.x += 6.0f;
			}
			startTime = Time.time;
			moving = true;
		}
	}

	public bool isMoving(){
		return moving;
	}

	public string getResult(){
		return result;
	}

	public void GameOver ()
	{
		SSDirector.getInstance ().NextScene ();
	}
	#endregion


	// Use this for initialization
	void Start () {

	}
	
	// Update is called once per frame
	void Update () {
		//船移动
		if(moving){
			float dist = (Time.time - startTime) * speed;
			float fraction = dist / length;
			Vector3 end_position;
			if(boat.boat_state){
				boat.role.transform.position = Vector3.MoveTowards(boat_right_position, boat_left_position, fraction);
				end_position = boat_left_position;
			}
			else{
				boat.role.transform.position = Vector3.MoveTowards(boat_left_position, boat_right_position, fraction);
				end_position = boat_right_position;
			}
			for(int i = 0; i < boat.boat_num; i++){
				boat.object_on_boat[i].transform.position = boat.role.transform.position + relative_position[i];
			}
			if(boat.role.transform.position == end_position){
				boat.boat_state = !boat.boat_state;
				moving = false;
				result = check();
			}
		}
	}

}

Interface

  • IUserAction
using System;

public interface IUserAction
{
	void priest_on();
	void priest_off();
	void devil_on();
	void devil_off();
	void move_boat();
	bool isMoving();
	string getResult();
	void GameOver();
}
  • ISceneController
using System;

public interface ISceneController
{
	void LoadResources();
}

四、游戏视频

牧师与魔鬼游戏视频

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值