本文主要是介绍3D游戏编程与设计Hw4(牧师与魔鬼),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
- 游戏中提及的事物:物体牧师、物体魔鬼、物体河岸、物体水域、物体船。
玩家动作表(规则表)
玩家 | 玩家动作 |
---|---|
船 | 点击Go按钮则行进(船上必须有一个人) |
魔鬼/牧师 | 点击岸上的玩家则跑到船上,同理返回岸上。岸边的牧师数必须等于或大于魔鬼数,否则游戏失败 |
UML类图
代码参考学长博客实现:
Boat.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Boat{readonly GameObject boat;readonly Moveable moveableScript;readonly Vector3 startPos = new Vector3(-1.95F,0.68F,0);// 在起始岸边的位置readonly Vector3 endPos = new Vector3(1.95F,0.68F,0);// 在终点岸边的位置readonly Vector3 startFirstPos = new Vector3(-2.3F,1.15F,0);// 在起始岸边船的第一个座位位置readonly Vector3 startSecondPos = new Vector3(-1.54F,1.15F,0);// 在起始岸边船的第二个座位位置readonly Vector3 endFirstPos = new Vector3(1.54F,1.15F,0);// 在终点岸边船的第一个座位位置readonly Vector3 endSecondPos = new Vector3(2.3F,1.15F,0);// 在终点岸边船的第二个座位位置private Character[] passenger;// 乘客对象数组,存放船上的对象private int curPosition;//当前船在哪个岸边 0-start 1-endprivate int count;// 船上人数public Boat(){// 初始化对象数组,一开始船上无人,故置为空passenger = new Character[2];passenger[0] = null;passenger[1] = null;// 动态加载船的预制boat = Object.Instantiate (Resources.Load ("Prefabs/boat", typeof(GameObject)), startPos, Quaternion.identity, null) as GameObject;boat.name = "boat";// 添加moveable组件使得船可以移动moveableScript = boat.AddComponent (typeof(Moveable)) as Moveable;// 初始变量curPosition = 0;count = 0;}// move 函数使船可以根据当前位置进行移动public void move(){if(curPosition == 0){moveableScript.setDestination(endPos);curPosition = 1;}else{moveableScript.setDestination(startPos);curPosition = 0;}}// 下面两个函数分别用来判断船的情况public bool isEmpty(){return count == 0;}public bool isFull(){return count == 2;}public bool addPassenger(Character ch){if(count == 2){return false;}// 找到空位置for(int i = 0;i < 2;++i){if(passenger[i] == null){passenger[i] = ch;break;}}count++;return true;}public bool removePassenger(Character ch){if(count == 0){return false;}// 找到要删除的乘客for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getName() == ch.getName()){passenger[i] = null;}}count--;return true;}public int getCurPosition(){return curPosition;}public Vector3 getEmptyPosition(){// 若船已满,则返回坐标(0,0,0)if(count == 2){return new Vector3(0,0,0);}if(curPosition == 0){if(passenger[0] == null){return startFirstPos;}else{return startSecondPos;}}else{if(passenger[0] == null){return endFirstPos;}else{return endSecondPos;}}}public GameObject getGameobj(){return boat;}public int getNumOfPriest(){int res = 0;for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getType() == 0){res++;}}return res;}public int getNumOfDevil(){int res = 0;for(int i = 0;i < 2;++i){if(passenger[i] != null && passenger[i].getType() == 1){res++;}}return res;}public void reset(){count = 0;passenger[0] = null;passenger[1] = null;// 若船在终点,则回到起始岸if(curPosition == 1){moveableScript.setDestination(startPos);curPosition = 0;}}
}
Land.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Land{private GameObject land;readonly Vector3 startPos = new Vector3(-6.6F,0,0);// 起始岸的位置readonly Vector3 endPos = new Vector3(6.6F,0,0);// 终点岸的位置private int type;//河岸类型 0-start 1-endprivate int count;// 岸上人数private Character[] curCharacter;// 当前岸上的角色readonly Vector3[] place;// 岸上的六个位置坐标 角色数组下标和位置数组下标保持一致private int[] emptyPlace;// 岸上六个位置的情况 0-empty 1-not emptypublic Land(string sel){place = new Vector3[6];if(sel == "start"){land = Object.Instantiate(Resources.Load("Prefabs/land", typeof(GameObject)),startPos, Quaternion.identity, null) as GameObject;land.name = "start";type = 0;count = 0;for(int i = 0;i < 6;++i){place[i] = new Vector3(-3.5F-0.8F*i,1.5F,0);}}else{land = Object.Instantiate(Resources.Load("Prefabs/land", typeof(GameObject)),endPos, Quaternion.identity, null) as GameObject;land.name = "end";type = 1;count = 0;for(int i = 0;i < 6;++i){place[i] = new Vector3(3.5F+0.8F*i,1.5F,0);}}curCharacter = new Character[6];emptyPlace = new int[6];for(int i = 0;i < 6;++i){curCharacter[i] = null;}for(int i = 0;i < 6;++i){emptyPlace[i] = 0;}}public int getType(){return type;}public int getCount(){return count;}public Vector3 getOnLand(Character ch){int index = 0;// 找到空位置,将角色放入对应下标的角色数组中,方便后面查找删除while(true){if(emptyPlace[index] == 0){emptyPlace[index] = 1;curCharacter[index] = ch;count++;break;}else{index++;}}// 返回角色所在位置return place[index];}public void leaveLand(Character ch){for(int i = 0;i < 6;++i){if( curCharacter[i] != null && curCharacter[i].getName() == ch.getName()){curCharacter[i] = null;emptyPlace[i] = 0;count--;return;}} }public Vector3 getEmptyPosition(){for(int i = 0;i < 6;++i){if(emptyPlace[i] == 0){return place[i];}}return new Vector3(0,0,0);}public int getNumOfPriest(){int res = 0;for(int i = 0;i < 6;++i){if(curCharacter[i] == null){continue;}if(curCharacter[i].getType() == 0){res++;}}return res;}public int getNumOfDevil(){int res = 0;for(int i = 0;i < 6;++i){if(curCharacter[i] == null){continue;}if(curCharacter[i].getType() == 1){res++;}}return res;}public void reset(){if(type == 0){for(int i = 0;i < 6;++i){emptyPlace[i] = 1;}count = 6;}else{for(int i = 0;i < 6;++i){emptyPlace[i] = 0;}count = 0;}}
}
Character.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Character {readonly GameObject character;readonly int type; //0-priest 1-devilreadonly Moveable moveableScript;// 移动脚本组件readonly GUIClick _GUIClick;// 响应鼠标点击组件private bool isOnBoat;// 是否在船上private bool isFinished;//是否已经过河// 构造函数,根据传入的字符串选择创建牧师对象或者魔鬼对象public Character(string sel){// 动态加载预制if(sel == "priest"){character = Object.Instantiate(Resources.Load("Prefabs/priest", typeof(GameObject)),Vector3.zero, Quaternion.identity, null) as GameObject;type = 0;}else{character = Object.Instantiate(Resources.Load("Prefabs/devil", typeof(GameObject)),Vector3.zero, Quaternion.identity, null) as GameObject;type = 1;}// 为对象添加移动和点击响应组件moveableScript = character.AddComponent (typeof(Moveable)) as Moveable;_GUIClick = character.AddComponent(typeof(GUIClick)) as GUIClick;_GUIClick.bindCharacter(this);// 初始化变量isOnBoat = false;isFinished = false;}public int getType(){return type;}public void setName(string name) {character.name = name;}public string getName() {return character.name;}public void getOnBoat(Boat boat){// 设置transform为船的子组件,这样当船移动的时候就可以随着船移动character.transform.parent = boat.getGameobj().transform;isOnBoat = true;}public void getOffBoat(){character.transform.parent = null;isOnBoat = false;}public void getOnLand(Land land){if(land.getType() == 0){isFinished = false;}else{isFinished = true;}isOnBoat = false;}public bool getIsOnBoat(){return isOnBoat;}public void setPosition(Vector3 pos){character.transform.position = pos;}public void moveToPosition(Vector3 pos){moveableScript.setDestination(pos);}public bool getIsFinished(){return isFinished;}// 重置对象public void reset(){moveableScript.reset();// 如果对象已经过河if(isFinished){// 通过导演对象获取当前场景的控制器,取得其控制的Land对象Land endLand = (Director.getInstance ().currentSceneController as FirstController).endLand;endLand.leaveLand(this);Land startLand = (Director.getInstance ().currentSceneController as FirstController).startLand;getOnLand(startLand);setPosition(startLand.getOnLand(this));}// 如果对象在船上if(isOnBoat){getOffBoat();Land startLand = (Director.getInstance ().currentSceneController as FirstController).startLand;Boat boat = (Director.getInstance ().currentSceneController as FirstController).boat;boat.removePassenger(this);getOnLand(startLand);setPosition(startLand.getOnLand(this));}character.transform.parent = null; }}
以上是预制物体的代码,实现了程序运行后物体自动生成而不是在Scene界面自己做。
接下来是控制部分:
SceneController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface SceneController {void loadResources ();void checkGameStatus();
}
FirstController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FirstController : MonoBehaviour, SceneController, UserAction{readonly Vector3 water_pos = new Vector3(0,-0.4F,0);// 河流预制的位置public Land startLand;// 起始河岸public Land endLand;// 终点河岸public Boat boat;// 船public int status;//游戏状态 0-gaming 1-lose 2-win private Character[] characters;// 六个游戏角色private _GUI userGUI;// GUI组件void Awake() {// 将自身设置为当前场记Director director = Director.getInstance ();director.currentSceneController = this;// 将GUI作为一个组件userGUI = gameObject.AddComponent <_GUI>() as _GUI;characters = new Character[6];// 加载游戏资源loadResources();}// 实现SceneController接口,加载游戏资源public void loadResources() {GameObject water = Instantiate (Resources.Load ("Prefabs/river", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;water.name = "water";startLand = new Land ("start");endLand = new Land ("end");boat = new Boat();loadCharacter ();}// 实现SceneController接口,检查游戏状态 0->not finish, 1->lose, 2->winpublic void checkGameStatus() { // 船在出发点int startNumOfPriest = startLand.getNumOfPriest();int startNumOfDevil = startLand.getNumOfDevil();int endNumOfPriest = endLand.getNumOfPriest();int endNumOfDevil = endLand.getNumOfDevil();int boatNumOfPriest = boat.getNumOfPriest();int boatNumOfDevil = boat.getNumOfDevil();if(endNumOfPriest + endNumOfDevil + boatNumOfPriest + boatNumOfDevil == 6){status = 2;return ;}if(boat.getCurPosition() == 1){if((startNumOfPriest < startNumOfDevil && startNumOfPriest > 0)||(endNumOfPriest + boatNumOfPriest < endNumOfDevil + boatNumOfDevil && endNumOfPriest + boatNumOfPriest > 0)){status = 1;return ;}}else{if((startNumOfPriest + boatNumOfPriest < startNumOfDevil + boatNumOfDevil && startNumOfPriest + boatNumOfPriest > 0) || (endNumOfPriest < endNumOfDevil && endNumOfPriest > 0)){status = 1;return ;}}status = 0;}// 加载游戏对象private void loadCharacter() {for (int i = 0; i < 3; i++) {Character ch = new Character("priest");ch.setName("priest" + i);ch.getOnLand(startLand);ch.setPosition (startLand.getOnLand(ch));characters[i] = ch;}for (int i = 0; i < 3; i++) {Character ch = new Character("devil");ch.setName("devil" + i);ch.setPosition (startLand.getOnLand(ch));ch.getOnLand(startLand);characters [i+3] = ch;}}// 实现UserAction接口的goButtonIsClicked函数public void goButtonIsClicked(){if(!boat.isEmpty()){boat.move();checkGameStatus();}}// 实现UserAction接口的characterIsClicked函数public void characterIsClicked(Character ch){// 角色在船上if(ch.getIsOnBoat()){if(boat.getCurPosition() == 0){ch.moveToPosition(startLand.getOnLand(ch));ch.getOnLand(startLand);}else{ch.moveToPosition(endLand.getOnLand(ch));ch.getOnLand(endLand);}ch.getOffBoat();boat.removePassenger(ch);}// 角色在岸上else{if(!boat.isFull()){if(ch.getIsFinished() && boat.getCurPosition() == 1){ch.getOnBoat(boat);endLand.leaveLand(ch);ch.moveToPosition(boat.getEmptyPosition());boat.addPassenger(ch);}if(!ch.getIsFinished() && boat.getCurPosition() == 0){ch.getOnBoat(boat);startLand.leaveLand(ch);ch.moveToPosition(boat.getEmptyPosition());boat.addPassenger(ch);}}}}// 重置游戏public void restart(){status = 0;for(int i = 0;i < 6;++i){characters[i].reset();}boat.reset();startLand.reset();endLand.reset(); }}
Director.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Director : System.Object{private static Director _instance;public SceneController currentSceneController { get; set; }public static Director getInstance() {if (_instance == null) {_instance = new Director ();}return _instance;}
}
视觉部分(点击事件聚集处)
GUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class _GUI : MonoBehaviour{private SceneController sc;private UserAction ac;private GUIStyle style;private int status;private Texture2D priest;private Texture2D devil;private Texture2D rule;void Start(){style = new GUIStyle();style.fontSize = 40;// 获得控制器,通过控制器更新model部分的数据sc = Director.getInstance ().currentSceneController;ac = Director.getInstance().currentSceneController as UserAction;status = (Director.getInstance ().currentSceneController as FirstController).status;// 动态加载图片priest = Instantiate (Resources.Load ("Pictures/牧师", typeof(Texture2D))) as Texture2D;devil = Instantiate (Resources.Load ("Pictures/恶魔", typeof(Texture2D))) as Texture2D;rule = Instantiate (Resources.Load ("Pictures/规则", typeof(Texture2D))) as Texture2D;// Debug.Log("Screen.width"+Screen.width);// Debug.Log(" Screen.height"+ Screen.height);}void OnGUI(){// 同步游戏状态status = (Director.getInstance ().currentSceneController as FirstController).status;if(GUI.Button(new Rect(1300,850, 120, 120),"GO")){if(status == 0){ac.goButtonIsClicked();}}if(GUI.Button(new Rect(1600,850, 120, 120), "Restart")){ac.restart();}if(status == 1){GUI.Label(new Rect(800,100,300,250),devil);GUI.Label(new Rect(840, 400, 100, 50), "You lose!",style);}if(status == 2){GUI.Label(new Rect(800,100,300,250),priest);GUI.Label(new Rect(840, 400, 100, 50), "You win!",style);}GUI.Label(new Rect(0,800,1500,1500),rule);}
}
GUIClick.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GUIClick : MonoBehaviour{UserAction action;Character bindingCharacter;// 组件当前绑定的角色对象SceneController sc;int status;// 游戏状态public void bindCharacter(Character ch){bindingCharacter = ch;status = (Director.getInstance ().currentSceneController as FirstController).status;}void Start(){action = Director.getInstance().currentSceneController as UserAction;sc = Director.getInstance().currentSceneController;}void OnMouseDown(){// 同步游戏状态status = (Director.getInstance ().currentSceneController as FirstController).status;// 只有在游戏中点击才有效if(status == 0){action.characterIsClicked(bindingCharacter);}}
}
剩下两个组件:
Moveabel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Moveable : MonoBehaviour{readonly float speed = 10;int moving_status; // 0->not moving, 1->moving to middle, 2->moving to destVector3 dest;Vector3 middle;void Update() {if (moving_status == 1) {transform.position = Vector3.MoveTowards (transform.position, middle, speed * Time.deltaTime);if (transform.position == middle) {moving_status = 2;}} else if (moving_status == 2) {transform.position = Vector3.MoveTowards (transform.position, dest, speed * Time.deltaTime);if (transform.position == dest) {moving_status = 0;}}}public void setDestination(Vector3 _dest) {dest = _dest;middle = _dest;if (_dest.y == transform.position.y) { // boat movingmoving_status = 2;}else if (_dest.y < transform.position.y) { // character from coast to boatmiddle.y = transform.position.y;} else { // character from boat to coastmiddle.x = transform.position.x;}moving_status = 1;}public void reset() {moving_status = 0;}
}
UserAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface UserAction {public void goButtonIsClicked();public void characterIsClicked(Character characterCtrl);public void restart();
}
- 视频链接
3D作业牧师与魔鬼
这篇关于3D游戏编程与设计Hw4(牧师与魔鬼)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!