动作分离:即 将游戏达到结束条件时的判断从场景控制器中分离出来处理。
同时也要将管理物体移动的程序从场景控制器中分离,以便独立管理游戏对象的动作。
首先:删除Moveable文件,新建Action和Judge文件
Action
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSAction : ScriptableObject{ //动作public bool enable = true; //是否正在进行此动作public bool destroy = false; //是否需要被销毁public GameObject gameobject{get;set;} //动作对象public Transform transform{get;set;} //动作对象的transformpublic ISSActionCallback callback{get;set;} //回调函数protected SSAction() { } //保证SSAction不会被newpublic virtual void Start() //子类可以使用这两个函数{throw new System.NotImplementedException();}public virtual void Update(){throw new System.NotImplementedException();}
}public class SSMoveToAction : SSAction //移动
{public Vector3 target; //移动到的目的地public float speed; //移动的速度private SSMoveToAction() { }public static SSMoveToAction GetSSAction(Vector3 target, float speed){SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();//让unity自己创建一个MoveToAction实例,并自己回收action.target = target;action.speed = speed;return action;}public override void Update(){ansform.position = Vector3.ansform.position, target, speed * Time.deltaTime);if (ansform.position == target){this.destroy = true;this.callback.SSActionEvent(this); //告诉动作管理或动作组合这个动作已完成}}public override void Start(){//移动动作建立时候不做任何事情}
}public class SequenceAction : SSAction, ISSActionCallback
{public List<SSAction> sequence; //动作的列表public int repeat = -1; //-1就是无限循环做组合中的动作public int start = 0; //当前做的动作的索引public static SequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence){SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();//让unity自己创建一个SequenceAction实例peat = repeat;action.sequence = sequence;action.start = start;return action;}public override void Update(){if (sequence.Count == 0) return;if (start < sequence.Count){sequence[start].Update(); //一个组合中的一个动作执行完后会调用接口,所以这里看似没有start++实则是在回调接口函数中实现}}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){source.destroy = false; //先保留这个动作,如果是无限循环动作组合之后还需要使用this.start++;if (this.start >= sequence.Count){this.start = 0;if (repeat > 0) repeat--;if (repeat == 0){this.destroy = true; //整个组合动作就删除this.callback.SSActionEvent(this); //告诉组合动作的管理对象组合做完了}}}public override void Start(){foreach (SSAction action in sequence){action.gameobject = this.ansform = ansform;action.callback = this; //组合动作的每个小的动作的回调是这个组合动作action.Start();}}void OnDestroy(){//如果组合动作做完第一个动作突然不要它继续做了,那么后面的具体的动作需要被释放}
}public enum SSActionEventType : int { Started, Competeted }public interface ISSActionCallback
{void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}public class SSActionManager : MonoBehaviour, ISSActionCallback //action管理器
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); //将执行的动作的字典集合,int为key,SSAction为valueprivate List<SSAction> waitingAdd = new List<SSAction>(); //等待去执行的动作列表private List<int> waitingDelete = new List<int>(); //等待删除的动作的key //不断更新待处理的动作protected void Update(){foreach (SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac; //获取动作实例的ID作为key}waitingAdd.Clear();foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}foreach (int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);DestroyObject(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = ansform = ansform;action.callback = manager;waitingAdd.Add(action);action.Start();}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){//牧师与魔鬼的游戏对象移动完成后就没有下一个要做的动作了,所以回调函数为空}
}public class MySceneActionManager : SSActionManager //本游戏管理器
{private SSMoveToAction moveBoatToEndOrStart; //移动船到结束岸,移动船到开始岸private SequenceAction moveRoleToLandorBoat; //移动角色到陆地,移动角色到船上public FirstController sceneController;protected new void Start(){sceneController = (Instance().currentSceneController;sceneController.actionManager = this;}public void moveBoat(GameObject boat, Vector3 target, float speed){moveBoatToEndOrStart = SSMoveToAction.GetSSAction(target, speed);//创建移动动作this.RunAction(boat, moveBoatToEndOrStart, this);//执行动作}public void moveCharacter(GameObject role, Vector3 middle_pos, Vector3 end_pos, float speed){SSAction action1 = SSMoveToAction.GetSSAction(middle_pos, speed);//创建前半部分路径的移动动作SSAction action2 = SSMoveToAction.GetSSAction(end_pos, speed);//创建后半部分路径的移动动作moveRoleToLandorBoat = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });//将两个动作组合成一个动作序列this.RunAction(role, moveRoleToLandorBoat, this);//执行动作序列}
}
Judge
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Judge : MonoBehaviour{private Land startLand;// 起始河岸private Land endLand;// 终点河岸private Boat boat;// 船public Judge(Land _startLand, Land _endLand, Boat _boat){startLand = _startLand;endLand = _endLand;boat = _boat;}public int checkGameState() { // 船在出发点int startNumOfPriest = NumOfPriest();int startNumOfDevil = NumOfDevil();int endNumOfPriest = NumOfPriest();int endNumOfDevil = NumOfDevil();int boatNumOfPriest = NumOfPriest();int boatNumOfDevil = NumOfDevil();if(endNumOfPriest + endNumOfDevil + boatNumOfPriest + boatNumOfDevil == 6){return 2;}CurPosition() == 1){if((startNumOfPriest < startNumOfDevil && startNumOfPriest > 0)||(endNumOfPriest + boatNumOfPriest < endNumOfDevil + boatNumOfDevil && endNumOfPriest + boatNumOfPriest > 0)){return 1;}}else{if((startNumOfPriest + boatNumOfPriest < startNumOfDevil + boatNumOfDevil && startNumOfPriest + boatNumOfPriest > 0) || (endNumOfPriest < endNumOfDevil && endNumOfPriest > 0)){return 1;}}return 0;}
}
修改Judge时同时需要更改FirstController的代码,在FirstController中调用Judge中的判断游戏结束的函数,因此FirstController的代码更改如下:
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 state;//游戏状态 0-gaming 1-lose 2-win private Character[] characters;// 六个游戏角色private _GUI userGUI;// GUI组件private Judge judge;// 新增的裁判类public MySceneActionManager actionManager; //新增的动作管理void Awake() {// 将自身设置为当前场记Director director = Instance ();director.currentSceneController = this;// 将GUI作为一个组件userGUI = gameObject.AddComponent <_GUI>() as _GUI;characters = new Character[6];// 加载游戏资源loadResources();// 将游戏动作管理器作为一个组件actionManager = gameObject.AddComponent<MySceneActionManager>() as MySceneActionManager; }// 实现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();judge = new Judge(startLand, endLand, boat);// 新增裁判类的初始化loadCharacter ();}// 实现SceneController接口,检查游戏状态 0->not finish, 1->lose, 2->win// public void checkGameState() { // // 船在出发点// int startNumOfPriest = NumOfPriest();// int startNumOfDevil = NumOfDevil();// int endNumOfPriest = NumOfPriest();// int endNumOfDevil = NumOfDevil();// int boatNumOfPriest = NumOfPriest();// int boatNumOfDevil = NumOfDevil();// if(endNumOfPriest + endNumOfDevil + boatNumOfPriest + boatNumOfDevil == 6){// state = 2;// return ;// }// CurPosition() == 1){// if((startNumOfPriest < startNumOfDevil && startNumOfPriest > 0)||(endNumOfPriest + boatNumOfPriest < endNumOfDevil + boatNumOfDevil && endNumOfPriest + boatNumOfPriest > 0)){// state = 1;// return ;// }// }// else{// if((startNumOfPriest + boatNumOfPriest < startNumOfDevil + boatNumOfDevil && startNumOfPriest + boatNumOfPriest > 0) || (endNumOfPriest < endNumOfDevil && endNumOfPriest > 0)){// state = 1;// return ;// }// }// state = 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 (OnLand(ch));characters[i] = ch;}for (int i = 0; i < 3; i++) {Character ch = new Character("devil");ch.setName("devil" + i);ch.setPosition (OnLand(ch));ch.getOnLand(startLand);characters [i+3] = ch;}}// 动作分离版新增,获取游戏对象到达目的地的路径上的中间位置,以便实现折线移动public Vector3 getMiddlePosition(GameObject gameObject,Vector3 dest){Vector3 middle = dest;if (dest.y < ansform.position.y) { // character from coast to boatmiddle.y = ansform.position.y;} else { // character from boat to coastmiddle.x = ansform.position.x;}return middle;}// 动作分离版修改,修改了原有的goButtonIsClickedpublic void goButtonIsClicked(){ if (!boat.isEmpty()){GameObject(),boat.boatMoveToPosition(),ve_speed); //动作分离版本改变state = judge.checkGameState();}}// 动作分离版修改,修改了原有的characterIsClickedpublic void characterIsClicked(Character ch){// 角色在船上IsOnBoat()){CurPosition() == 0){Vector3 end_pos = OnLand(ch);////ch.OnLand(ch));// 原来的//Vector3 end_pos = land.GetEmptyPosition(); //动作分离版本改变Vector3 middle_pos = GameObject(),end_pos); //动作分离版本改变GameObject(), middle_pos, end_pos, ch.move_speed); //动作分离版本改变ch.getOnLand(startLand);}else{Vector3 end_pos = OnLand(ch);Vector3 middle_pos = GameObject(),end_pos); //动作分离版本改变GameObject(), middle_pos, end_pos, ch.move_speed); //动作分离版本改变//ch.OnLand(ch));ch.getOnLand(endLand);}ch.getOffBoat();vePassenger(ch);}// 角色在岸上else{if(!boat.isFull()){IsFinished() && CurPosition() == 1){ch.getOnBoat(boat);endLand.leaveLand(ch);Vector3 end_pos = EmptyPosition();Vector3 middle_pos = GameObject(),end_pos);//ch.EmptyPosition());GameObject(), middle_pos, end_pos, ch.move_speed); //动作分离版本改变boat.addPassenger(ch);}if(!ch.getIsFinished() && CurPosition() == 0){ch.getOnBoat(boat);startLand.leaveLand(ch);Vector3 end_pos = EmptyPosition();Vector3 middle_pos = GameObject(),end_pos);GameObject(), middle_pos, end_pos, ch.move_speed); //动作分离版本改变//ch.EmptyPosition());boat.addPassenger(ch);}}}}// 实现UserAction接口的goButtonIsClicked函数// public void goButtonIsClicked(){// if(!boat.isEmpty()){// ve();// checkGameState();// }// }// 实现UserAction接口的characterIsClicked函数// public void characterIsClicked(Character ch){// // 角色在船上// IsOnBoat()){// CurPosition() == 0){// ch.OnLand(ch));// ch.getOnLand(startLand);// }// else{// ch.OnLand(ch));// ch.getOnLand(endLand);// }// ch.getOffBoat();// vePassenger(ch);// }// // 角色在岸上// else{// if(!boat.isFull()){// IsFinished() && CurPosition() == 1){// ch.getOnBoat(boat);// endLand.leaveLand(ch);// ch.EmptyPosition());// boat.addPassenger(ch);// }// if(!ch.getIsFinished() && CurPosition() == 0){// ch.getOnBoat(boat);// startLand.leaveLand(ch);// ch.EmptyPosition());// boat.addPassenger(ch);// }// }// }// }// 重置游戏public void restart(){state = 0;for(int i = 0;i < 6;++i){characters[i].reset();}set();set();set(); }}
以及SceneController中的checkGameState()函数也不需要了,因为功能在Judge里实现了。
游戏实际效果不变,因此链接如下
3D作业魔鬼与牧师
本文发布于:2024-02-02 13:27:00,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170685161944105.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |