游戏目标:将3个牧师和3个魔鬼从河的一端安全地送到河的另一端。
游戏规则:在运送过程中,船可以搭载两个人,而且必须有一人掌船。
游戏结果:无论何时,只要河一边的魔鬼数量多于牧师的数量,游戏就会以失败结束。当三个牧师与魔鬼都平安到达河的另一端时胜利。
游戏对象的行为
角色:上下船、划船
魔鬼:当两岸任意一边人数多于牧师时杀死牧师,游戏结束
船:有人时可以动
参考上级同学实现MVC架构:
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
师兄博客传送门:Klog师兄的牧师与魔鬼
代码实现
文件结构我使用的文件结构:
预制:prefabs
介绍prefabs的博客:作者000000000000O–Unity Prefabs
使用预制可以创建游戏对象后设置好再拉到预制,之后只要把对象删除就好!在Asset里面可以创建Material来给预制上色之类。
这里我把河岸、河还有岸上的树当作一个主物体,会动的priest devil boat则不用管
以M开头的就是Material
在代码中可用Resources.Load 和 Instantiate来加载预制!加载出来的名字是”xx(Clone)”
Scripts
自己很难明白怎么做,还好有学长们的博客哈哈
其中SceneHandle和UserAction是接口:由FirstControllor来具体实现
接口知识:c#接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface SceneHandle {
void Load ();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface UserAction{
void priestGetOn ();
void priestGetOff ();
void devilGetOn ();
void devilGetOff ();
void moveBoat ();
void restart ();
int result ();
int getResult ();
}
SDirector即所谓单例类,是全局中只能存在唯一一个对象的类,通过函数getInstance()可以获得这个类的实例对象。通过这唯一一个全局可访问的对象即使不用SendMessage之类的方法也可以实现类之间的通信,从而保有了代码的MVC架构
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SDirector : System.Object {
private static SDirector _instance;
public SceneHandle currentSceneController {get; set;}
public static SDirector getInstance() {
if (_instance == null) {
_instance = new SDirector();
}
return _instance;
}
}
myGui时对游戏场景Button等的构建,FirstControllor对游戏进行了逻辑实现,值得一提的是在restart()方法里重新加载场景所调用的EditorSceneManager.LoadScene方法会造成场景变暗,但改进的话要创建灯光之类的看不太明白…
还有就是判定结果是否输赢我最开始是在点击GetOff方法时进行判定,但玩游戏的时候发现不是这时判定的,但在点Go时判定又有些早,所以应该是Go时判定,但当船到对岸时再出游戏结果。因为这个问题发现的很晚没来得及仔细实现,只好在myGUI类里加上了判定,才让游戏看起来比较合理
using System.Collections;
using System.Collections.Generic;
using UnityEditor.SceneManagement;
using UnityEngine;
public class FirstControllor : MonoBehaviour, SceneHandle, UserAction {
SDirector MySD;
public int boatState = 0;
//0=start,1=end,2=move from start shore,3=move from end shore
public int gameResult = 0;
//1=win,2=lose
GameObject[] onBoat=new GameObject[2];
GameObject boat;
float gap = 1.5f;
Stack<GameObject> SPriest = new Stack<GameObject>();
Stack<GameObject> EPriest = new Stack<GameObject>();
Stack<GameObject> SDevil = new Stack<GameObject>();
Stack<GameObject> EDevil = new Stack<GameObject>();
Vector3 boatStart = new Vector3 (-2f, 0.5f, 0);
Vector3 boatEnd = new Vector3 (2f, 0.5f, 0);
float speed=10;
public void Load(){
GameObject myGO = Instantiate<GameObject> (Resources.Load<GameObject> ("prefabs/main"), Vector3.zero, Quaternion.identity);
myGO.name = "main";
boat = Instantiate (Resources.Load ("prefabs/boat"), boatStart, Quaternion.identity)as GameObject;
for (int i = 0; i < 3; i++) {
SPriest.Push (Instantiate (Resources.Load ("prefabs/priest")) as GameObject);
SDevil.Push (Instantiate (Resources.Load ("prefabs/devil"))as GameObject);
}
}
void Awakemethod(){
SDirector d = SDirector.getInstance ();
d.currentSceneController = this;
d.currentSceneController.Load ();
}
void Awake(){
Awakemethod ();
}
int boatCapacity(){
int cnt = 0;
for(int i=0;i<2;i++){
if (onBoat [i] == null)
cnt++;
}
return cnt;
}
void setCharacterPositions(Stack<GameObject> que, Vector3 pos) {
GameObject[] array = que.ToArray();
for (int i = 0; i < que.Count; ++i) {
array[i].transform.position = new Vector3(pos.x + gap*i, pos.y, pos.z);
}
}
public void getOn(GameObject obj){
if (boatCapacity () != 0) {
obj.transform.parent = boat.transform;
if (onBoat [0] == null) {
onBoat [0] = obj;
obj.transform.localPosition = new Vector3 (-0.2f, 1f, 0);
} else {
onBoat [1] = obj;
obj.transform.localPosition = new Vector3 (0.2f, 1f, 0);
}
}
}
public void priestGetOn(){
if (SPriest.Count != 0 && boatCapacity () != 0 && this.boatState == 0) {
getOn (SPriest.Pop ());
} else if (EPriest.Count != 0 && boatCapacity () != 0 && this.boatState == 1) {
getOn (EPriest.Pop ());
}
}
public void devilGetOn(){
if (SDevil.Count != 0 && boatCapacity () != 0 && this.boatState == 0) {
getOn (SDevil.Pop ());
} else if (EDevil.Count != 0 && boatCapacity () != 0 && this.boatState == 1) {
getOn (EDevil.Pop ());
}
}
public void priestGetOff(){
for(int i=0;i<2;i++){
if(onBoat[i]!=null){
if(this.boatState==1){
if(onBoat[i].name=="priest(Clone)"){
EPriest.Push (onBoat [i]);
onBoat[i].transform.parent=null;
onBoat [i] = null;
break;
}
}
else if(this.boatState==0){
if(onBoat[i].name=="priest(Clone)"){
SPriest.Push (onBoat [i]);
onBoat[i].transform.parent=null;
onBoat[i]=null;
break;
}
}
}
}
}
public void devilGetOff(){
for(int i=0;i<2;i++){
if(onBoat[i]!=null){
if(this.boatState==1){
if(onBoat[i].name=="devil(Clone)"){
EDevil.Push (onBoat [i]);
onBoat[i].transform.parent=null;
onBoat [i] = null;
break;
}
}
else if(this.boatState==0){
if(onBoat[i].name=="devil(Clone)"){
SDevil.Push (onBoat [i]);
onBoat[i].transform.parent=null;
onBoat[i]=null;
break;
}
}
}
}
}
public void moveBoat(){
if(boatCapacity()==2)return ;
/*if (boatState == 0)
boatState = 2;
else if (boatState == 1)
boatState = 3;*/
this.boatState += 2;
//Debug.Log (boatState);
}
public void restart(){
//Awakemethod ();
EditorSceneManager.LoadScene(EditorSceneManager.GetActiveScene().name);
boatState = gameResult = 0;
}
public int getResult(){
return gameResult;
}
public int result(){
if (EPriest.Count == 3 && EDevil.Count == 3) {
gameResult = 1;
}
int cntPriest = 0, cntDevil = 0;
for (int i = 0; i < 2; i++) {
if (onBoat [i] != null) {
if (onBoat [i].name == "priest(Clone)")
cntPriest++;
else
cntDevil++;
}
}
int cntPriestStart = 0, cntPriestEnd = 0;
int cntDevilStart = 0, cntDevilEnd = 0;
if (boatState == 0) {
cntPriestStart = SPriest.Count + cntPriest;
cntDevilStart = SDevil.Count + cntDevil;
cntPriestEnd = EPriest.Count;
cntDevilEnd = EDevil.Count;
} else if (boatState == 1) {
cntPriestStart = SPriest.Count;
cntDevilStart = SDevil.Count;
cntPriestEnd = EPriest.Count + cntPriest;
cntDevilEnd = EDevil.Count + cntDevil;
}
/*cntPriestStart = SPriest.Count;
cntDevilStart = SDevil.Count;
cntPriestEnd = EPriest.Count;
cntDevilEnd = EDevil.Count;*/
if ((cntPriestStart != 0 && cntPriestStart < cntDevilStart) || (cntPriestEnd != 0 && cntPriestEnd < cntDevilEnd)) {
gameResult = 2;
}
return gameResult;
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
setCharacterPositions (SPriest, new Vector3 (-13f, 3, 0));
setCharacterPositions (EPriest, new Vector3 (9f, 3, 0));
setCharacterPositions (SDevil, new Vector3 (-8f, 3, 0));
setCharacterPositions (EDevil, new Vector3 (4f, 3, 0));
if (boatState == 2) {
boat.transform.position = Vector3.MoveTowards (boat.transform.position, boatEnd, speed * Time.fixedDeltaTime);
if (boat.transform.position == boatEnd) {
boatState = 1;
result ();
}
} else if (boatState == 3) {
boat.transform.position = Vector3.MoveTowards (boat.transform.position, boatStart, speed * Time.fixedDeltaTime);
if (boat.transform.position == boatStart) {
boatState = 0;
result ();
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class myGUI : MonoBehaviour {
private UserAction action;
// Use this for initialization
void Start () {
action = SDirector.getInstance ().currentSceneController as UserAction;
}
// Update is called once per frame
void OnGUI()
{
GUIStyle fontStyle = new GUIStyle();
fontStyle.normal.background = null;
fontStyle.normal.textColor = new Color(1, 0, 0);
fontStyle.fontSize = 20;
float width = Screen.width / 6;
float height = Screen.height / 12;
if (action.getResult()==1)
{ //赢了的话
GUI.Label(new Rect(Screen.width/2, 15, 100, 100), "Win!", fontStyle);
if (GUI.Button(new Rect(0, Screen.height - height, Screen.width, height), "Restart!"))
{
action.restart();
}
}
else if (action.getResult()==2)
{ //输了的话
GUI.Label(new Rect(Screen.width/2,15, 100, 100), "Lose!", fontStyle);
if (GUI.Button(new Rect(0, Screen.height - height, Screen.width, height), "Restart!"))
{
action.restart();
}
}
else
{
if (GUI.Button(new Rect(0, 0, width, height), "PriestOnBoat"))
{
action.priestGetOn();
}
if (GUI.Button(new Rect( width, 0, width, height), "PriestOffBoat"))
{
action.result ();
action.priestGetOff();
}
if (GUI.Button(new Rect(0, height, width, height), "DevilOnBoat"))
{
action.devilGetOn();
}
if (GUI.Button(new Rect(width, height, width, height), "DevilOffBoat"))
{
action.result ();
action.devilGetOff();
}
if (GUI.Button(new Rect(2 * width, 0, width, height), "GO"))
{
action.moveBoat();
}
if (GUI.Button (new Rect (2 * width, height, width, height), "restart")) {
action.restart ();
}
}
}
}