牧师与魔鬼是一款益智游戏。河边有三个牧师和三个魔鬼。他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。如果神父的人数超过了河两边的魔鬼,他们就会被杀死,游戏就结束了。
表现形式:白色方块为牧师,红色方块为魔鬼,棕色矩形为船
交互模式:通过点击游戏实体进行交互,点击牧师或魔鬼,可以进行上下船。通过点击船,可以让船过河。如果船上没有牧师或魔鬼,则无法过河。如果船上已经有两人,则无法上船。
游戏的加载方式:通过创建空对象,挂载场记脚本,在场记的awake方法中进行资源加载。
面向对象设计:有一个单例导演类SSDirector和一个场记类FirstController,还有一个挂载在恶魔和牧师上的PositionInfo脚本。SSDirector和场记交互,场记和游戏对象交互。FirstController实现接口ISceneController,并保存在导演中以供全局访问。
代码如下:
PositionInfo:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface ISceneController
{//场记接口
void LoadResources();
void GameOver(bool win);
void GameRestart();
float getBoatPosition();
}
public class SSDirector : System.Object
{
private static SSDirector instance;
public ISceneController currentSceneController { get; set;}//记录并提供当前场记的访问
public static SSDirector getInstance()//提供单例的访问
{
if (instance == null)
{
instance = new SSDirector();
}
return instance;
}
public void setFPS(int fps)//提供fps设置
{
Application.targetFrameRate = fps;
}
}
FirstController
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
public class FirstController : MonoBehaviour, ISceneController
{
//需要在unity中将主摄像机拖入
public GameObject cam;
//MVC的模型部分
public GameObject boatObject,leftShore,rightShore,river;//场景元素和船
public float boatPosition;//船的z坐标
public int boatArea;//船所在区域(1为左,2为右)
public GameObject[] left;//左岸的角色
public GameObject[] right;//右岸的角色
public GameObject[] boat;//船上的角色
int leftCount;
int rightCount;
int boatCount;
int leftDevil, rightDevil, leftPriest, rightPriest;//左右的牧师和恶魔数量
bool gameover;//游戏结束
bool win;//true为赢,false为输
public float getBoatPosition()//提供船的z坐标查询
{
return boatPosition;
}
public void Awake()
{
SSDirector director = SSDirector.getInstance();
director.setFPS(60);
director.currentSceneController = this;
director.currentSceneController.LoadResources();
}
public void LoadResources()
{
left = new GameObject[6];
right = new GameObject[6];
boat = new GameObject[2];
rightCount = 0;
boatCount = 0;
leftDevil = 3; rightDevil = 0; leftPriest = 3; rightPriest = 0;
//加载资源文件,创建游戏对象
GameObject devil = Instantiate(Resources.Load("Prefabs/devil"));
devil.GetComponent().UpdatePosition(1, 0);
left[0] = devil;
devil.name = "DEVIL";
GameObject devil2=Instantiate(devil);
devil2.GetComponent().UpdatePosition(1, 1);
left[1] = devil2;
devil2.name = "DEVIL";
GameObject devil3 = Instantiate(devil);
devil3.GetComponent().UpdatePosition(1, 2);
left[2] = devil3;
devil3.name = "DEVIL";
GameObject priest = Instantiate(Resources.Load("Prefabs/priest"));
priest.GetComponent().UpdatePosition(1, 3);
left[3] = priest;
priest.name = "PRIEST";
GameObject priest2 = Instantiate(priest);
priest2.GetComponent().UpdatePosition(1, 4);
left[4] = priest2;
priest2.name = "PRIEST";
GameObject priest3 = Instantiate(priest);
priest3.GetComponent().UpdatePosition(1, 5);
left[5] = priest3;
priest3.name = "PRIEST";
boatObject = Instantiate(Resources.Load("Prefabs/boat"),new Vector3(0,0,-3), Quaternion.identity);
boatObject.name = "BOAT";
boatPosition = -3;
boatArea = 1;
leftShore=Instantiate(Resources.Load("Prefabs/shore"), new Vector3(0, 0, -13), Quaternion.identity);
rightShore=Instantiate(Resources.Load("Prefabs/shore"), new Vector3(0, 0, 13), Quaternion.identity);
river=Instantiate(Resources.Load("Prefabs/water"), new Vector3(0, 0, 0), Quaternion.identity);
}
public void GameOver(bool win)
{
Debug.Log("WIN");
Debug.Log("LOST");
gameover = true;
this.win = win;
}
public void GameRestart()
{
for (int i = 0; i < 6; i++)
{
if (left[i])
Destroy(left[i]);
if (right[i])
Destroy(right[i]);
}
if (boat[0])
Destroy(boat[0]);
if (boat[1])
Destroy(boat[1]);
Destroy(leftShore);
Destroy(rightShore);
Destroy(river);
Destroy(boatObject);
LoadResources();
gameover = false;
}
//MVC的视图部分
void Update()
{
if (gameover)
{ string str;
if (win)
str = "YOU WIN";
else str = "YOU LOST";
if (EditorUtility.DisplayDialog("Confirmation", str, "Yes"))
{
GameRestart();
}
}
else if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Fired Pressed");
Debug.Log(Input.mousePosition);
Vector3 mp = Input.mousePosition; //get Screen Position
//create ray, origin is camera, and direction to mousepoint
Camera ca;
if (cam != null) ca = cam.GetComponent();
else ca = Camera.main;
Ray ray = ca.ScreenPointToRay(Input.mousePosition);
//Return the ray's hit
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
print(hit.transform.gameObject.name);
ClickOn(hit.transform.gameObject);
}
}
}
//MVC的控制部分
void ClickOn(GameObject a)
{
if (a.name == "DEVIL" || a.name == "PRIEST")
{
PositionInfo p = a.GetComponent();
if (p.Area == 3)//Area:1-左岸,2-右岸,3-船上
{
if (boatArea == 1)
{
int i = 0;
while (left[i] != null) i++;
GetDown(a, 1, i);
leftCount++;
boatCount--;
}
else if (boatArea == 2)
{
int i = 0;
while (right[i] != null) i++;
GetDown(a, 2, i);
rightCount++;
boatCount--;
}
}
else if (p.Area == 1)
{
int i;
if (boat[0] == null)
i = 0;
else if (boat[1] == null)
i = 1;
else
return;
leftCount--;
boatCount++;
GetOn(a, i);
}
else if (p.Area == 2)
{
int i;
if (boat[0] == null)
i = 0;
else if (boat[1] == null)
i = 1;
else
return;
rightCount--;
boatCount++;
GetOn(a, i);
}
}else if (a.name == "BOAT")
{
if (boatCount == 0)//船上没人不能过河
return;
if (boatArea == 1)
{
a.transform.position = new Vector3(0, 0, 3);
boatPosition = 3;
boatArea = 2;
if (boat[0] != null)
{
if (boat[0].name == "DEVIL")
{
leftDevil--;
rightDevil++;
}
else
{
leftPriest--;
rightPriest++;
}
}
if (boat[1]!=null)
{
if (boat[1].name == "DEVIL")
{
leftDevil--;
rightDevil++;
}
else
{
leftPriest--;
rightPriest++;
}
}
}else if(boatArea == 2)
{
a.transform.position = new Vector3(0, 0, -3);
boatPosition = -3;
boatArea = 1;
if (boat[0] != null)
{
if (boat[0].name == "DEVIL")
{
leftDevil++;
rightDevil--;
}
else
{
leftPriest++;
rightPriest--;
}
}
if (boat[1] != null)
{
if (boat[1].name == "DEVIL")
{
leftDevil++;
rightDevil--;
}
else
{
leftPriest++;
rightPriest--;
}
}
}
checkGameOver();
}
}
void checkGameOver()
{
//某一侧的牧师少于恶魔
if (leftDevil > leftPriest && leftPriest != 0)
{
GameOver(false);
}
if(rightDevil >rightPriest && rightPriest != 0)
{
GameOver(false);
}
if (rightDevil+rightPriest==6)
{
GameOver(true);
}
}
void GetOn(GameObject a,int boatSeat)//上船
{
a.transform.SetParent(boatObject.transform);
PositionInfo p = a.GetComponent();
switch (p.Area){
case 1:
left[p.Index] = null;
boat[boatSeat] = a;
p.UpdatePosition(3, boatSeat);
break;
case 2:
right[p.Index] = null;
boat[boatSeat] = a;
p.UpdatePosition(3, boatSeat);
break;
}
}
void GetDown(GameObject a, int Area, int shoreSeat)//下船
{
a.transform.SetParent(null);
PositionInfo p = a.GetComponent();
switch (Area)
{
case 1:
boat[p.Index] = null;
left[shoreSeat] = a;
p.UpdatePosition(1, shoreSeat);
break;
case 2:
boat[p.Index] = null;
right[shoreSeat] = a;
p.UpdatePosition(2, shoreSeat);
break;
}
}
}
SSDirector:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PositionInfo : MonoBehaviour
{
//保存位置信息(区域+下标),进行空间上的移动(三维坐标)
public int Area {set;get;}
public int Index {set; get;}
public void UpdatePosition(int a,int b)
{
Transform t = this.gameObject.transform;
switch (a)
{
case 1://左岸
t.position=new Vector3(0,2,-7-2*b);
break;
case 2://右岸
t.position = new Vector3(0,2,7+2*b);
break;
case 3://船
t.position = new Vector3(0,1.25f, SSDirector.getInstance().currentSceneController.getBoatPosition()+b*1.2f-0.6f);
break;
}
Area = a;
Index = b;
}
}
完整代码链接:unity游戏开发学习: 交作业专用,不对代码质量负责~ (gitee.com)
运行视频:unity实现牧师与魔鬼_哔哩哔哩_bilibili
因为使用弹窗提示游戏结束,录屏软件有些问题,视频中没有录到。