做网页网站怎么样,中山祥云做的网站怎么样百度百科,车网站模板预览,制作网页的网站费用属于资本性支出吗最终效果 文章目录 最终效果前言素材下载#xff1a;玩家移动跳跃控制攻击动画配置轻攻击重攻击 攻击时禁止移动和攻击移动补偿敌人击退和播放受击动画受击特效攻击停顿和屏幕震动局部顿帧#xff08;补充#xff09;参考源码完结 前言
注意本文为自己的学习记录笔记#…最终效果 文章目录 最终效果前言素材下载玩家移动跳跃控制攻击动画配置轻攻击重攻击 攻击时禁止移动和攻击移动补偿敌人击退和播放受击动画受击特效攻击停顿和屏幕震动局部顿帧补充参考源码完结 前言
注意本文为自己的学习记录笔记主要是对游戏攻击 连击 轻重攻击和打击感进行探究其中打击感实现一般依靠播放受击动画、击退、攻击特效、时停和屏幕震动反馈等来实现如果你有其他的好方法也欢迎补充。
素材下载
人物 https://legnops.itch.io/red-hood-character
敌人 https://jesse-m.itch.io/skeleton-pack
环境 https://szadiart.itch.io/pixel-fantasy-caves
攻击特效 https://v-ktor.itch.io/pixelated-attackhit-animations
玩家移动跳跃控制
public class PlayerController : MonoBehaviour
{[Header(移动和跳跃参数)] public float moveSpeed; // 移动速度public float jumpForce; // 跳跃力量new private Rigidbody2D rigidbody; // 刚体组件private Animator animator; // 动画控制器private float input; // 输入private bool isGround; // 是否在地面上[SerializeField] private LayerMask layer; // 地面碰撞层[SerializeField] private Vector3 check; // 地面检测向量void Start(){rigidbody GetComponentRigidbody2D();animator GetComponentAnimator();}void Update(){input Input.GetAxisRaw(Horizontal);isGround Physics2D.OverlapCircle(transform.position new Vector3(check.x, check.y, 0), check.z, layer);animator.SetFloat(Horizontal, rigidbody.velocity.x);animator.SetFloat(Vertical, rigidbody.velocity.y);animator.SetBool(isGround, isGround);Move();Attack();}void Move(){// 根据输入来移动角色rigidbody.velocity new Vector2(input * moveSpeed, rigidbody.velocity.y);// 处理跳跃if (Input.GetButtonDown(Jump) isGround){rigidbody.velocity new Vector2(0, jumpForce);animator.SetTrigger(Jump); // 触发跳跃动画}// 根据水平速度方向更新角色朝向if (rigidbody.velocity.x 0)transform.localScale new Vector3(-1, 1, 1); // 向左else if (rigidbody.velocity.x 0)transform.localScale new Vector3(1, 1, 1); // 向右}private void OnDrawGizmos(){Gizmos.DrawWireSphere(transform.position new Vector3(check.x, check.y, 0), check.z);}}攻击动画配置 攻击动画分为轻攻击和重攻击 轻攻击 重攻击 [Header(攻击)]
public float interval 2f; // 攻击间隔时间
private float timer; // 计时器
private bool isAttack; // 是否正在攻击
private string attackType; // 攻击类型
private int comboStep; // 连击步骤void Update()
{//...Attack();
}void Attack()
{// 轻攻击输入检测if (Input.GetKeyDown(KeyCode.Return) !isAttack){isAttack true;attackType Light;comboStep; // 连击步骤加一if (comboStep 3)comboStep 1; // 连击步骤循环timer interval; // 设置计时器animator.SetTrigger(LightAttack); // 触发轻攻击动画animator.SetInteger(ComboStep, comboStep); // 设置连击步骤参数}// 重攻击输入检测if (Input.GetKeyDown(KeyCode.RightShift) !isAttack){isAttack true;attackType Heavy;comboStep; // 连击步骤加一if (comboStep 3)comboStep 1; // 连击步骤循环timer interval; // 设置计时器animator.SetTrigger(HeavyAttack); // 触发重攻击动画animator.SetInteger(ComboStep, comboStep); // 设置连击步骤参数}// 处理连击计时器if (timer ! 0){timer - Time.deltaTime;if (timer 0){timer 0;comboStep 0; // 重置连击步骤}}
}//攻击结束
public void AttackOver()
{isAttack false;
}配置每个攻击动画在执行的位置执行攻击结束事件通常攻击结束事件都不会放在动画的最后一帧因为连击一般都存在预输入也就是在上一个动画还未结束时就进行输入这样能很好的提升combo的连贯性 效果
攻击时禁止移动和攻击移动补偿
攻击时我们不希望玩家还能移动但是简单粗暴的禁止移动又会影响我们的攻击操作手感在死亡细胞等游戏中攻击时会朝前方以一个较小的速度移动这样可以一定程度的补偿攻击时无法移动的缺陷
[Header(攻击补偿速度)]
public float lightSpeed; // 轻攻击速度
public float heavySpeed; // 重攻击速度void Move()
{// 如果玩家没有在攻击状态下根据输入来移动角色if (!isAttack)rigidbody.velocity new Vector2(input * moveSpeed, rigidbody.velocity.y);else{// 如果正在攻击则根据攻击类型设置速度if (attackType Light)rigidbody.velocity new Vector2(transform.localScale.x * lightSpeed, rigidbody.velocity.y);else if (attackType Heavy)rigidbody.velocity new Vector2(transform.localScale.x * heavySpeed, rigidbody.velocity.y);}// ...
}配置 效果
敌人击退和播放受击动画
配置敌人受击动画 配置玩家每个动画的攻击范围 新增Enemy 敌人脚本实现击退和受击动画
public class Enemy : MonoBehaviour
{public float speed; // 敌人的移动速度private Vector2 direction; // 受击时的移动方向private bool isHit; // 是否正在受击状态private AnimatorStateInfo info; // 动画状态信息private Animator animator; // 敌人的主动画控制器new private Rigidbody2D rigidbody; // 敌人的刚体组件void Start(){// 获取组件的引用animator transform.GetComponentAnimator();rigidbody transform.GetComponentRigidbody2D();}void Update(){info animator.GetCurrentAnimatorStateInfo(0); // 获取当前动画状态信息if (isHit){rigidbody.velocity direction * speed; // 根据受击方向设置速度if (info.normalizedTime .6f)isHit false; // 当动画播放超过60%时结束受击状态}}// 外部调用使敌人进入受击状态public void GetHit(Vector2 direction){transform.localScale new Vector3(-direction.x, 1, 1); // 根据受击方向调整朝向isHit true; // 进入受击状态this.direction direction; // 设置受击方向animator.SetTrigger(Hit); // 播放主动画的受击动画状态}
}修改PlayerController调用击退敌人
private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag(Enemy)){// 根据角色朝向确定敌人受击方向if (transform.localScale.x 0)other.GetComponentEnemy().GetHit(Vector2.right); // 右侧受击else if (transform.localScale.x 0)other.GetComponentEnemy().GetHit(Vector2.left); // 左侧受击}
}效果
受击特效 特效动画配置 修改Enemy
private Animator hitAnimator; // 敌人的受击特效动画控制器hitAnimator transform.GetChild(0).GetComponentAnimator(); // 敌人的受击特效动画控制器在子对象中// 外部调用使敌人进入受击状态public void GetHit(Vector2 direction){//...hitAnimator.SetTrigger(Hit); // 播放受击特效动画}效果
攻击停顿和屏幕震动
新增AttackSense
public class AttackSense : MonoBehaviour
{private static AttackSense instance;public static AttackSense Instance{get{if (instance null)instance FindObjectOfTypeAttackSense(); // 查找当前场景中的 AttackSense 实例return instance;}}private bool isShake; // 是否正在进行摄像机震动// 暂停游戏一段时间public void HitPause(int duration){StartCoroutine(Pause(duration));}// 使用协程实现暂停功能IEnumerator Pause(int duration){float pauseTime duration / 60f; // 将帧数转换为实际暂停时间Time.timeScale 0.2f; // 将游戏时间缩放设为0.2yield return new WaitForSecondsRealtime(pauseTime); // 等待指定的暂停时间Time.timeScale 1; // 恢复游戏时间正常}// 触发摄像机震动效果public void CameraShake(float duration, float strength){if (!isShake) // 如果当前没有进行震动StartCoroutine(Shake(duration, strength));}// 使用协程实现摄像机震动效果IEnumerator Shake(float duration, float strength){isShake true; // 标记正在进行震动Transform camera Camera.main.transform; // 获取主摄像机的 Transform 组件Vector3 startPosition camera.position; // 记录摄像机震动前的初始位置while (duration 0){// 将摄像机位置随机偏移一定范围来模拟震动效果camera.position Random.insideUnitSphere * strength startPosition;duration - Time.deltaTime; // 每帧减去时间yield return null; // 等待下一帧}camera.position startPosition; // 震动结束后将摄像机位置恢复到初始位置isShake false; // 结束震动状态}
}修改PlayerController调用
[Header(打击感)]
public float shakeTime; // 摇晃时间
public int lightPause; // 轻攻击暂停时间
public float lightStrength; // 轻攻击相机震动强度
public int heavyPause; // 重攻击暂停时间
public float heavyStrength; // 重攻击相机震动强度private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag(Enemy)){// 根据攻击类型处理打击感if (attackType Light){AttackSense.Instance.HitPause(lightPause); // 轻攻击暂停AttackSense.Instance.CameraShake(shakeTime, lightStrength); // 相机震动}else if (attackType Heavy){AttackSense.Instance.HitPause(heavyPause); // 重攻击暂停AttackSense.Instance.CameraShake(shakeTime, heavyStrength); // 相机震动}// 根据角色朝向确定敌人击退方向if (transform.localScale.x 0)other.GetComponentEnemy().GetHit(Vector2.right); // 右侧受击else if (transform.localScale.x 0)other.GetComponentEnemy().GetHit(Vector2.left); // 左侧受击}
}配置参数 最终效果
局部顿帧补充
前面的顿帧这个思路其实不太好可以看看有的游戏他们不是所有物体都停顿的一般是攻击者和受击者停顿其他的不受影响。animator有个scale播放速度scale值应该可以实现这种效果连续攻击可能用局部顿帧好一点下面大概分享一下思路
public class AttackController : MonoBehaviour
{public Animator animator;public float slowMotionTimeScale 0.5f; // 慢动作时的时间缩放值public void PerformAttack(){StartCoroutine(AttackCoroutine());}IEnumerator AttackCoroutine(){// 播放攻击动画前先设置慢动作animator.speed slowMotionTimeScale;// 等待攻击动画播放完成yield return new WaitForSeconds(animator.GetCurrentAnimatorStateInfo(0).length / slowMotionTimeScale);// 恢复正常时间缩放animator.speed 1f;}
}在这个示例中PerformAttack 方法可以被调用来开始攻击动作。在攻击动作开始时时间缩放被设置为 slowMotionTimeScale然后通过 Coroutine 等待攻击动画播放完成后再恢复为正常速度。
通过这种方法你可以在游戏中实现局部的动画停顿效果而不是整体减速从而增强游戏的视觉冲击力和玩家的体验。
参考
https://www.bilibili.com/video/BV1fX4y1G7tv
源码
整理好我会放上来
完结
赠人玫瑰手有余香如果文章内容对你有所帮助请不要吝啬你的点赞评论和关注以便我第一时间收到反馈你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法也欢迎评论私信告诉我哦
好了我是向宇https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者出于兴趣爱好最近开始自学unity闲暇之余边学习边记录分享站在巨人的肩膀上通过学习前辈们的经验总是会给我很多帮助和启发php是工作unity是生活如果你遇到任何问题也欢迎你评论私信找我 虽然有些问题我也不一定会但是我会查阅各方资料争取给出最好的建议希望可以帮助更多想学编程的人共勉~