可视化
- OnDrawGizmos():画出所有
- OnDrawGizmosSelected()画出选中的
void OnDrawGizmosSelected() { Gizmos.color = Color.blue; Gizmos.DrawWireSphere(transform.position, sightRadius); }
获得范围内随机点用于巡逻
void GetNewWayPoint() { //还原停留时间 remainLookAtTime = lookAtTime; float randomX = Random.Range(-patrolRange, patrolRange); float randomZ = Random.Range(-patrolRange, patrolRange); Vector3 randomPoint = new Vector3(guardPos.x + randomX, transform.position.y, guardPos.z + randomZ); //随机点不能是障碍物 NavMeshHit hit; //NavMesh.SamplePosition用于寻找与给定点距离最近的可用点 //1指的是navmesh area里walkable的cost wayPoint = NavMesh.SamplePosition(randomPoint,out hit, patrolRange, 1) ? hit.position : transform.position; }
ScriptableObject
-数值型文件,用于存储数据
using System.Collections; using System.Collections.Generic; using UnityEngine; //默认文件名为New Data,菜单分级中为Character Stats/Data [CreateAssetMenu(fileName ="New Data",menuName="Character Stats/Data" )] //继承自ScriptableObject public class CharacterData_SO : ScriptableObject { [Header("Stats Info")] //最大血量 public int maxHealth; //当前血量 public int currentHealth; //基础防御 public int baseDefence; //当前防御 public int currentDefence; }
- 数值文件实例
创建状态管理类用于管理数据
- get/set用于快速访问和修改
sing System.Collections; using System.Collections.Generic; using UnityEngine; public class CharacterStats : MonoBehaviour { public CharacterData_SO characterData; public int MaxHealth { get{if (characterData != null)return characterData.maxHealth;else return 0;} set{characterData.maxHealth = value;} } }
同步脚本和动画的逻辑
void SwitchAnimation() { anim.SetBool("Walk", isWalk); anim.SetBool("Chase", isChase); anim.SetBool("Follow", isFollow); anim.SetBool("Critical", characterStats.isCritical); anim.SetBool("Death", isDead);
攻击造成伤害的实现
在Animation中添加帧事件
打开Animation面板
点击+号添加帧事件
触发Hit事件
//Animation Event void Hit() { var targetStats = attackTarget.GetComponent<CharacterStats>(); targetStats.TakeDamage(characterStats, targetStats); }
结算伤害
//受到攻击 public void TakeDamage(CharacterStats attacker,CharacterStats defender) { int damage = Mathf.Max(attacker.CurrentDamage() - defender.CurrentDefence,0); CurrentHealth = Mathf.Max(CurrentHealth - damage, 0); //暴击时触发挨打的人的受击动画 if (attacker.isCritical) { defender.GetComponent<Animator>().SetTrigger("Hit"); } //更新血量UI //结算经验值 }
部分Animation无法添加帧事件的解决办法
- 包含在fbx文件中的动画是无法编辑的
- 使用ctrl+D将动画复制一份到fbx外,使用复制的动画即可编辑
Quaternion.Lerp
- 差值运算,用于缓慢执行某个动作
- 如缓慢从一个角度旋转到另一个角度
transform.rotation = Quaternion.Lerp(transform.rotation,guardRotation,0.01f);
单位死亡时关闭相应组件
- 避免出现一遍播放死亡动画一遍移动,或是殴打尸体的情况
collider.enabled = false; agent.enabled = false;
泛型单例模式
- virtual为虚函数,在子类中使用override重载
using System.Collections; using System.Collections.Generic; using UnityEngine; //泛型类 public class Singleton<T> : MonoBehaviour where T:Singleton<T> { private static T instance; public static T Instance { get { return instance; } } protected virtual void Awake()//虚函数 { if (instance != null) Destroy(gameObject); else instance = (T)this; } public static bool IsInitialized { get { return instance != null; } } protected virtual void OnDestroy() { if (instance == this) { instance = null; } } }