Hi,
I decided going into the course that I wanted to have the player tap a button rather than hold to execute the attack action as well as give the player two ways of doing damage, one being light damage, with the other being heavy damage.
At first I put both the light and heavy animations in one array (exactly as it was done in the course) and had the player attacking switch state function in both the targeting and free look script dictate which damage type was being used by keeping the 0 as it was for the Light Attack button and changing the 0 to a 3 if the Heavy Attack Button was selected. However while everything else in the melee combat section of this course worked, I was unable to get the player to perform anything outside of the first animation for both Light and Heavy.
Presently, I decided to create two arrays in the player state machine, one that holds the light attack damage and another for the heavy attack damage as I have a few individuals do the same thing. But, more errors have occurred with this method than the previous one to the point where I question if I should revert back to the previous iteration. Upon attacking using both Light and Heavy Attack Button, only the Heavy Attack animation plays, and once again, it is only the first heavy animation. I tried coming up with a method as I have seen those before do but to no avail do they work and now they’re just blank.
I suspect the problem comes from the the cluster of items in enter function as well as an oversight in the tick function
(Apologies, this is my first, I didn’t know how to format the code for a post)
public class PlayerAttackingState : PlayerBaseState
{
private float previousFrameTime;
private bool alreadAppliedForce;
private Attack attack;
private Attack heavyAttack;
public PlayerAttackingState(PlayerStateMachine stateMachine, int attackIndex) : base(stateMachine)
{
attack = stateMachine.Attacks[attackIndex];
heavyAttack = stateMachine.HeavyAttacks[attackIndex];
}
public override void Enter()
{
stateMachine.InputReader.LightAttackDown += OnLightAttackDown;
stateMachine.InputReader.HeavyAttackDown += OnHeavyAttackDown;
stateMachine.Weapon.SetAttack(attack.Damage);
stateMachine.Weapon.SetAttack(heavyAttack.Damage);
stateMachine.Animator.CrossFadeInFixedTime(attack.AnimationName, attack.TransitionDuration);
stateMachine.Animator.CrossFadeInFixedTime(heavyAttack.AnimationName, heavyAttack.TransitionDuration);
}
public override void Tick(float deltaTime)
{
Move(deltaTime);
FaceTarget();
float normalizedTime = GetNormalizedTime();
if(normalizedTime < 1f)
{
if(normalizedTime >= attack.ForceTime)
{
TryApplyForce();
}
}
else
{
if(stateMachine.Targeter.CurrentTarget != null)
{
stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}
else
{
stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
}
}
previousFrameTime = normalizedTime;
}
public override void Exit()
{
stateMachine.InputReader.LightAttackDown -= OnLightAttackDown;
stateMachine.InputReader.HeavyAttackDown -= OnHeavyAttackDown;
}
private float GetNormalizedTime()
{
AnimatorStateInfo currentInfo = stateMachine.Animator.GetCurrentAnimatorStateInfo(0);
AnimatorStateInfo nextInfo = stateMachine.Animator.GetNextAnimatorStateInfo(0);
if(stateMachine.Animator.IsInTransition(0) && nextInfo.IsTag("Attack"))
{
return nextInfo.normalizedTime;
}
else if(!stateMachine.Animator.IsInTransition(0) && currentInfo.IsTag("Attack"))
{
return currentInfo.normalizedTime;
}
else
{
return 0f;
}
}
private void TryComboAttack(float normalizedTime)
{
if(attack.ComboStateIndex == -1) {return;}
if (normalizedTime < attack.ComboAttackTime) {return;}
stateMachine.SwitchState
(
new PlayerAttackingState
(
stateMachine,
attack.ComboStateIndex
)
);
}
private void TryApplyForce()
{
if(alreadAppliedForce) { return; }
stateMachine.ForceReceiver.AddForce(stateMachine.transform.forward * attack.Force);
alreadAppliedForce = true;
}
private void OnLightAttackDown()
{
}
private void OnHeavyAttackDown()
{
}
}