已阅读5页,还剩8页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Unity3D 利用FSM设计相机跟随实现FSM有限状态机前面已经跟读者介绍过,使用Unity3D引擎实现了动作状态以及技能切换,FSM使用的条件是有限个状态切换,我们可以将FSM应用到相机中,很多人会问在相机中如何使用FSM,不论那种架构其主要目的是将模块之间的耦合性降低,传统的写法就是使用一个相机跟随类,所有的逻辑一股脑的写在一个类或者两个类中,这样一旦逻辑变动,修改起来非常麻烦,可能修改的就不是一个类两个类的事情,而如果我们采用FSM设计相机跟随,这样就容易多了。接下来就实现FSM有限状态机,FSM作为一个通用类需要将其设置成模版的方式,具体代码如下所示:csharp view plain copy 在CODE上查看代码片派生到我的代码片using System; using System.Collections.Generic; namespace Core public class FSM public class Object where T : Object public delegate void Function(T self, float time); #region Protected members protected TimeSource timeSource = null; protected DictionaryK, State states = new DictionaryK,State(); protected State state = null; protected State prevState = null; #endregion #region Ctors public Object() timeSource = TimeManager.Instance.MasterSource; public Object(TimeSource source) timeSource = source; #endregion #region Public properties public K PrevState get return prevState.key; public K State get return state.key; set prevState = state; if (prevState != null) prevState.onExit(this as T, timeSource.TotalTime); State nextState; if (states.TryGetValue(value, out nextState) state = nextState; state.onEnter(this as T, timeSource.TotalTime); else state = null; public TimeSource TimeSource get return timeSource; set timeSource = value; #endregion #region Public methods public void AddState(K key, Function onEnter, Function onExec, Function onExit) State newState = new State(); newState.key = key; newState.onEnter = onEnter; newState.onExec = onExec; newState.onExit = onExit; states.Add(key, newState); public void Update() if (null = state) return; state.onExec(this as T, timeSource.TotalTime); #endregion public class State where T : Object public K key; public Object.Function onEnter; public Object.Function onExec; public Object.Function onExit; 在这个类中有三部分最重要,第一部分是定义了状态类,它实现了状态的切换函数,onEnter,onExec,onExit,这个是作为状态切换使用的。代码如下:csharp view plain copy 在CODE上查看代码片派生到我的代码片public class State where T : Object public K key; public Object.Function onEnter; public Object.Function onExec; public Object.Function onExit; 另一个类的函数是增加状态函数,这个需要在Start函数中去执行的,函数代码如下所示:csharp view plain copy 在CODE上查看代码片派生到我的代码片public void AddState(K key, Function onEnter, Function onExec, Function onExit) State newState = new State(); newState.key = key; newState.onEnter = onEnter; newState.onExec = onExec; newState.onExit = onExit; states.Add(key, newState); 最后一个函数就是Update函数,需要每帧去检测执行状态,函数如下所示:csharp view plain copy 在CODE上查看代码片派生到我的代码片public void Update() if (null = state) return; state.onExec(this as T, timeSource.TotalTime); 这三个是最重要的,必须要有的,接下来编写挂接到对象上的类FiniteStateMachine类脚本,代码如下所示:csharp view plain copy 在CODE上查看代码片派生到我的代码片using Sstem; using System.Collections.Generic; using UnityEngine; using Core; public class FiniteStateMachine : MonoBehaviour public enum UpdateFunction Update = 0, LateUpdate, FixedUpdate #region Public classes public class FSMObject : FSM.Object public GameObject go; public FSMObject(GameObject _go) go = _go; Serializable public class StateType public int id; public string onEnterMessage; public string onExecMessage; public string onExitMessage; public void onEnter(FSMObject fsmObject, float time) fsmObject.go.SendMessage(onEnterMessage, time, SendMessageOptions.RequireReceiver); public void onExec(FSMObject fsmObject, float time) fsmObject.go.SendMessage(onExecMessage, time, SendMessageOptions.RequireReceiver); public void onExit(FSMObject fsmObject, float time) fsmObject.go.SendMessage(onExitMessage, time, SendMessageOptions.RequireReceiver); #endregion #region Public members public bool manualUpdate = false; public UpdateFunction updateFunction = UpdateFunction.Update; public StateType states; public int startState; #endregion #region Protected members protected FSMObject fsmObject = null; #endregion #region Public properties public int PrevState get return fsmObject.PrevState; public int State get return fsmObject.State; set fsmObject.State = value; public TimeSource TimeSource get return fsmObject.TimeSource; set fsmObject.TimeSource = value; #endregion #region Public methods public void ForceUpdate() fsmObject.Update(); #endregion #region Unity callbacks protected void Start() fsmObject = new FSMObject(gameObject); foreach (StateType state in states) fsmObject.AddState(state.id, state.onEnter, state.onExec, state.onExit); fsmObject.State = startState; void Update() /Debug.Log (update); if (manualUpdate) return; if (UpdateFunction.Update = updateFunction) fsmObject.Update(); void LateUpdate() if (manualUpdate) return; if (UpdateFunction.LateUpdate = updateFunction) fsmObject.Update(); void FixedUpdate() if (manualUpdate) return; if (UpdateFunction.FixedUpdate = updateFunction) fsmObject.Update(); #endregion 该函数需要挂接到对象上,效果如下所示:以上就是我们所封装的FSM有限状态机,接下来在项目中使用我们的FSM,先实现最基本的逻辑类如下所示:csharp view plain copy 在CODE上查看代码片派生到我的代码片using System; using System.Collections.Generic; using UnityEngine; public class FollowCharacter : MonoBehaviour public GameObject player; public Vector3 sourceOffset = new Vector3(0.0f, 2.5f, -3.4f); public Vector3 targetOffset = new Vector3(0.0f, 1.7f, 0.0f); protected bool firstFrame; protected float currHeightSmoothing; protected float groundHeightTest; protected bool slideshowActive = false; protected float slideshowEnterTime = 0.0f; protected float slideshowExitTime = 0.0f; protected bool oldCameraActive = true; protected float oldFov = 70.0f; protected Vector3 oldCamSourceOffset = new Vector3(0.0f, 8.5f, -4.5f); protected Vector3 oldCamTargetOffset = new Vector3(0.0f, 0.9f, 5.3f); protected int cameraIndex = 3; protected float cameraFovs = 55.0f, 60.0f, 55.0f ; protected Vector3 cameraSourceOffsets = new Vector3(0.0f, 5.8f, -3.8f), new Vector3(0.0f, 6.04f, -4.0f), new Vector3(0.0f, 8.5f, -6.7f) ; protected Vector3 cameraTargetOffsets = new Vector3(0.0f, 2.2f, 2.5f), new Vector3(0.0f, 1.35f, 3.36f), new Vector3(0.0f, 1.45f, 5.3f) ; protected Vector3 newCamSourceOffset = new Vector3(0.0f, 6.04f, -4.0f);/Camera 2 protected Vector3 newCamTargetOffset = new Vector3(0.0f, 1.35f, 3.36f);/Camera 2 protected Vector3 testNewTurboSourceOffset = new Vector3(0.0f, 5.8f, -4.0f); protected Vector3 testNewTurboTargetOffset = new Vector3(0.0f, 2.1f, 2.5f); protected Vector3 testNewFinalSourceOffset = new Vector3(-6.5f, 5.0f, -5.5f); protected Vector3 testNewFinalTargetOffset = new Vector3(-4.5f, 1.7f, 0.0f); csharp view plain copy 在CODE上查看代码片派生到我的代码片 #region public Classes public class ShakeData public float duration; public float noise; public float smoothTime; public ShakeData(float _duration, float _noise, float _smoothTime) duration = _duration; noise = _noise; smoothTime = _smoothTime; #endregion public void OnFollowCharaEnter(float time) prevPlayerPivot = player.transform.position; firstFrame = rue; currHeightSmoothing = heightSmoothing; deadTime = -1.0f; actionTaken = false; public void OnFollowCharaExec(float time) if (player = null) return; float dt = Time.fixedDeltaTime; float now = TimeManager.Instance.MasterSource.TotalTime; Vector3 playerPivot = player.transform.position; playerPivot.x = 0.0f; playerPivot.y = 0.0f; float targetHeight = playerPivot.y; if (firstFrame) lastPivotHeight = targetHeight; prevPlayerPivot = playerPivot; heightVelocity = 0.0f; firstFrame = false; else float targetSmoothTime = 0.1f; smoothTime = Mathf.MoveTowards(smoothTime, targetSmoothTime, 2.5f * dt); lastPivotHeight = Mathf.SmoothDamp(lastPivotHeight, targetHeight, ref heightVelocity, smoothTime, 50.0f, dt); prevPlayerPivot = playerPivot; Vector3 camPivot = new Vector3(prevPlayerPivot.x * 0.8f, lastPivotHeight, prevPlayerPivot.z); lastSourceOffset = this.EaseTo(lastSourceOffset, goalSourceOffset, sourceOffset); lastTargetOffset = this.EaseTo(lastTargetOffset, goalTargetOffset, targetOffset); transform.position = camPivot + lastSourceOffset + offset * 0.1f + noise * noiseStrength; / +noise * noiseStrength + noiseTremor * 0.00069f * kinematics.PlayerRigidbody.velocity.z; /PIETRO transform.LookAt(camPivot + lastTargetOffset + offset * 0.1f, Vector3.up); if (!TimeManager.Instance.MasterSource.IsPaused) /Camera Shake if (shakeCameraActive) ShakeCamera(dt); /tremor (always active this.UpdateTremor(dt); /check if is dead if (now - deadTime 3.6f & !actionTaken & deadTime 0.0f) actionTaken = true; /Debug.Log(GO TO REWARD); LevelRoot.Instance.BroadcastMessage(GoToOffgame); /GoToReward); public void OnFollowCharaExit(float time) void OnReset() /Debug.Log(RESET CAM); interpolating = false; shakeCameraActive = false; sourceOffset = defaultSourceOffset; targetOffset = defaultTargetOffset; void ShakeCamera(float deltaTime) if (TimeManager.Instance.MasterSource.TotalTime - shakeStartTime 0.0f) noiseStrength = Mathf.SmoothDamp(noiseStrength, currentShakeData.noise, ref noiseStrengthVel, currentShakeData.smoothTime, 300.0f, deltaTime); else noiseStrength = currentShakeData.noise; / go directly if (noiseStrength 0.0f) Vector3 v = UnityEngine.Random.onUnitSphere; noise += (v - noise) * deltaTime * 8.0f; else noise = SRVector3.zero; if (TimeManager.Instance.MasterSource.TotalTime - shakeStartTime = currentShakeData.duration) StopShakeCamera(); void StopShakeCam
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030专业建筑设计事务所市场供需分析评估投资规划合作模式研究报告
- 2026年山西经贸职业学院单招职业技能测试题库带答案详解(黄金题型)
- 2026年广东省湛江市单招职业适应性测试题库及答案详解(网校专用)
- 2026年崇左幼儿师范高等专科学校单招职业倾向性考试题库带答案详解(b卷)
- 2026车载摄像头模组产业链布局与技术创新分析报告
- 2026跨境电商物流配送网络供需关系及发展潜力评估报告
- 2026贵金属材料价格波动与投资风险分析报告
- 2026年广东省潮州市单招职业适应性考试题库附答案详解ab卷
- 2026自动驾驶高精度地图发展及商业模式研究报告
- 2026自动驾驶技术商业化路径及法规环境与风险管控分析报告
- 医疗机构反家暴培训课件
- 多发性硬化症患者的康复护理
- 2026春三年级下册第二单元6《会摇尾巴的狼》 教学教学课件
- 2025天津市自来水集团有限公司人才引进招聘试题及答案
- 2026年通辽职业学院单招职业适应性测试题库含答案详解
- 2025年湖南电气职业技术学院单招职业适应性考试题库附答案
- 2026年江苏安全技术职业学院单招职业技能测试必刷测试卷汇编
- 2025人教版一年级美术下册教案(全册)
- 机电安装安全施工方案
- 钢楼梯施工流程方案
- 2023新教科版科学五年级下册知识点
评论
0/150
提交评论