首先十分感谢学姐的参考博客Unity实战——牧师与魔鬼!!!
相关资源
游戏背景
牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河。河边有三个牧师和三个魔鬼。他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。在flash游戏中,您可以单击它们移动它们,然后单击go按钮将船移动到另一个方向。如果牧师的人数超过了河两边的魔鬼,他们就会被杀死,游戏就结束了。你可以用很多方法来尝试。让所有牧师都活着!祝你好运!
Unity组件
河岸、河流、人物模型(牧师、恶魔)、船
规则表
动作 | 条件 | 事件 |
---|---|---|
点击人物 | 游戏未结束&船未满&船没有到对岸 | 上船 |
点击船 | 游戏未结束&船上至少有一个人物 | 船移动到对岸 |
点击人物 | 游戏未结束&人物在船上&船在岸边 | 下船 |
MVC模式
游戏文件组织结构
- 分为三个部分
- Resources中定义了Model
- Scripts中定义了View和Controller
- 更具体的文件可以到项目地址中找到
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>();
}
}
- 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>();
}
}
- 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.name = "river";
river.transform.position = position;
}
}
- Land.cs:陆地
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.cs:为了移动更加方便,设置一个类存在各种对象的位置
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Position
{
public static Vector3 left_land = new Vector3(-8,-3,0);
public static Vector3 right_land = new Vector3(8,-3,0);
public static Vector3 river = new Vector3(0,-4,0);
// 船在左岸的位置
public static Vector3 left_boat = new Vector3(-2.3f,-2.3f,-0.4f);
// 船在右岸的位置
public static Vector3 right_boat = new Vector3(2.4f, -2.3f, -0.4f);
// 岸上的角色应该站的位置
public static Vector3[] role_shore = new Vector3[] {new Vector3(0.4f,0.77f,0), new Vector3(0.2f,0.77f,0), new Vector3(0,0.77f,0), new Vector3(-0.2f,0.77f,0), new Vector3(-0.4f,0.77f,0), new Vector3(-0.6f,0.77f,0)};
// 船上的两个位置
public static Vector3[] role_boat = new Vector3[] {new Vector3(0.2f,3,0), new Vector3(-0.2f,3,0)};
}
- 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.ClickOnObject();
}
}
- ClickAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ClickAction
{
void ClickOnObject();
}
Controller
- BoatControl.cs:控制船只动作
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 GetBoat(){
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--;
}
}
}
}
}
- RoleControl.cs:控制角色运动
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 GetRole(){
return role;
}
}
- LandControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LandControl
{
Land land;
public void CreateLand(Vector3 position) {
if (land == null) {
land = new Land(position);
}
}
public Land GetShore() {
return land;
}
// 将角色加到岸上
public Vector3 AddRole(Role r){
r.role.transform.parent = land.land.transform;
r.inBoat = false;
if(r.isPriest) land.priestCount++;
else land.devilCount++;
return Position.role_shore[r.id];
}
// 将角色从岸上移除
public void RemoveRole(Role r){
if (r.isPriest) land.priestCount--;
else land.devilCount--;
}
}
- Move.cs,MoveControl.cs 控制移动
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);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveControl
{
GameObject moveObj;
// Start is called before the first frame update
public bool GetIsMoving() {
return (moveObj != null && moveObj.GetComponent<Move>().canMove == true);
}
// Update is called once per frame
public void SetMove(Vector3 destination, GameObject moveObj)
{
Move test;
this.moveObj = moveObj;
if (!moveObj.TryGetComponent<Move>(out test)) {
moveObj.AddComponent<Move>();
}
this.moveObj.GetComponent<Move>().destination = destination;
if (this.moveObj.transform.localPosition.y > destination.y) {
this.moveObj.GetComponent<Move>().mid_destination = new Vector3(destination.x, this.moveObj.transform.localPosition.y, destination.z);
}
else {
this.moveObj.GetComponent<Move>().mid_destination = new Vector3(this.moveObj.transform.localPosition.x, destination.y, destination.z);
}
}
}
- 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;
}
}
- 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 role);
void Check();
}
- 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 + (boatController.GetBoatModel().isRight ? 0 : boatController.GetBoatModel().priestCount);
rightPriestCount = rightLandController.GetLand().priestCount + (boatController.GetBoatModel().isRight ? boatController.GetBoatModel().priestCount : 0);
leftDevilCount = leftLandController.GetLand().devilCount + (boatController.GetBoatModel().isRight ? 0 : boatController.GetBoatModel().devilCount);
rightDevilCount = rightLandController.GetLand().devilCount + (boatController.GetBoatModel().isRight ? boatController.GetBoatModel().devilCount : 0);
if (leftPriestCount != 0 && leftPriestCount < leftDevilCount || 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() {
}
}