游戏机制:
牧师与魔鬼是一款益智游戏,玩家需要帮助牧师与魔鬼在规定时间内过河。河边有三个牧师和三个魔鬼,他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。在游戏中,玩家可以通过单击人物来将人物移动到船只上,然后单击船只将船移动到河的另一边。如果在其中一边魔鬼的数量超过了这一边中牧师的数量,牧师就会被杀死,游戏就失败了。而当全部牧师和全部魔鬼都到达另一边时,游戏就胜利了。
UML图:
Controller制作代码:
BoatControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BoatControl : ClickAction
{
Boat boatModel;
IUserAction userAction;
public void DealClick() {
// 前置条件:船没有满员
// 如果能上船,角色应到的位置就是船所在的位置
// 如果不能上船,角色应到的位置就是原来的位置
if (boatModel.roles[0] != null || boatModel.roles[1] != null) {
userAction.MoveBoat();
}
}
public BoatControl() {
userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
}
public void CreateBoat(Vector3 position) {
if (boatModel != null) {
Object.DestroyImmediate(boatModel.boat);
}
boatModel = new Boat(position);
boatModel.boat.GetComponent<Click>().setClickAction(this);
}
public Boat GetBoatModel() {
return boatModel;
}
public Vector3 AddRole(Role roleModel) {
int index = -1;
if (boatModel.roles[0] == null) index = 0;
else if (boatModel.roles[1] == null) index = 1;
if (index == -1) return roleModel.role.transform.localPosition;
boatModel.roles[index] = roleModel;
roleModel.inBoat = true;
roleModel.role.transform.parent = boatModel.boat.transform;
if (roleModel.isPriest) boatModel.priestCount++;
else boatModel.devilCount++;
return Position.role_boat[index];
}
//将角色从船上移到岸上
public void RemoveRole(Role roleModel) {
for (int i = 0; i < 2; ++i){
if (boatModel.roles[i] == roleModel) {
boatModel.roles[i] = null;
if (roleModel.isPriest) boatModel.priestCount--;
else boatModel.devilCount--;
break;
}
}
}
}
FirstController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstController : MonoBehaviour, ISceneController, IUserAction {
LandControl leftLandController, rightLandController;
River river;
BoatControl boatController;
RoleControl[] roleControllers;
MoveCtrl moveController;
bool isRunning;
float time;
public void LoadResources() {
//role
roleControllers = new RoleControl[6];
for (int i = 0; i < 6; ++i) {
roleControllers[i] = new RoleControl();
roleControllers[i].CreateRole(Position.role_land[i], i < 3 ? true : false, i);
}
//land
leftLandController = new LandControl();
leftLandController.CreateLand(Position.left_land);
leftLandController.GetLand().land.name = "left_land";
rightLandController = new LandControl();
rightLandController.CreateLand(Position.right_land);
rightLandController.GetLand().land.name = "right_land";
//将人物添加并定位至左岸
foreach (RoleControl roleController in roleControllers)
{
roleController.GetRoleModel().role.transform.localPosition = leftLandController.AddRole(roleController.GetRoleModel());
}
//boat
boatController = new BoatControl();
boatController.CreateBoat(Position.left_boat);
//river
river = new River(Position.river);
//move
moveController = new MoveCtrl();
isRunning = true;
time = 60;
}
public void MoveBoat() {
if (isRunning == false || moveController.GetIsMoving()) return;
if (boatController.GetBoatModel().isRight) {
moveController.SetMove(Position.left_boat, boatController.GetBoatModel().boat);
}
else {
moveController.SetMove(Position.right_boat, boatController.GetBoatModel().boat);
}
boatController.GetBoatModel().isRight = !boatController.GetBoatModel().isRight;
}
public void MoveRole(Role roleModel) {
if (isRunning == false || moveController.GetIsMoving()) return;
if (roleModel.inBoat) {
if (boatController.GetBoatModel().isRight) {
moveController.SetMove(rightLandController.AddRole(roleModel), roleModel.role);
}
else {
moveController.SetMove(leftLandController.AddRole(roleModel), roleModel.role);
}
roleModel.onRight = boatController.GetBoatModel().isRight;
boatController.RemoveRole(roleModel);
}
else {
if (boatController.GetBoatModel().isRight == roleModel.onRight) {
if (roleModel.onRight) {
rightLandController.RemoveRole(roleModel);
}
else {
leftLandController.RemoveRole(roleModel);
}
moveController.SetMove(boatController.AddRole(roleModel), roleModel.role);
}
}
}
public void Check() {
if (isRunning == false) return;
this.gameObject.GetComponent<UserGUI>().gameMessage = "";
if (rightLandController.GetLand().priestCount == 3) {
this.gameObject.GetComponent<UserGUI>().gameMessage = "You Win!";
isRunning = false;
}
else {
int leftPriestCount, rightPriestCount, leftDevilCount, rightDevilCount;
leftPriestCount = leftLandController.GetLand().priestCount ;
rightPriestCount = rightLandController.GetLand().priestCount;
leftDevilCount = leftLandController.GetLand().devilCount ;
rightDevilCount = rightLandController.GetLand().devilCount ;
if (leftPriestCount != 0 && leftPriestCount < leftDevilCount ){
this.gameObject.GetComponent<UserGUI>().gameMessage = "Game Over!";
isRunning = false;
}
else if( rightPriestCount != 0 && rightPriestCount < rightDevilCount) {
this.gameObject.GetComponent<UserGUI>().gameMessage = "Game Over!";
isRunning = false;
}
}
}
void Awake() {
SSDirector.GetInstance().CurrentSceneController = this;
LoadResources();
this.gameObject.AddComponent<UserGUI>();
}
void Update() {
}
}
ISceneController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ISceneController
{
void LoadResources();
}
IUserAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IUserAction {
void MoveBoat();
void MoveRole(Role roleModel);
void Check();
}
LandControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LandControl
{
Land landModel;
public void CreateLand(Vector3 position) {
if (landModel == null) {
landModel = new Land(position);
}
}
public Land GetLand() {
return landModel;
}
public Vector3 AddRole(Role roleModel) {
roleModel.role.transform.parent = landModel.land.transform;
roleModel.inBoat = false;
if (roleModel.isPriest) landModel.priestCount++;
else landModel.devilCount++;
return Position.role_land[roleModel.id];
}
public void RemoveRole(Role roleModel) {
if (roleModel.isPriest) landModel.priestCount--;
else landModel.devilCount--;
}
}
Move.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public bool isMoving = false;
public float speed = 5;
public Vector3 destination;
public Vector3 mid_destination;
// Update is called once per frame
void Update()
{
if (transform.localPosition == destination) {
isMoving = false;
return;
}
isMoving = true;
if (transform.localPosition.x != destination.x && transform
.localPosition.y != destination.y) {
transform.localPosition = Vector3.MoveTowards(transform.localPosition, mid_destination, speed * Time.deltaTime);
}
else {
transform.localPosition = Vector3.MoveTowards(transform.localPosition, destination, speed * Time.deltaTime);
}
}
}
MoveControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCtrl
{
GameObject moveObject;
public bool GetIsMoving() {
return (moveObject != null && moveObject.GetComponent<Move>().isMoving == true);
}
public void SetMove(Vector3 destination, GameObject moveObject) {
Move test;
this.moveObject = moveObject;
if (!moveObject.TryGetComponent<Move>(out test)) {
moveObject.AddComponent<Move>();
}
this.moveObject.GetComponent<Move>().destination = destination;
if (this.moveObject.transform.localPosition.y > destination.y) {
this.moveObject.GetComponent<Move>().mid_destination = new Vector3(destination.x, this.moveObject.transform.localPosition.y, destination.z);
}
else {
this.moveObject.GetComponent<Move>().mid_destination = new Vector3(this.moveObject.transform.localPosition.x, destination.y, destination.z);
}
}
}
RoleControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoleControl : ClickAction
{
Role roleModel;
IUserAction userAction;
public RoleControl() {
userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
}
public void CreateRole(Vector3 position, bool isPriest, int id) {
if (roleModel != null) {
Object.DestroyImmediate(roleModel.role);
}
roleModel = new Role(position, isPriest, id);
roleModel.role.GetComponent<Click>().setClickAction(this);
}
public Role GetRoleModel() {
return roleModel;
}
public void DealClick() {
userAction.MoveRole(roleModel);
}
}
SSDirector.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSDirector : System.Object
{
static SSDirector _instance;
public ISceneController CurrentSceneController {get; set;}
public static SSDirector GetInstance() {
if (_instance == null) {
_instance = new SSDirector();
}
return _instance;
}
}
View制作代码:
UserGUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserGUI : MonoBehaviour
{
IUserAction userAction;
public string gameMessage ;
GUIStyle style, bigstyle;
// Start is called before the first frame update
void Start()
{
userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
style = new GUIStyle();
style.normal.textColor = Color.white;
style.fontSize = 30;
bigstyle = new GUIStyle();
bigstyle.normal.textColor = Color.white;
bigstyle.fontSize = 50;
}
// Update is called once per frame
void OnGUI() {
userAction.Check();
GUI.Label(new Rect(160, Screen.height * 0.1f, 50, 200), "Preists and Devils", bigstyle);
GUI.Label(new Rect(250, 100, 50, 200), gameMessage, style);
}
}
Model制作代码:
Boat.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Boat
{
public GameObject boat;//船对象
public Role[] roles;//船上的角色
public bool isRight;
public int priestCount, devilCount;
public Boat(Vector3 position) {
boat = GameObject.Instantiate(Resources.Load("Prefabs/Boat", typeof(GameObject))) as GameObject;
boat.name = "boat";
boat.transform.position = position;
boat.transform.localScale = new Vector3(2.8f,0.4f,2);
roles = new Role[2];
isRight = false;
priestCount = devilCount = 0;
boat.AddComponent<BoxCollider>();
boat.AddComponent<Click>();
}
}
Click.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Click : MonoBehaviour
{
ClickAction clickAction;
public void setClickAction(ClickAction clickAction) {
this.clickAction = clickAction;
}
void OnMouseDown() {
clickAction.DealClick();
}
}
ClickAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ClickAction
{
void DealClick();
}
Land.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Land
{
public GameObject land;
public int priestCount, devilCount;
public Land (Vector3 position){
land = GameObject.Instantiate(Resources.Load("Prefabs/Land", typeof(GameObject))) as GameObject;
land.transform.position = position;
priestCount = devilCount = 0;
}
}
Position.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Position
{
public static Vector3 left_land = new Vector3(-8,-3.52f,0);
public static Vector3 right_land = new Vector3(8,-3.52f,0);
public static Vector3 river = new Vector3(0,-4,0);
public static Vector3 left_boat = new Vector3(-2.3f,-3.05f,-0.4f);
public static Vector3 right_boat = new Vector3(2.3f, -3.05f, -0.4f);
public static Vector3[] role_land = new Vector3[] {new Vector3(0.4f,0.77f,0), new Vector3(0.228f,0.77f,0), new Vector3(0.058f,0.77f,0), new Vector3(-0.126f,0.77f,0), new Vector3(-0.29f,0.77f,0), new Vector3(-0.44f,0.77f,0)};
// 在船上的位置
public static Vector3[] role_boat = new Vector3[] {new Vector3(0.2f,2.41f,0), new Vector3(-0.2f,2.41f,0)};
}
River.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class River
{
public GameObject river;
public River(Vector3 position) {
river = GameObject.Instantiate(Resources.Load("Prefabs/river", typeof(GameObject))) as GameObject;
river.transform.position = position;
river.name = "river";
}
}
Role.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Role
{
public GameObject role;//model对应的游戏对象
public bool isPriest;
public bool inBoat;
public bool onRight;
public int id;
public Role (Vector3 position, bool isPriest, int id) {
this.isPriest = isPriest;
this.id = id;
onRight = false;
inBoat = false;
role = GameObject.Instantiate(Resources.Load("Prefabs/" + (isPriest ? "Priest" : "Devil"), typeof(GameObject))) as GameObject;
role.transform.localScale = new Vector3(0.6f,0.6f, 0.6f);
role.transform.position = position;
role.name = "role" + id;
role.AddComponent<Click>();
role.AddComponent<BoxCollider>();
}
}