本节最终效果
前言
本节紧跟着上一篇,主要实现敌人受击死亡效果特效,主角等级、击杀数、经验、血条UI显示。
命中敌人闪白和击退效果
敌人动画配置
修改Enemy
WaitForFixedUpdate wait; void Awake() { //。。。 wait = new WaitForFixedUpdate();//等待下一帧 FixedUpdate() 调用 } void FixedUpdate() { //anim.GetCurrentAnimatorStateInfo(0).IsName("Hit")判断0层(第一个层级)的动画状态是否为名为 "Hit" 的状态 if (!isLive || anim.GetCurrentAnimatorStateInfo(0).IsName("Hit")) return; //。。。 } void OnTriggerEnter2D(Collider2D collision) { //... StartCoroutine(KnockBack()); // 启动协程,执行击退效果 if (health > 0) { anim.SetTrigger("Hit"); // 播放受击动画 } //... } IEnumerator KnockBack() { yield return wait; // 等待一段时间 Vector3 playerPos = GameManager.instance.player.transform.position; // 获取玩家的位置 Vector3 dirVec = transform.position - playerPos; // 计算从玩家位置指向当前位置的方向向量 rigid.AddForce(dirVec.normalized * 3, ForceMode2D.Impulse); // 施加一个以该方向为单位向量的冲量,实现击退效果 }
效果
敌人死亡效果
敌人死亡动画
修改Enemy
Collider2D coll; coll = GetComponent<Collider2D>(); private void OnEnable() { target = GameManager.instance.player.GetComponent<Rigidbody2D>(); isLive = true; health = maxHealth; coll.enabled = true; rigid.simulated = true; spriter.sortingOrder = 1; anim.SetBool("Dead", false); } private void Update() { if (anim.GetCurrentAnimatorStateInfo(0).IsName("Dead")) { //持续的获取动画进度 AnimatorStateInfo info = anim.GetCurrentAnimatorStateInfo(0); if (info.normalizedTime >= 1) { //当播放完动画后 Dead(); } } } void OnTriggerEnter2D(Collider2D collision) { //... else { isLive = false; coll.enabled = false; rigid.simulated = false; spriter.sortingOrder = 0;//死亡降低排序,不要遮挡其他敌人 anim.SetBool("Dead", true); } }
效果
等级 击杀数 经验
修改
public int level;//等级 public int kill;//杀敌数 public int exp;//经验值 public int[] nextExp = { 3, 5, 10, 100, 150, 210, 280, 360, 450, 600 };//升级梯度 //加经验和升级 public void GetExp(){ exp++; if(exp == nextExp[level]){ level ++; exp = 0; } }
修改Enemy,敌人死亡加经验和杀敌数
void OnTriggerEnter2D(Collider2D collision) { //... else { //... GameManager.instance.kill++; GameManager.instance.GetExp(); } }
效果,击杀敌人数据跟着增长
绘制经验条
画布配置
新增滑动条,配置如下
配置背景图
效果
新增HUD,用于显示不同类型信息的脚本
public class HUD : MonoBehaviour { public enum InfoType { Exp, Level, Kill, Time, Health } // 信息类型枚举 public InfoType type; // 当前信息类型 TextMeshProUGUI myText; // 文本组件 Slider mySlider; // 滑动条组件 void Awake() { myText = GetComponent<TextMeshProUGUI>(); mySlider = GetComponent<Slider>(); } void LateUpdate() { switch (type) { case InfoType.Exp: // 处理经验信息逻辑 float curExp = GameManager.instance.exp; float maxExp = GameManager.instance.nextExp[GameManager.instance.level]; mySlider.value = curExp / maxExp; break; case InfoType.Level: // 处理等级信息逻辑 break; case InfoType.Kill: // 处理击杀信息逻辑 break; case InfoType.Time: // 处理时间信息逻辑 break; case InfoType.Health: // 处理生命值信息逻辑 break; } } }
挂载脚本
效果
显示等级和杀敌数
绘制UI
修改HUD
case InfoType.Level: // 处理等级信息逻辑 myText.text = "Lv." + GameManager.instance.level; break; case InfoType.Kill: // 处理击杀信息逻辑 myText.text = GameManager.instance.kill.ToString(); break;
挂载脚本
效果
游戏倒计时
绘制UI
修改HUD
case InfoType.Time: // 处理时间信息逻辑 float remainTime = GameManager.instance.maxGameTime - GameManager.instance.gameTime; int min = Mathf.FloorToInt(remainTime / 60); int sec = Mathf.FloorToInt(remainTime % 60); myText.text = min + ":" + sec; break;
挂载脚本
效果
玩家血条
参考:
unity 3种办法实现血条效果并实现3d世界血条一直看向摄像机
绘制血条UI,和经验条差不多的方法,绘制即可,换个背景图
修改GameManager
public int health;//当前生命值 public int maxHealth = 100;//最大生命值 private void Start() { health = maxHealth; }
修改HUD
case InfoType.Health: // 处理生命值信息逻辑 float curHeadlth = GameManager.instance.health; float maxHealth = GameManager.instance.maxHealth; mySlider.value = curHeadlth / maxHealth; break;
挂载脚本
运行可以看到血条并不会跟随,因为我们把血条放在了UI屏幕上
新增Follow,控制血条跟随
public class Follow : MonoBehaviour { RectTransform rect; // UI元素的RectTransform组件 void Awake() { rect = GetComponent<RectTransform>(); } void FixedUpdate() { // 将玩家的世界坐标转换为屏幕坐标,并将UI元素的位置设置为屏幕坐标 rect.position = Camera.main.WorldToScreenPoint(GameManager.instance.player.transform.position); } }
挂载脚本
效果
参考
【视频】https://www.youtube.com/watch?v=MmW166cHj54&list=PLO-mt5Iu5TeZF8xMHqtT_DhAPKmjF6i3x
源码
源码在最后一节