前一个版本 FirstSceneController中包含了很多动作处理的部分。FirstSceneController类需要处理的事情太多,功能分离的不彻底。使用动作管理器将动作从 FirstSceneController类中分离出来能简化FirstSceneController类的结构,使之功能更加清晰。
首先明确动作管理器的基本结构,构造动作管理器基类:SSAction。首先是动作能否发生和动作是否完成,在这个游戏中,每个动作的发生还与两个因素有关:一个是触发动作的游戏对象gameObject,另一个是游戏对象的tranform。在每一个动作完成后,可能需要触发某些函数(例如:船移动结束后要判断是否游戏结束),因此添加一个回调函数callback。
using UnityEngine;
public class SSAction : ScriptableObject
{
public bool enable = true;
public bool destory = false;
public GameObject gameObject { get; set; }
public Transform transform { get; set; }
public ISSActionCallback callback { get; set; }
protected SSAction() { }
public virtual void Start () {
throw new System.NotImplementedException();
}
public virtual void Update() {
throw new System.NotImplementedException();
}
}
然后构建动作管理类:SSActionManager
using System.Collections.Generic;
using UnityEngine;
public class SSActionManager : MonoBehaviour {
public Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
public List waitingAdd = new List();
public List<int> waitingDelete = new List<int>();
protected void Update()
{
foreach (SSAction ac in waitingAdd)
actions[ac.GetInstanceID()] = ac;
waitingAdd.Clear();
foreach (KeyValuePair <int, SSAction> kv in actions)
{
if (kv.Value.destory)
waitingDelete.Add(kv.Value.GetInstanceID());
else if (kv.Value.enable)
kv.Value.Update();
else
waitingDelete.Add(kv.Value.GetInstanceID());
}
foreach (int key in waitingDelete)
{
DestroyObject(actions[key]);
actions.Remove(key);
}
waitingDelete.Clear();
}
public void RunAction(GameObject gameObject, SSAction action, ISSActionCallback manager)
{
action.gameObject = gameObject;
action.transform = gameObject.transform;
action.callback = manager;
waitingAdd.Add(action);
action.Start();
}
}
根据整个游戏过程中的动作,分为两个动作类:UserClickAction和CCMoveToAction。
UserClickAction类处理牧师和魔鬼的上船下船动作,CCMoveToAction处理船移动的动作。
UserClickAction类:
using UnityEngine;
public class UserClickAction : SSAction {
// Use this for initialization
public static UserClickAction GetSSAction()
{
UserClickAction action = CreateInstance();
return action;
}
public override void Start()
{
}
public override void Update()
{
FirstSceneController sceneController = SSDirector.getInstance().currentSceneController as FirstSceneController;
if (sceneController.onBoatDevil.Contains(gameObject) || sceneController.onBoatPriest.Contains(gameObject))
{
int f = sceneController.boat.transform.position.x < 0 ? 1 : -1;
int i = gameObject.name[gameObject.name.Length - 1] - '0';
gameObject.transform.parent = sceneController.transform;
gameObject.transform.position = new Vector3(f * (-4.9f - i * 0.6f), 1.0f, 0);
if(gameObject.tag == "devil")
{
sceneController.onBoatDevil.Remove(gameObject);
if (f > 0) sceneController.startDevil.Add(gameObject);
else sceneController.endDevil.Add(gameObject);
}
else
{
sceneController.onBoatPriest.Remove(gameObject);
if (f > 0) sceneController.startPriest.Add(gameObject);
else sceneController.endPriest.Add(gameObject);
}
sceneController.boatCapacity++;
}
else if (sceneController.boatCapacity > 0)
{
float i = sceneController.boat.transform.position.x * gameObject.transform.position.x;
if (i < 0) return;
int f = sceneController.boat.transform.position.x < 0 ? 1 : -1;
gameObject.transform.parent = sceneController.boat.transform;
if (sceneController.boatCapacity == 1)
{
Vector3 onBoatGameObjectPosition = (sceneController.onBoatPriest.Count == 1 ? sceneController.onBoatPriest[0] : sceneController.onBoatDevil[0]).transform.position;
gameObject.transform.position = new Vector3(-onBoatGameObjectPosition.x, onBoatGameObjectPosition.y,onBoatGameObjectPosition.z) + 2 * sceneController.boat.transform.position;
}
else
gameObject.transform.position = new Vector3(-0.6f, 0.25f) + sceneController.boat.transform.position;
if (gameObject.tag == "devil")
{
sceneController.onBoatDevil.Add(gameObject);
if (f > 0) sceneController.startDevil.Remove(gameObject);
else sceneController.endDevil.Remove(gameObject);
}
else
{
sceneController.onBoatPriest.Add(gameObject);
if (f > 0) sceneController.startPriest.Remove(gameObject);
else sceneController.endPriest.Remove(gameObject);
}
sceneController.boatCapacity--;
}
this.destory = true;
}
}
CCMoveToAction类:
using UnityEngine;
public class CCMoveToAction : SSAction
{
public Vector3 target;
public float speed;
public static CCMoveToAction GetSSAction(Vector3 target, float speed)
{
CCMoveToAction action = CreateInstance();
action.target = target;
action.speed = speed;
return action;
}
public override void Start()
{
}
public override void Update()
{
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed);
this.callback.SSActionEvent(this);
if (this.transform.position == target)
{
this.enable = false;
this.destory = true;
this.callback.CheckEvent(this);
}
}
}
最后我们需要一个调用这些动作,进行管理并和FirstSceneController通信的类:CCActionManager
using UnityEngine;
public class CCActionManager : SSActionManager, ISSActionCallback {
public FirstSceneController sceneController;
public CCMoveToAction moveToAction,moveToActionB;
public UserClickAction userClickAction;
protected new void Start()
{
sceneController = (FirstSceneController)SSDirector.getInstance().currentSceneController;
sceneController.actionManager = this;
}
protected new void Update()
{
if (Input.GetMouseButtonDown(0) && sceneController.flag == 0)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitGameObject;
if (Physics.Raycast(ray, out hitGameObject))
{
GameObject gameObject = hitGameObject.collider.gameObject;
if (gameObject.tag == "devil" || gameObject.tag == "priest")
{
userClickAction = UserClickAction.GetSSAction();
this.RunAction(gameObject, userClickAction, this);
}
else if (gameObject.transform.parent.name == "boat" && sceneController.boatCapacity < 2 && (moveToAction == null || !moveToAction.enable))
{
moveToAction = CCMoveToAction.GetSSAction(-gameObject.transform.parent.transform.position, 10*Time.deltaTime);
this.RunAction(gameObject.transform.parent.gameObject, moveToAction, this);
}
}
}
base.Update();
}
public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intParam = 0, string strParam = null, Object objParam = null)
{
if(source == moveToAction)
{
userClickAction.enable = !source.enable;
}
}
public void CheckEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed, int intParam = 0, string strParam = null, Object objParam = null)
{
if (source == moveToAction)
{
int startDevilNum = sceneController.startDevil.Count + (source.transform.position.x < 0 ? sceneController.onBoatDevil.Count : 0);
int startPriestNum = sceneController.startPriest.Count + (source.transform.position.x < 0 ? sceneController.onBoatPriest.Count : 0);
if (startDevilNum > startPriestNum && startPriestNum != 0)
sceneController.flag = 2;
else if (startPriestNum + startDevilNum == 0)
sceneController.flag = 1;
}
}
}
当这些类都完成后,动作已经可以很好地从FirstSceneController中分离出来了,现在处理一下FirstSceneController类吧。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class FirstSceneController : MonoBehaviour, IUserAction, ISceneController{
public CCActionManager actionManager;
public GameObject boat;
public List startPriest = new List();
public List startDevil = new List();
public List endPriest = new List();
public List endDevil = new List();
public List onBoatPriest = new List();
public List onBoatDevil = new List();
public int boatCapacity = 2;
public int flag = 0;
private void Awake()
{
SSDirector director = SSDirector.getInstance();
director.setFPS(60);
director.currentSceneController = this;
director.currentSceneController.GenGameObjects();
}
private void Start()
{
}
public void GenGameObjects ()
{
GameObject river = Instantiate(Resources.Load("prefabs/river"), Vector3.zero, Quaternion.identity);
river.name = "river";
river.transform.parent = this.transform;
boat = Instantiate(Resources.Load("prefabs/boat"));
boat.name = "boat";
boat.transform.parent = this.transform;
boat.transform.position = new Vector3(-3.5f,0);
for (int i=1;i<=3;++i)
{
GameObject person = Instantiate(Resources.Load("prefabs/Priest"));
person.name = "Priest" + i;
person.transform.parent = this.transform;
person.transform.position = new Vector3(- 4.9f - i*0.6f, 1.0f, 0);
startPriest.Add(person);
}
for (int i = 1; i <= 3; ++i)
{
GameObject person = Instantiate(Resources.Load("prefabs/Devils"));
person.name = "Devils" + (i+3);
person.transform.parent = this.transform;
person.transform.position = new Vector3(-4.9f - (i+3) * 0.6f, 1.0f, 0);
startDevil.Add(person);
}
}
}
更详细的内容请戳:传送门