Unity手游制作记-制作通用基础动作管理器

xiaoxiao2021-02-28  102

动作管理

用来管理单位的动作。

我将动作分别攻击、防御、奔跑、发呆、死亡这5个基本动作,一般来说给你的模型的动作也就这几项。

我们今天就写个来统一管理,并进行通用化。

Animation和Animator

Unity的话,动画就分为这二个。

一个是状态机、一个是动画帧数。

接着我们来对这二个进行操作即可。

Animation这个的话,我就用Trigger来进行控制。

Animator这个的话,直接用Play即可。

using UnityEngine; using System.Collections; public class BehaviorOfAni : MonoBehaviour { Animation animation; Animator animator; public string nowAni = ""; int nowPriority = -1; // 当前动作优先级 float nowAniTime = 0; // 当前动作时间 float time = 0; // 当前动作计时 [SerializeField] string []attackAniName = {"Attack1", "Attack2", "Attack3"}; // 攻击名字 [SerializeField] float[] attackAniTime = {1.2f, 1.5f, 1.2f}; // 攻击时间 public int attackPriority = 3; // 攻击优先级 [SerializeField] string[] defendAniName = {"Defend"}; // 防御名字 [SerializeField] float[] defendAniTime = {1.0f}; // 防御时间 public int defendPriority = 1; // 防御优先级 [SerializeField] string runAniName = "Run"; // 奔跑名字 [SerializeField] float runAniTime = 1.0f; // 奔跑时间 public int runPriority = 2; // 奔跑优先级 [SerializeField] string idleAniName = "Idle"; // 发呆名字 [SerializeField] float idleAniTime = 1.0f; // 发呆时间 public int idlePriority = 0; // 发呆优先级 [SerializeField] string deathAniName = "Death"; // 死亡名字 [SerializeField] float deathAniTime = 2.5f; // 死亡时间 public int deathPriority = 10; // 死亡优先级 // Use this for initialization [SerializeField] public int nowTime = 0; void Start () { animation = GetComponent<Animation>(); animator = GetComponent<Animator>(); if (animation == null && animator == null) { Debug.LogError("未指定animation和animator中的任意一个"); } } public float beDef() { if (this.nowPriority < defendPriority) { if (this.nowAni.Equals("Defent")) { nowTime = 0; } else { nowTime++; if (nowTime >= defendAniName.Length) { nowTime = 0; } } if (animation) { animation.Play(defendAniName[nowTime]); } else { animator.SetBool(defendAniName[nowTime], true); } this.nowPriority = defendPriority; this.nowAniTime = defendAniTime[nowTime]; time = 0; nowAni = "Defend"; return nowAniTime; } return 0; } public float beAttack() { if (this.nowPriority < attackPriority) { if (this.nowAni.Equals("Attack")) { nowTime = 0; } else { nowTime++; if (nowTime >= attackAniName.Length) { nowTime = 0; } } if (animation) { animation.Play(attackAniName[nowTime]); } else { animator.SetBool(attackAniName[nowTime], true); } this.nowPriority = attackPriority; this.nowAniTime = attackAniTime[nowTime]; time = 0; nowAni = "Attack"; return nowAniTime; } return 0; } public float beIdle() { if (this.nowPriority < idlePriority) { if (animation) { animation.Play(idleAniName); } else { animator.SetBool(idleAniName, true); } this.nowPriority = idlePriority; this.nowAniTime = idleAniTime; time = 0; nowAni = "Idle"; return nowAniTime; } return 0; } public float beMustIdle() { if (animation) { animation.Play(idleAniName); } else { animator.SetBool(idleAniName, true); } this.nowPriority = idlePriority; this.nowAniTime = idleAniTime; time = 0; nowAni = "Idle"; return nowAniTime; } public float beRun() { if (this.nowPriority < runPriority) { if (animation) { animation.Play(runAniName); } else { animator.SetBool(runAniName, true); } this.nowPriority = runPriority; this.nowAniTime = runAniTime; time = 0; nowAni = "Run"; return nowAniTime; } return 0; } public float beDeath() { if (this.nowPriority < deathPriority) { if (animation) { animation.Play(deathAniName); } else { animator.SetBool(deathAniName, true); } this.nowPriority = deathPriority; this.nowAniTime = deathAniTime; time = 0; nowAni = "Death"; return nowAniTime; } return 0; } void FixedUpdate() { if (nowPriority != 0) { time += Time.fixedDeltaTime; if (time >= nowAniTime) { time = 0; nowPriority = -999; beMustIdle(); nowAni = ""; } } } }

加上执行时间和优先级,即可实现动作管理,用起来也非常的方便。

测试

void Start () { StartCoroutine(fun()); } IEnumerator fun() { yield return new WaitForSeconds(1.0f); float time = behaviorOfAni.beAttack(); TextControl.getIns().set3dText("正在执行攻击-" + time, behaviorOfAni.gameObject, Vector3.up * 2, time * 0.75f); yield return new WaitForSeconds(time * 1.25f); time = behaviorOfAni.beRun(); TextControl.getIns().set3dText("正在执行跑步-" + time, behaviorOfAni.gameObject, Vector3.up * 4, time * 0.75f); yield return new WaitForSeconds(time * 1.25f); time = behaviorOfAni.beIdle(); TextControl.getIns().set3dText("正在执行呆立-" + time, behaviorOfAni.gameObject, Vector3.up * 6, time * 0.75f); yield return new WaitForSeconds(time * 1.25f); time = behaviorOfAni.beDeath(); TextControl.getIns().set3dText("正在执行死亡-" + time, behaviorOfAni.gameObject, Vector3.up * 8, time * 0.75f); yield return new WaitForSeconds(time * 1.25f); behaviorOfAni.gameObject.AddComponent<AutoDeath>().maxTime = time; }

自动寻路攻击

接着就是配套的自动寻路攻击。

using UnityEngine; using System.Collections; [RequireComponent(typeof(NavMeshAgent))] public class BehaviorOfMove : MonoBehaviour { NavMeshAgent agent; float stoppingDistance; // Use this for initialization void Start() { init(); stoppingDistance = agent.stoppingDistance; } protected void init() { agent = GetComponent<NavMeshAgent>(); } public void moveTo(Vector3 pos) { if (!isFinish(pos)) { agent.destination = pos; } } public bool isFinish(Vector3 pos) { if (Vector3.Distance(this.transform.position, pos) <= stoppingDistance) { return true; } else { return false; } } }

具体的话,根据怪物的不同,我们需要继承下面这个类,进行逻辑设计。

using UnityEngine; using System.Collections; [RequireComponent(typeof(BehaviorOfMove))] public class BehaviorAutoAttack : MonoBehaviour { protected BehaviorOfMove move; protectedGameObject des; // 攻击目标 [SerializeField, TooltipAttribute("刷新周期(次/秒)")] protected int defTime = 10; // 周期 protected float time; // 记录周期 protected float maxTime; // 记录周期 protected virtual void Start() { init(); } protected virtual void init() { move = this.GetComponent<BehaviorOfMove>(); maxTime = 1.0f / defTime; } public void setAttack(GameObject att) { des = att; } protected virtual void attack() { } protected virtual void run() { } protected virtual void idle() { } protected virtual void doThing() { time += Time.fixedDeltaTime; if (time >= maxTime) { time = 0; if (des) { move.moveTo(des.transform.position); if (move.isFinish(des.transform.position)) { this.transform.LookAt(des.transform.position); attack(); } else { run(); } } } } }

以这个弓箭手为例(一般的远程也通用,近战也一样- -就是射程掌握好即可)

using UnityEngine; using System.Collections; [RequireComponent(typeof(BehaviorOfAni))] public class Archer : BehaviorAutoAttack { BehaviorOfAni ani; [SerializeField] float firingRange = 1.5f; // 射程 protected override void Start () { init(); } protected override void init() { base.init(); ani = this.GetComponent<BehaviorOfAni>(); this.move.setStoppingDistance(firingRange); } protected override void attack() { ani.beAttack(); } protected override void run() { ani.beRun(); } protected override void idle() { ani.beIdle(); } void FixedUpdate () { doThing(); } }

测试

可以看到弓箭手自动去攻击另外一个弓箭手

转载请注明原文地址: https://www.6miu.com/read-69237.html

最新回复(0)