【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili
教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/
本章节增强了敌人skeleton的攻击范围,并且给skeleton添加了快慢刀
白色圆框是增大后的敌人攻击范围,缩小了弹反的关键帧
SkeletonBattleState.cs
private bool CanAttack()
{
if (Time.time >= enemy.lastTimeAttack + enemy.attackCoolDown)
{
enemy.attackCoolDown = Random.Range(enemy.minAttackCoolDown, enemy.maxAttackCoolDown);
enemy.lastTimeAttack = Time.time;
return true;
}
else
return false;
}
修改玩家死亡后会一直攻击的bug
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SkeletonBattleState : EnemyState
{
private Transform player;
private Enemy_Skelteon enemy;
private int moveDir;
public SkeletonBattleState(Enemy _enemyBase, EnemyStateMachine _stateMachine, string _animBoolName, Enemy_Skelteon _enemy) : base(_enemy, _stateMachine, _animBoolName)
{
this.enemy = _enemy;
}
public override void Enter()
{
base.Enter();
//player = GameObject.Find("Player").transform;
player=PlayerManager.instance.player.transform;
if(player.GetComponent<PlayerStats>().isDead)
stateMachine.ChangeState(enemy.moveState);
}
public override void Update()
{
base.Update();
if (enemy.IsPlayerDetected())
{
stateTimer = enemy.battleTime;
if (enemy.IsPlayerDetected().distance < enemy.attackDistance)
{
if(CanAttack())
stateMachine.ChangeState(enemy.attackState);
}
}
else
{
if(stateTimer < 0 || Vector2.Distance ( player.transform.position,enemy.transform.position ) > 10 )//超过距离或者时间到了
stateMachine.ChangeState(enemy.idleState);
}
if (player.position.x > enemy.transform.position.x)
moveDir = 1;
else if (player.position.x < enemy.transform.position.x)
moveDir = -1;
if (Vector2.Distance(player.transform.position, enemy.transform.position) > 1)
enemy.SetVelocity(enemy.moveSpeed * moveDir, rb.velocity.y);
else
enemy.SetZeroVelocity();
}
public override void Exit()
{
base.Exit();
}
private bool CanAttack()
{
if (Time.time >= enemy.lastTimeAttack + enemy.attackCoolDown)
{
enemy.attackCoolDown = Random.Range(enemy.minAttackCoolDown, enemy.maxAttackCoolDown);
enemy.lastTimeAttack = Time.time;
return true;
}
else
return false;
}
}
Enemy.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : Entity
{
[SerializeField]protected LayerMask whatIsPlayer;// LayerMask: 这是字段的类型,LayerMask 是一个用于指定物理层的结构体 ; [SerializeField] 属性使得 whatIsPlayer 字段在 Unity 编辑器中可见
[Header("眩晕信息")]//Stunned info
public float stunDuration;
public Vector2 stunDirection;
public bool canBeStunned;
[SerializeField] protected GameObject counterImage;
[Header("移动信息")]//Move info
public float moveSpeed ;
public float idleTime;
public float battleTime;
private float defaultMoveSpeed;
[Header("攻击信息")]//Attack info
public float attackDistance;
public float attackCoolDown;
public float minAttackCoolDown;//最小攻击冷却时间
public float maxAttackCoolDown;
[HideInInspector] public float lastTimeAttack;
public EnemyStateMachine stateMachine { get; private set; }
public string lastAnimBoolName { get; protected set; }// 存储上一个动画布尔值的名称
protected override void Awake()
{
base.Awake();
stateMachine = new EnemyStateMachine();
defaultMoveSpeed = moveSpeed;
}
protected override void Update()
{
base.Update();
stateMachine.currentState.Update();
//Debug.Log(IsPlayerDetected().collider.gameObject.name+"i see it");
}
public virtual void AssignLastBoolName(string _animBoolName) => lastAnimBoolName = _animBoolName;
public override void SlowEntityBy(float _slowPercentage, float _slowDuration)
{
moveSpeed = moveSpeed * (1 - _slowPercentage);
anim.speed = anim.speed * (1 - _slowPercentage);
Invoke("ReturnDefaultSpeed", _slowDuration);
}
protected override void ReturnDefaultSpeed()
{
base.ReturnDefaultSpeed();
moveSpeed = defaultMoveSpeed;
}
public virtual void FreezeTime(bool _timeFrozen)
{
if (_timeFrozen)
{
moveSpeed = 0;
anim.speed = 0;
}
else
{
moveSpeed = defaultMoveSpeed;
anim.speed = 1;
}
}
public virtual void FreezeTimeFor(float _duration) => StartCoroutine(FreezeTimerCoroutine(_duration));
protected virtual IEnumerator FreezeTimerCoroutine(float _seconds)//IEnumerator 是一个接口,用于支持迭代器的实现。迭代器允许你在集合上进行迭代操作。Unity 中的协程(Coroutine)也使用 IEnumerator 来实现异步操作。
{
FreezeTime(true);
yield return new WaitForSeconds(_seconds);//等待 _seconds 秒
FreezeTime(false);
}
#region Counter Attack Window
public virtual void OpenCounterAttackWindow()// virtual 方法可以在派生类中使用 override 关键字进行重写,以提供不同的实现。
{
canBeStunned = true;
counterImage.SetActive(true);//这行代码将 counterImage 游戏对象设置为激活状态,使其在游戏中可见。
}
public virtual void CloseCounterAttackWindow()
{
canBeStunned = false;
counterImage.SetActive(false);
}
#endregion
public virtual bool CanBeStunned()
{
if (canBeStunned)
{
CloseCounterAttackWindow();
return true;
}
return false;
}
public virtual void AnimationFinishTrigger() => stateMachine.currentState.AnimationFinishTrigger();
public virtual RaycastHit2D IsPlayerDetected() => Physics2D.Raycast(wallCheck.position, Vector2.right * facingDir, wallCheckDistance, 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));
}
}