活泼的网站广州网站制作公司 番禺
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:51
当前位置: 首页 > news >正文
活泼的网站,广州网站制作公司 番禺,深圳做网站建设和维护专员管理层,备案期间网站关闭Unity开发2D类银河恶魔城游戏学习笔记
Unity教程#xff08;零#xff09;Unity和VS的使用相关内容 Unity教程#xff08;一#xff09;开始学习状态机 Unity教程#xff08;二#xff09;角色移动的实现 Unity教程#xff08;三#xff09;角色跳跃的实现 Unity教程零Unity和VS的使用相关内容 Unity教程一开始学习状态机 Unity教程二角色移动的实现 Unity教程三角色跳跃的实现 Unity教程四碰撞检测 Unity教程五角色冲刺的实现 Unity教程六角色滑墙的实现 Unity教程七角色蹬墙跳的实现 Unity教程八角色攻击的基本实现 Unity教程九角色攻击的改进
Unity教程十Tile Palette搭建平台关卡 Unity教程十一相机 Unity教程十二视差背景
Unity教程十三敌人状态机 Unity教程十四敌人空闲和移动的实现 Unity教程十五敌人战斗状态的实现 Unity教程十六敌人攻击状态的实现 Unity教程十七敌人战斗状态的完善
Unity教程十八战斗系统 攻击逻辑 Unity教程十九战斗系统 受击反馈 Unity教程二十战斗系统 角色反击 如果你更习惯用知乎 Unity开发2D类银河恶魔城游戏学习笔记目录 文章目录 Unity开发2D类银河恶魔城游戏学习笔记前言一、概述二、闪烁特效的实现1创建闪烁特效材质2实现闪烁特效脚本 三、击退效果的实现四、攻击方向问题的修复总结 完整代码EntityFX.csEntity.csPlayerPrimaryAttackState.cs 前言
本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记如有错误欢迎指正。
本节实现战斗系统的受击反馈部分。
Udemy课程地址
对应视频 On Hit Fx On Hit Impact Attack’s direction hot fix 一、概述
本节我们实现角色的受击反馈包括闪烁特效击退效果两部分。 为实现特效创建了实体特效组件用于存放作用于实体的特效。闪烁特效用两种材质交替实现。击退效果设置受击角色速度实现。 除此之外还修复了学习过程中发现的攻击方向bug。
二、闪烁特效的实现
在开始之前我们先整理一下脚本文件把相应脚本放入创建的文件夹中文件整理大致如下
1创建闪烁特效材质
首先我们在Materials文件夹中创建闪烁特效FlashFXMaterial。 在Project面板中 右键-Create-Material-重命名为FlashFXMaterial Shader选择GUI-Text Shader,Text Color选择白色 更换Playerd Animator的材质看一下效果 将原始材质与这个纯白的来回交替就可以产生闪烁的特效。
2实现闪烁特效脚本
首先我们创建一个特效组件EntityFX用来实现实体的特效。
特效由更换精灵的材质实现即要调用接口修改对应实体下Animator中SpriteRenderer组件的Material属性。 首先要在EntityFX中获取相应SpriteRenderer组件并设置两个变量分别存储原始材质和受击后的材质。还要创建变量flashDuration定义受击后闪烁的时长。
//EntityFX:实体特效
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EntityFX : MonoBehaviour
{private SpriteRenderer sr;[Header(Flash FX)][SerializeField] private Material hitMat;private Material originalMat;[SerializeField] private float flashDuration;private void Start(){sr GetComponentInChildrenSpriteRenderer();originalMat sr.material;}
}接着使用协程实现材质每隔一小段时间更替一次材质。 //闪烁特性private IEnumerator FlashFX(){sr.material hitMat;yield return new WaitForSeconds(flashDuration);sr.material originalMat;}在Entity中创建特效组件EntityFX并赋值。 #region 组件public EntityFX fx { get; private set; }public Rigidbody2D rb { get; private set; }public Animator anim { get; private set; }#endregion//获取组件protected virtual void Start(){fx GetComponentEntityFX();rb GetComponentRigidbody2D();anim GetComponentInChildrenAnimator();}在Entity的Damage函数中调用闪烁特效。 public virtual void Damage(){fx.StartCoroutine(FlashFX);Debug.Log(gameObject.name was damaged);}将EntityFX拖到Player上作为组件拖入闪烁特效作为受击材质并给闪烁持续时间赋一个合适的值。 骷髅小怪Enemy_Skeleton同理最终效果如下
三、击退效果的实现
击退效果我们依然用协程实现。在实体受到攻击时设置实体后退速度等待一小段时间后恢复原来速度设置。
在Entity中创建击退效果相关的变量分别为击退方向是否被击退击退持续的时间。 [Header(Knockback Info)][SerializeField] protected Vector2 knockbackDirection;[SerializeField] protected float knockbackDuration;protected bool isKnocked;创建一个协程HitKnockback设置击退速度。一个实体受到攻击后后退方向与它面向的方向相反。这里存在一个问题在玩家从背后攻击骷髅时一般骷髅会在检测后迅速转身但个别时候会发生它没有转身就受到攻击的情况这时骷髅会向它朝向的方向跌这个问题本节暂不解决。
isKnocked用来记录实体是否处于被击退的状态在击退效果持续期间我们需要让其他涉及设置速度的操作都不生效在击退结束后再恢复原来状态里的速度设置。 protected virtual IEnumerator HitKnockback(){isKnocked true;rb.velocity new Vector2(knockbackDirection.x * -facingDir, knockbackDirection.y);yield return new WaitForSeconds(knockbackDuration);isKnocked false;}在速度设置和速度置零函数中添加一个判定当处于击退状态时直接return不执行后面设置速度的部分直到击退结束。 #region 速度设置//速度置零public void ZeroVelocity(){if (isKnocked)return;rb.velocity new Vector2(0, 0);}//设置速度public void SetVelocity(float _xVelocity, float _yVelocity){if (isKnocked)return;rb.velocity new Vector2(_xVelocity, _yVelocity);FlipController(_xVelocity);}#endregion在Damage函数中调用击退效果。 public virtual void Damage(){fx.StartCoroutine(FlashFX);StartCoroutine(HitKnockback);Debug.Log(gameObject.name was damaged);}骷髅受到攻击后直接飘出去了。加大重力就可以解决这一问题。但需要注意加大重力后骷髅的移速也会变迟缓可以根据需要设定。 四、攻击方向问题的修复
在学习过程中发现了一个问题在个别先向左后向右跑的时候角色面向右进行攻击时攻击方向却是向左。 问题出在下图位置。在基本攻击状态PlayerPrimaryAttackState中我们原本设置的是攻击时如果有输入攻击方向为输入方向但在进入攻击状态时xInput并不是最新的。 xInput的定义在状态基类PlayerState中它的赋值在Update函数中进行PlayerPrimaryAttackState继承自状态基类所以每次进入攻击状态获取的xInput都是上次攻击Update中获取的。 教程里的改法是在进入状态时xInput赋0。我选择了在进入时重新获取一次xInput。 //进入public override void Enter(){base.Enter();xInput Input.GetAxisRaw(Horizontal);//攻击方向问题教程改法//xInput 0;if (comboCounter 2 || Time.time lastTimeAttacked comboWindow)comboCounter 0;player.anim.SetInteger(comboCounter,comboCounter);float attackDir player.facingDir;if (xInput ! 0)attackDir xInput;player.SetVelocity(player.attackMovement[comboCounter].x * attackDir, player.attackMovement[comboCounter].y);stateTimer 0.1f;}总结 完整代码
EntityFX.cs
实体特效组件。实现闪烁特效。
//EntityFX:实体特效
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EntityFX : MonoBehaviour
{private SpriteRenderer sr;[Header(Flash FX)][SerializeField] private Material hitMat;private Material originalMat;[SerializeField] private float flashDuration;private void Start(){sr GetComponentInChildrenSpriteRenderer();originalMat sr.material;}//闪烁特效private IEnumerator FlashFX(){sr.material hitMat;yield return new WaitForSeconds(flashDuration);sr.material originalMat;}
}Entity.cs
获取实体特效组件调用闪烁特效。实现并调用击退效果修改速度设置。
//Entity:实体类
using System.Collections;
using System.Collections.Generic;
using Unity.IO.LowLevel.Unsafe;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;public class Entity : MonoBehaviour
{[Header(Knockback Info)][SerializeField] protected Vector2 knockbackDirection;[SerializeField] protected float knockbackDuration;protected bool isKnocked;[Header(Flip Info)]protected bool facingRight true;public int facingDir { get; private set; } 1;[Header(Collision Info)]public Transform attackCheck;public float attackCheckRadius;[SerializeField] protected Transform groundCheck;[SerializeField] protected float groundCheckDistance;[SerializeField] protected Transform wallCheck;[SerializeField] protected float wallCheckDistance;[SerializeField] protected LayerMask whatIsGround;#region 组件public EntityFX fx { get; private set; }public Rigidbody2D rb { get; private set; }public Animator anim { get; private set; }#endregionprotected virtual void Awake(){}//获取组件protected virtual void Start(){fx GetComponentEntityFX();rb GetComponentRigidbody2D();anim GetComponentInChildrenAnimator();}// 更新protected virtual void Update(){}public virtual void Damage(){fx.StartCoroutine(FlashFX);StartCoroutine(HitKnockback);Debug.Log(gameObject.name was damaged);}protected virtual IEnumerator HitKnockback(){isKnocked true;rb.velocity new Vector2(knockbackDirection.x * -facingDir, knockbackDirection.y);yield return new WaitForSeconds(knockbackDuration);isKnocked false;}#region 速度设置//速度置零public void ZeroVelocity(){if (isKnocked)return;rb.velocity new Vector2(0, 0);}//设置速度public void SetVelocity(float _xVelocity, float _yVelocity){if (isKnocked)return;rb.velocity new Vector2(_xVelocity, _yVelocity);FlipController(_xVelocity);}#endregion#region 翻转//翻转实现public virtual void Flip(){facingDir -1 * facingDir;facingRight !facingRight;transform.Rotate(0, 180, 0);}//翻转控制public virtual void FlipController(float _x){if (_x 0 !facingRight)Flip();else if (_x 0 facingRight)Flip();}#endregion#region 碰撞//碰撞检测public virtual bool isGroundDetected() Physics2D.Raycast(groundCheck.position, Vector2.down, groundCheckDistance, whatIsGround);public virtual bool isWallDetected() Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, whatIsGround);//绘制碰撞检测protected virtual void OnDrawGizmos(){Gizmos.DrawLine(groundCheck.position, new Vector3(groundCheck.position.x, groundCheck.position.y - groundCheckDistance));Gizmos.DrawLine(wallCheck.position, new Vector3(wallCheck.position.x wallCheckDistance, wallCheck.position.y));Gizmos.DrawWireSphere(attackCheck.position, attackCheckRadius);}#endregion
}
PlayerPrimaryAttackState.cs
修复攻击方向问题。
//PlayerPrimaryAttackState:基本攻击状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerPrimaryAttackState : PlayerState
{private int comboCounter;private float lastTimeAttacked;private float comboWindow 2;public PlayerPrimaryAttackState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName) : base(_stateMachine, _player, _animBoolName){}//进入public override void Enter(){base.Enter();xInput Input.GetAxisRaw(Horizontal);//攻击方向问题教程改法//xInput 0;if (comboCounter 2 || Time.time lastTimeAttacked comboWindow)comboCounter 0;player.anim.SetInteger(comboCounter,comboCounter);float attackDir player.facingDir;if (xInput ! 0)attackDir xInput;player.SetVelocity(player.attackMovement[comboCounter].x * attackDir, player.attackMovement[comboCounter].y);stateTimer 0.1f;}//退出public override void Exit(){base.Exit();player.StartCoroutine(BusyFor, 0.15f);comboCounter;lastTimeAttacked Time.time;}// 更新public override void Update(){base.Update();if (stateTimer 0)player.ZeroVelocity();if(triggerCalled)stateMachine.ChangeState(player.idleState);}
}
- 上一篇: 活动手机网站开发如何清空网站数据库
- 下一篇: 活泼的网站网络培训总结
