织梦小说网站源码,手机网站 微信网站 区别,怎么把网站做seo到首页,中国上海人才市场官网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开发2D类银河恶魔城游戏学习笔记目录 文章目录 Unity开发2D类银河恶魔城游戏学习笔记前言一、概述二、创建骷髅攻击动画三、骷髅攻击的实现1整理代码2创建SkeletonAttackState3触发器的实现4攻击的实现 四、骷髅攻击的冷却总结 完整代码EnemyState.csEnemy.csEnemy_SkeletonAnimationTriggers.csEnemy_Skeleton.csSkeletonBattleState.csSkeletonAttackState.csSkeletonMoveState.cs  前言 
本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记如有错误欢迎指正。 
本节实现敌人的攻击状态。 
Udemy课程地址  
对应视频 Enemy’s Attack State 一、概述 
在骷髅进入战斗状态并走到距离玩家很近的距离时就要进入攻击状态攻击玩家。本节中我们就实现骷髅的攻击状态。 这一部分状态转换条件较多如下图   
二、创建骷髅攻击动画 
我们创建动画skeletonAttack 层次面板中选中Enemy_skeleton下的Animator在Animation面板中创建动画 将精灵表SkeletonAttack内容全部拖入采样率改为15 动画创建的更详细讲解见Unity教程零Unity和VS的使用相关内容     
连接状态机并添加过渡条件Attack并修改过渡设置 添加bool型条件变量Attack并连接过渡  Entry-skeletonAttack的过渡,加条件变量  
skeletonAttack-Exit的过渡,加条件变量并更改设置  
三、骷髅攻击的实现 
1整理代码 
上一节我们用到了很多次骷髅的速度所以我们在敌人状态中创建刚体使代码更简洁。 
protected Rigidbody2D rb;public virtual void Enter(){rb  enemyBase.rb;triggerCalled  false;enemyBase.anim.SetBool(animBoolName, true);}SkeletonBattleState状态Update函数中改为 public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance  enemy.attackDistance){stateMachine.ChangeState(enemy.attackState);}}if(player.position.x  enemy.transform.position.x)moveDir  1;else if(player.position.x  enemy.transform.position.x)moveDir  -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, rb.velocity.y);}SkeletonMoveState状态Update函数中改为 public override void Update(){base.Update();enemy.SetVelocity(enemy.moveSpeed*enemy.facingDir,rb.velocity.y);if(!enemy.isGroundDetected() || enemy.isWallDetected()){enemy.Flip();stateMachine.ChangeState(enemy.idleState);}}2创建SkeletonAttackState 
首先创建SkeletonAttackState它继承自EnemyState,通过菜单生成构造函数和重写。  添加Enemy_Skeleton变量并修改构造函数中传入值 protected Enemy_Skeleton enemy;public SkeletonAttackState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy  _enemy;}3触发器的实现 
和Player一样敌人攻击的结束也要借助触发器来实现。 详细讲解请见Unity教程八角色基本攻击的实现 我们在状态基类EnemyState中添加改变参数的函数若触发器被调用则triggerCalled置为真。添加代码 //修改触发器参数public virtual void AnimationFinishTrigger(){triggerCalled  true;}在Enemy中进行调用 //设置触发器public virtual void AnimationTrigger()  stateMachine.currentState.AnimationFinishTrigger();我们创建骷髅的触发器脚本Enemy_SkeletonAnimationTriggers。获取Animator的父组件Enemy_Skeleton并调用其中的AnimationTrigger() 
//Enemy_SkeletonAnimationTriggers:触发器组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_SkeletonAnimationTriggers : MonoBehaviour
{private Enemy_Skeleton enemy  GetComponentInParentEnemy_Skeleton();private void AnimationTrigger(){enemy.AnimationTrigger();}
}把触发器脚本挂在Enemy_Skeleton的Animator下面  我们在skeletonAttack的最后一帧设置事件帧调用触发器函数设置triggerCalled参数。 
先把白色竖线拉到最后一帧点击动画面板左边钉子符号的标志添加事件。   点击选中事件帧在右边面板选中函数AnimationTrigger Fuction-Enemy_SkeletonAnimationTriggers-Methods-AnimationTrigger()  
4攻击的实现 
我们要在Enemy_Skeleton中创建骷髅攻击状态。 
public SkeletonAttackState attackState { get; private set; }protected override void Awake()
{base.Awake();idleState  new SkeletonIdleState(stateMachine,this,this,Idle);moveState  new SkeletonMoveState(stateMachine, this,this, Move);battleState  new SkeletonBattleState(stateMachine, this, this, Move);attackState  new SkeletonAttackState(stateMachine, this, this, Attack);
}在SkeletonBattleState中添加状态转换当距离过近时转换到攻击状态。 public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance  enemy.attackDistance){stateMachine.ChangeState(enemy.attackState);}}if(player.position.x  enemy.transform.position.x)moveDir  1;else if(player.position.x  enemy.transform.position.x)moveDir  -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, enemy.rb.velocity.y);}我们在SkeletonAttackState中实现攻击的具体内容。 首先我们希望骷髅靠近玩家时先停止移动再攻击所以我们先把骷髅速度赋零。 在攻击动画播放完触发器被触发时攻击结束转换到战斗状态。  点击Animator也能看到左侧Attack变量在转换切换很快不仔细看不清楚。 
四、骷髅攻击的冷却 
现在骷髅的攻击是连续不断的在游戏中通常小怪是按照一定的频率进行的让玩家有一定的躲避时间。 我们给骷髅小怪加上攻击冷却时间实现上可以参照Player的连击。 我们在Enemy中添加冷却时间attackCoolDown记录上次攻击的时间lastTimeAttacked用于实现。 [Header(Attack Info)]public float attackDistance;public float attackCoolDown;[HideInInspector] public float lastTimeAttacked;在SkeletonAttackState中每次退出攻击状态时更新lastTimeAttacked。 public override void Exit(){base.Exit();enemy.lastTimeAttackedTime.time;}在SkeletonBattleState中添加CanAttack函数利用现在的时间与上次攻击时间加冷却时间比较判断冷却时间是否已经过去骷髅是否处于可攻击状态。 先判断是否能检测到玩家再判断玩家与骷髅的距离再做攻击冷却的判断条件都成立时转到战斗状态。 
public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance  enemy.attackDistance){if(CanAttack())stateMachine.ChangeState(enemy.attackState);}}if(player.position.x  enemy.transform.position.x)moveDir  1;else if(player.position.x  enemy.transform.position.x)moveDir  -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, rb.velocity.y);}private bool CanAttack(){if (Time.time  enemy.lastTimeAttacked  enemy.attackCoolDown)return true;return false;}设置合适的冷却时间  效果如下  我们可以看到骷髅每隔一段时间进行攻击了。但是有个很明显的问题在攻击的间隙骷髅不会停止移动玩家会被推着走。这个问题下节我们再来解决。 
总结 完整代码 
EnemyState.cs 
增加刚体和触发函数调用 
//EnemyState:敌人状态基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EnemyState
{protected EnemyStateMachine stateMachine;protected Enemy enemyBase;protected Rigidbody2D rb;private string animBoolName;protected float stateTimer;protected bool triggerCalled;//构造函数public EnemyState(EnemyStateMachine _stateMachine, Enemy _enemyBase, string _animBoolName){this.stateMachine  _stateMachine;this.enemyBase  _enemyBase;this.animBoolName  _animBoolName;}public virtual void Enter(){rb  enemyBase.rb;triggerCalled  false;enemyBase.anim.SetBool(animBoolName, true);}public virtual void Update(){stateTimer- Time.deltaTime;}public virtual void Exit(){enemyBase.anim.SetBool(animBoolName, false);}//修改触发器参数public virtual void AnimationFinishTrigger(){triggerCalled  true;}
} 
Enemy.cs 
添加攻击相关变量添加触发函数调用。 
//Enemy:敌人基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy : Entity
{[SerializeField] protected LayerMask WhatIsPlayer;[Header(Move Info)]public float moveSpeed  1.5f;public float idleTime  2.0f;[Header(Attack Info)]public float attackDistance;public float attackCoolDown;[HideInInspector] public float lastTimeAttacked;public EnemyStateMachine stateMachine;protected override void Awake(){base.Awake();stateMachine  new EnemyStateMachine();}protected override void Update(){base.Update();stateMachine.currentState.Update();}//设置触发器public virtual void AnimationTrigger()  stateMachine.currentState.AnimationFinishTrigger();public virtual RaycastHit2D IsPlayerDetected()Physics2D.Raycast(transform.position, Vector2.right * facingDir, 50 ,WhatIsPlayer);protected override void OnDrawGizmos(){base.OnDrawGizmos();Gizmos.color  Color.yellow;Gizmos.DrawLine(transform.position, new Vector3(transform.position.x  attackDistance * facingDir, transform.position.y));}
} 
Enemy_SkeletonAnimationTriggers.cs 
触发器组件 
//Enemy_SkeletonAnimationTriggers:触发器组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_SkeletonAnimationTriggers : MonoBehaviour
{private Enemy_Skeleton enemy  GetComponentInParentEnemy_Skeleton();private void AnimationTrigger(){enemy.AnimationTrigger();}
} 
Enemy_Skeleton.cs 
增加攻击状态创建 
//Enemy_Skeleton:骷髅敌人
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Enemy_Skeleton : Enemy
{#region 状态public SkeletonIdleState idleState { get; private set; }public SkeletonMoveState moveState { get; private set; }public SkeletonBattleState battleState { get; private set; }public SkeletonAttackState attackState { get; private set; }#endregionprotected override void Awake(){base.Awake();idleState  new SkeletonIdleState(stateMachine,this,this,Idle);moveState  new SkeletonMoveState(stateMachine, this,this, Move);battleState  new SkeletonBattleState(stateMachine, this, this, Move);attackState  new SkeletonAttackState(stateMachine, this, this, Attack);}protected override void Start(){base.Start();stateMachine.Initialize(idleState);}protected override void Update(){base.Update();}} 
SkeletonBattleState.cs 
添加攻击冷却判断条件修改转到攻击状态的条件修改刚体速度部分代码 
//SkeletonBattleState:骷髅战斗状态
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonBattleState : EnemyState
{private Transform player;private Enemy_Skeleton enemy;private int moveDir;public SkeletonBattleState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy_enemy;}public override void Enter(){base.Enter();player  GameObject.Find(Player).transform;}public override void Exit(){base.Exit();}public override void Update(){base.Update();if (enemy.IsPlayerDetected()){if (enemy.IsPlayerDetected().distance  enemy.attackDistance){if(CanAttack())stateMachine.ChangeState(enemy.attackState);}}if(player.position.x  enemy.transform.position.x)moveDir  1;else if(player.position.x  enemy.transform.position.x)moveDir  -1;enemy.SetVelocity(enemy.moveSpeed * moveDir, rb.velocity.y);}private bool CanAttack(){if (Time.time  enemy.lastTimeAttacked  enemy.attackCoolDown)return true;return false;}
} 
SkeletonAttackState.cs 
创建攻击状态攻击时速度置零触发器触发转回到战斗状态 
//SkeletonAttackState:骷髅攻击状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonAttackState : EnemyState
{protected Enemy_Skeleton enemy;public SkeletonAttackState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton _enemy, string _animBoolName) : base(_stateMachine, _enemyBase, _animBoolName){enemy  _enemy;}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();enemy.lastTimeAttackedTime.time;}public override void Update(){base.Update();enemy.ZeroVelocity();if (triggerCalled)stateMachine.ChangeState(enemy.battleState);}
}SkeletonMoveState.cs 
修改刚体速度部分代码 
//SkeletonMoveState:骷髅移动状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkeletonMoveState : SkeletonGroundedState
{public SkeletonMoveState(EnemyStateMachine _stateMachine, Enemy _enemyBase, Enemy_Skeleton enemy, string _animBoolName) : base(_stateMachine, _enemyBase, enemy, _animBoolName){}public override void Enter(){base.Enter();}public override void Exit(){base.Exit();}public override void Update(){base.Update();enemy.SetVelocity(enemy.moveSpeed*enemy.facingDir,rb.velocity.y);if(!enemy.isGroundDetected() || enemy.isWallDetected()){enemy.Flip();stateMachine.ChangeState(enemy.idleState);}}
}