游戏演示
你家牧师会这样?
游戏介绍
本游戏为牧师与魔鬼过河游戏。
需要将牧师从左岸全部运送到右岸,运送过程中不能出现同一岸(包括靠岸的船)魔鬼的数量超过牧师的数量。
游戏设计过程
包含模型介绍
游戏包含以下预设
玩家交互表格
玩家行为 | 执行条件 | 执行结果 |
点击船 | 船靠岸并且船上有角色 | 船移动到另一岸 |
点击角色 | 角色在船上:船靠岸且没有其他角色移动 角色在岸上:船在同一岸且船上未满两角色 | 角色在船上:角色移动至岸上 角色在岸上:角色移动到船上 |
点击Restart按钮 | 任何时候可执行 | 资源重置,游戏重新开始 |
注:以上前两条行为均有游戏未结束的前提条件(游戏失败或胜利视为游戏结束)
MVC架构代码
MVC架构图
代码实现(部分)
Model部分
Role
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Role{
public GameObject role;
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;
Debug.Log("Prefabs/"+(isPriest ? "Priest" : "Devil"));
role = GameObject.Instantiate(Resources.Load("Prefabs/"+(isPriest ? "Priest" : "Devil"),typeof(GameObject))) as GameObject;
role.transform.localScale = new Vector3(0.77019f,1,0.6349832f);
role.name = "role"+id;
role.AddComponent<Click>();
role.AddComponent<BoxCollider>();
}
}
Boat
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Boat
{
public GameObject boat;
public bool isRight;
public Role[] roles;
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>();
}
}
Land
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Land{
public GameObject land;
public int priestCount;
public int devilCount;
public Land(Vector3 position){
land = GameObject.Instantiate(Resources.Load("Prefabs/Land",typeof(GameObject))) as GameObject;
land.name = "Land";
land.transform.position = position;
priestCount = 0;
devilCount = 0;
}
}
Position
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Position{
public static Vector3 leftLand = new Vector3(-6.99f,-0.77f,-2.3f);
public static Vector3 rightLand = new Vector3(4.52f,-0.77f,-2.3f);
public static Vector3 river = new Vector3(-1.2f,-2.6f,-2.77f);
//船左右岸位置
public static Vector3 leftBoat = new Vector3(-2.3f,-0.55f,-2.39f);
public static Vector3 rightBoat = new Vector3(-0.3f,-0.55f,-2.39f);
//岸上角色位置
public static Vector3[] role_shore = new Vector3[]{
new Vector3(0.4f,0.77f,0),
new Vector3(0.25f,0.77f,0),
new Vector3(0.1f,0.77f,0),
new Vector3(-0.05f,0.77f,0),
new Vector3(-0.2f,0.77f,0),
new Vector3(-0.35f,0.77f,0)
};
//船上的位置
public static Vector3[] role_boat = new Vector3[]{
new Vector3(0.2f,2.5f,0),
new Vector3(-0.2f,2.5f,0),
};
}
View部分
UserGUI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserGUI : MonoBehaviour
{
IUserAction userAction;
JudgeController judgeController;
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(230, Screen.height * 0.1f, 700, 200), "Priests and Devils", bigstyle);
GUI.Label(new Rect(350, 100, 50, 200), gameMessage, style);
if(GUI.Button(new Rect(0,0,100,40),"Restart")){
userAction.reStart();
}
}
}
Control部分
RoleControl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoleControl : ClickAction
{
Role role;
IUserAction userAction;
// 实现ClickAction接口
public void ClickOnObject() {
// 点击role,role移动
userAction.MoveRole(role);
}
public RoleControl(){
userAction = SSDirector.GetInstance().CurrentSceneController as IUserAction;
}
public void CreateRole(Vector3 position, bool isPriest, int id){
if(role != null){
// role已经存在
Object.DestroyImmediate(role.role);
}
role = new Role(position, isPriest, id);
role.role.GetComponent<Click>().setClickAction(this);
}
public Role GetRoleModel(){
return role;
}
public void Delect(){
Object.DestroyImmediate(role.role);
}
}
BoatControl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 控制Boat的运动
public class BoatControl : ClickAction
{
Boat boatModel;
IUserAction userAction;
// 实现ClickAction接口
public void ClickOnObject() {
// 点击船,船移动
// 通过userAction中的方法实现移动
// 前置条件:船上有role
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){
// boat已经存在
Object.DestroyImmediate(boatModel.boat);
}
boatModel = new Boat(position);
boatModel.boat.GetComponent<Click>().setClickAction(this);
}
public Boat GetBoatModel(){
return boatModel;
}
// 角色从岸上移动到船上
public Vector3 AddRole(Role r){
// 前置条件:船没有满员
// 如果能上船,角色应到的位置就是船所在的位置
// 如果不能上船,角色应到的位置就是原来的位置
int emptySeat = -1;
if(boatModel.roles[0] == null) emptySeat = 0;
else if (boatModel.roles[1] == null) emptySeat = 1;
// 船上无空位
if(emptySeat == -1){
return r.role.transform.localPosition;
}
else{
boatModel.roles[emptySeat] = r; // 装到boat上
r.inBoat = true;
r.role.transform.parent = boatModel.boat.transform; // 将role挂在boat下
if(r.isPriest){
boatModel.priestCount++;
}
else{
boatModel.devilCount++;
}
return Position.role_boat[emptySeat];
}
}
// 角色从船上移动到岸上
public void RemoveRole(Role r){
for(int i = 0; i < 2; i++){
if(boatModel.roles[i] == r){
boatModel.roles[i] = null;
if(r.isPriest){
boatModel.priestCount--;
}
else{
boatModel.devilCount--;
}
}
}
}
public void Delect(){
Object.DestroyImmediate(boatModel.boat);
}
}
FirstController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstController : MonoBehaviour, ISceneController, IUserAction {
// JudgeController judgeController;
public LandControl leftLandController, rightLandController;
River river;
public BoatControl boatController;
RoleControl[] roleControllers;
MoveControl moveController;
public bool isRunning;
public void LoadResources() {
// judgeController = new JudgeController();
//role
roleControllers = new RoleControl[6];
for (int i = 0; i < 6; ++i) {
roleControllers[i] = new RoleControl();
roleControllers[i].CreateRole(Position.role_shore[i], i < 3 ? true : false, i);
}
//land
leftLandController = new LandControl();
leftLandController.CreateLand(Position.leftLand);
leftLandController.GetLand().land.name = "left_land";
rightLandController = new LandControl();
rightLandController.CreateLand(Position.rightLand);
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.leftBoat);
//river
river = new River(Position.river);
//move
moveController = new MoveControl();
isRunning = true;
}
public void MoveBoat() {
if (isRunning == false || moveController.GetIsMoving()) return;
if (boatController.GetBoatModel().isRight) {
moveController.SetMove(Position.leftBoat, boatController.GetBoatModel().boat,false);
}
else {
moveController.SetMove(Position.rightBoat, boatController.GetBoatModel().boat,false);
}
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,true);
}
else {
moveController.SetMove(leftLandController.AddRole(roleModel), roleModel.role,true);
}
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,false);
}
}
}
public void Check() {
}
public void reStart(){
Destroy(GetComponent<JudgeController>());
foreach (RoleControl roleController in roleControllers)
{
roleController.Delect();
}
boatController.Delect();
// for (int i = 0; i < 6; ++i) {
// roleControllers[i] = new RoleControl();
// roleControllers[i].CreateRole(Position.role_shore[i], i < 3 ? true : false, i);
// }
// boatController = new BoatControl();
// boatController.CreateBoat(Position.leftBoat);
// foreach (RoleControl roleController in roleControllers)
// {
// roleController.GetRoleModel().role.transform.localPosition = leftLandController.AddRole(roleController.GetRoleModel());
// }
// boatController.CreateBoat(Position.leftBoat);
LoadResources();
this.gameObject.AddComponent<JudgeController>();
this.gameObject.GetComponent<UserGUI>().gameMessage = "";
}
void Awake() {
SSDirector.GetInstance().CurrentSceneController = this;
LoadResources();
this.gameObject.AddComponent<UserGUI>();
this.gameObject.AddComponent<JudgeController>();
}
void Update() {
}
}
Move
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public bool canMove = false;
public float speed = 5;
public Vector3 destination;
public Vector3 mid_destination;
void Update(){
if (transform.localPosition == destination) {
canMove = false;
return;
}
canMove = 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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveControl
{
GameObject moveObj;
public bool GetIsMoving() {
return (moveObj != null && moveObj.GetComponent<Move>().canMove == true);
}
public void SetMove(Vector3 destination, GameObject moveObj,bool inBoat)
{
Move test;
this.moveObj = moveObj;
if (!moveObj.TryGetComponent<Move>(out test)) {
moveObj.AddComponent<Move>();
}
this.moveObj.GetComponent<Move>().destination = destination;
if(inBoat){
this.moveObj.GetComponent<Move>().mid_destination = new Vector3(this.moveObj.transform.localPosition.x, destination.y, destination.z);
}
else{
this.moveObj.GetComponent<Move>().mid_destination = new Vector3(destination.x, this.moveObj.transform.localPosition.y, destination.z);
}
}
}
后记
本项目参考小原味鹦鹉的博客
在其基础上进行了修改和改进,同时进一步实现了裁判类。
完整代码:gitee项目地址