(Building off of Psyconius’s post)
I would also like to mandate my players click/press the attack button every time they wish to attack. Reading the previous post about this question, I tried to solve it using the available information. However (I don’t know if it’s because I’m new at C# and coding in general, or if its because I misinterpreted something), my code just doesn’t seem to want to work. Forgive me if it seems like I’m asking dumb questions but I’ve been hitting my head against the wall over this.
The two confusing parts for me were 1) when you said to subscribe and unsubscribe from the StateMachine.InputReader.OnAttack() in Enter and Exit and 2) when Psyconius described adding listeners to the FreeLook and Targeting states.
I’m having trouble seeing what these look like, even after Googling. Here’s what I have that Unity doesn’t like.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAttackingState : PlayerBaseState
{
private float previousFrameTime;
private bool alreadyAppliedForce;
private Attack attack;
public PlayerAttackingState(PlayerStateMachine stateMachine, int attackIndex) : base(stateMachine)
{
attack = stateMachine.Attacks[attackIndex];
}
public override void Enter()
{
stateMachine.InputReader.AttackDown += OnAttack;
stateMachine.Weapon.SetAttack(attack.Damage, attack.Knockback);
stateMachine.Animator.CrossFadeInFixedTime(attack.AnimationName, attack.TransitionDuration);
Debug.Log(attack.AnimationName);
}
public override void Tick(float deltaTime)
{
Move(deltaTime);
FaceTarget();
float normalizedTime = GetNormalizedTime(stateMachine.Animator, "Attack");
if(normalizedTime >= previousFrameTime && normalizedTime < 1f)
{
if (normalizedTime >= attack.ForceTime)
{
TryApplyForce();
}
/*if(stateMachine.InputReader.OnAttack)
{
TryComboAttack(normalizedTime);
}*/
}
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.AttackDown -= OnAttack;
}
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(alreadyAppliedForce) { return; }
stateMachine.ForceReceiver.AddForce(stateMachine.transform.forward * attack.Force);
alreadyAppliedForce = true;
}
void HandleAttackDown()
{
float normalizedTime = GetNormalizedTime(stateMachine.Animator, "Attack");
TryComboAttack(normalizedTime);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerFreeLookState : PlayerBaseState
{
private bool shouldFade;
private readonly int FreeLookBlendTreeHash = Animator.StringToHash("FreeLookBlendTree");
private readonly int FreeLookSpeedHash = Animator.StringToHash("FreeLookSpeed");
private const float AnimatorDampTime = 0.1f;
private const float CrossFadeDuration = 0.1f;
public PlayerFreeLookState(PlayerStateMachine stateMachine, bool shouldFade = true) : base(stateMachine)
{
this.shouldFade = shouldFade;
}
public override void Enter()
{
stateMachine.InputReader.TargetEvent += OnTarget;
stateMachine.InputReader.DodgeEvent += OnDodge;
stateMachine.InputReader.JumpEvent += OnJump;
stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0f);
if (shouldFade)
{
stateMachine.Animator.CrossFadeInFixedTime(FreeLookBlendTreeHash, CrossFadeDuration);
}
else
{
stateMachine.Animator.Play(FreeLookBlendTreeHash);
}
}
public override void Tick(float deltaTime)
{
Vector3 movement = CalculateMovement();
Move(movement * stateMachine.FreeLookMovementSpeed, deltaTime);
if(stateMachine.InputReader.OnAttack(AttackDown))
{
stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
return;
}
if(stateMachine.InputReader.IsBlocking)
{
stateMachine.SwitchState(new PlayerBlockingState(stateMachine));
return;
}
if (stateMachine.InputReader.MovementValue == Vector2.zero)
{
stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0, AnimatorDampTime, deltaTime);
return;
}
stateMachine.Animator.SetFloat(FreeLookSpeedHash, 1, AnimatorDampTime, deltaTime);
FaceMovementDirection(movement,deltaTime);
}
public override void Exit()
{
stateMachine.InputReader.TargetEvent -= OnTarget;
stateMachine.InputReader.DodgeEvent -= OnDodge;
stateMachine.InputReader.JumpEvent -= OnJump;
}
private void OnTarget()
{
if(!stateMachine.Targeter.SelectTarget()) { return; }
stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}
private void OnJump()
{
stateMachine.SwitchState(new PlayerJumpingState(stateMachine));
}
private void OnDodge()
{
if(stateMachine.InputReader.MovementValue == Vector2.zero) { return; }
stateMachine.SwitchState(new PlayerDodgingState(stateMachine, stateMachine.InputReader.MovementValue));
}
private Vector3 CalculateMovement()
{
Vector3 forward = stateMachine.MainCameraTransform.forward;
Vector3 right = stateMachine.MainCameraTransform.right;
forward.y = 0f;
right.y = 0f;
forward.Normalize();
right.Normalize();
return forward * stateMachine.InputReader.MovementValue.y + right * stateMachine.InputReader.MovementValue.x;
}
private void FaceMovementDirection(Vector3 movement, float deltaTime)
{
stateMachine.transform.rotation = Quaternion.Lerp(
stateMachine.transform.rotation,
Quaternion.LookRotation(movement),
deltaTime * stateMachine.RotationDamping);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerTargetingState : PlayerBaseState
{
private readonly int TargetingBlendTreeHash = Animator.StringToHash("TargetingBlendTree");
private readonly int TargetingForwardSpeedHash = Animator.StringToHash("TargetingForwardSpeed");
private readonly int TargetingRightSpeedHash = Animator.StringToHash("TargetingRightSpeed");
private const float CrossFadeDuration = 0.1f;
public PlayerTargetingState(PlayerStateMachine stateMachine) : base(stateMachine) { }
public override void Enter()
{
stateMachine.InputReader.TargetEvent += OnTarget;
stateMachine.InputReader.DodgeEvent += OnDodge;
stateMachine.InputReader.JumpEvent += OnJump;
stateMachine.Animator.CrossFadeInFixedTime(TargetingBlendTreeHash, CrossFadeDuration);
}
public override void Tick(float deltaTime)
{
if(stateMachine.InputReader.OnAttack(AttackDown))
{
stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
return;
}
if(stateMachine.InputReader.IsBlocking)
{
stateMachine.SwitchState(new PlayerBlockingState(stateMachine));
return;
}
if(stateMachine.Targeter.CurrentTarget == null)
{
stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
return;
}
Vector3 movement = CalculateMovement(deltaTime);
Move(movement * stateMachine.TargetingMovementSpeed, deltaTime);
UpdateAnimator(deltaTime);
FaceTarget();
}
public override void Exit()
{
stateMachine.InputReader.TargetEvent -= OnTarget;
stateMachine.InputReader.DodgeEvent -= OnDodge;
stateMachine.InputReader.JumpEvent -= OnJump;
}
private void OnTarget()
{
stateMachine.Targeter.Cancel();
stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
}
private void OnDodge()
{
if(stateMachine.InputReader.MovementValue == Vector2.zero) { return; }
stateMachine.SwitchState(new PlayerDodgingState(stateMachine, stateMachine.InputReader.MovementValue));
}
private void OnJump()
{
stateMachine.SwitchState(new PlayerJumpingState(stateMachine));
}
private Vector3 CalculateMovement(float deltaTime)
{
Vector3 movement = new Vector3();
movement += stateMachine.transform.right * stateMachine.InputReader.MovementValue.x;
movement += stateMachine.transform.forward * stateMachine.InputReader.MovementValue.y;
return movement;
}
private void UpdateAnimator(float deltaTime)
{
if(stateMachine.InputReader.MovementValue.y == 0)
{
stateMachine.Animator.SetFloat(TargetingForwardSpeedHash, 0, 0.1f, deltaTime);
}
else
{
float value = stateMachine.InputReader.MovementValue.y > 0 ? 1f : -1f;
stateMachine.Animator.SetFloat(TargetingForwardSpeedHash, value, 0.1f, deltaTime);
}
if(stateMachine.InputReader.MovementValue.x == 0)
{
stateMachine.Animator.SetFloat(TargetingRightSpeedHash, 0, 0.1f, deltaTime);
}
else
{
float value = stateMachine.InputReader.MovementValue.x > 0 ? 1f : -1f;
stateMachine.Animator.SetFloat(TargetingRightSpeedHash, value, 0.1f, deltaTime);
}
}
}