Unity实战——牧师与魔鬼
最终效果
牧师与魔鬼游戏效果
背景描述
牧师与魔鬼是一款益智游戏,您将帮助牧师与魔鬼在规定时间内过河。河边有三个牧师和三个魔鬼。他们都想去这条河的对岸,但只有一艘船,这艘船每次只能载两个人。而且必须有一个人把船从一边开到另一边。在flash游戏中,您可以单击它们移动它们,然后单击go按钮将船移动到另一个方向。如果神父的人数超过了河两边的魔鬼,他们就会被杀死,游戏就结束了。你可以用很多方法来尝试。让所有牧师都活着!祝你好运!
Objects
河岸(×2),河,船,牧师,魔鬼
规则表
动作 | 条件 | 事件 |
---|---|---|
点击人物 | 游戏未结束&船未满&船没有到对岸 | 上船 |
点击船 | 游戏未结束&船上至少有一个任务 | 船移动到对岸 |
MVC设计模式
简单来说,就是将项目分成Model、Controller、View三个层面
- Model. 存储数据对象
- Controller. 接受用户事件,在这里主要是鼠标点击
- View. 显示模型,转发人机交互事件
开始!
设置游戏对象
根据前面的分析,做几个游戏对象
魔鬼和牧师:
扫描二维码关注公众号,回复:
15066771 查看本文章
小河:
陆地:
船:
将他们拖到Assets中成为预制
Model
在Asset中创建Models文件夹,存放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;
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.7f,0.7f,0.7f);
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
,ClickAction.cs
Click
继承了ClickAction
接口
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();
}
}
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() {
}
}
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);
}
}