背景:
距离公司新项目《赶海XX》上线也有一个多月了,这么多年写过mmorpg类,动作类,卡牌类,小游戏还是头一遭。你可以什么都不服,但是时间总会把你制的服服贴贴。为了这次项目经历还能剩下点东西,我决定还是用文字记录一下还能想起的东西吧。
一如上线游戏中的赶海玩法,捕鱼的过程是可以拆解出一个个顺序的节点(你说鱼可能同时旋转加位移,我们可以当作是一个复杂节点),我们把这种顺序式称为Flow式,下面我们把整个思路整理一下。以下伪代码和截图只包含具体思路,并不包含逻辑细节。
参与对象:
Player类,Fish类,Pincer类等
附上基类结构,特殊类可以根据需求完成。
public abstract class Object { public int EntityID { private set; get; } public GameWorldBase World { private set; get; } public GameObject Root { private set; get; } public Entity Avatar { private set; get; } public Vector2 Grid { private set; get; } public Object(int entityID) { EntityID = entityID; } public void Create(GameWorldBase world, int avatarID, Vector3 pos, Vector3 rot) { } public void Destroy() { } public void Update(float deltaTime) { } public void HandleEvent(Message msg) { } protected virtual void OnCreate() { } protected virtual void OnDestroy() { } protected virtual void OnUpdate(float deltaTime) { } protected virtual void OnHandleEvent(Message msg) { } }
动作节点:
节点的基础类ActionNode:
public abstract class ActionNode { private ActionDirector director; protected Player player; protected Fish pickItem; protected bool isAction = false; protected bool isPause = false; public int ActionType; public ActionNode(ActionDirector director) { this.director = director; player = director.GetPlayer(); pickItem = director.GetPickup(); } public virtual void OnEnter() { isAction = true; } public virtual bool OnUpdate(float dt) { if (!isAction) return false; if (isPause) return false; return true; } public virtual void OnPause() { isPause = true; } public virtual void OnResume() { isPause = false; } public virtual void OnExit() { isAction = false; } public bool CanDoNext { get { return !isAction && !isPause; } } }
特殊节点类:
ActionParallel:平行节点,包含多个子节点,子节点同时运行
ActionSequence:顺序节点,包含多个子节点,子节点按顺序执行
ActionCondition:选择节点,包含两个子节点,根据输入执行对应节点
其他节点:
ActionDelay延迟节点,ActionAudio声音节点等其他各种各样的功能节点,根据功能不断扩充。
导演:
ActionDirector导演类,主要记录所有的Node节点,和节点的顺序执行。同时还包含节点数据的解析(根据编辑器存储的数据实例化出对应的各种节点)
public class ActionDirector { private Player player; private Fish pickItem; private bool isPerforming = false; private List<ActionNode> actionNodes = new List<ActionNode>(); private ActionNode actionNode = null; public ActionDirector() { } public void OnUpdate(float dt) { } public void OnDestory() { } public static ActionNode ParseAction(SimpleDirector director, ActionDataNode data) { return null; } }
节点编辑器:
根据不同节点的数据类型显示在编辑中显示出来:如
private void _GUIFieldCurve(ActionDataNode actionNode, SerializedProperty sp, string labelText=null) { actionNode.Curve = sp.FindPropertyRelative("Curve").animationCurveValue; actionNode.Curve = EditorGUILayout.CurveField(string.IsNullOrEmpty(labelText)?"Curve":labelText, actionNode.Curve); }
最终的实现效果如下:
文章评论