Hello! I bought the third person controller recently, I love it but it has a big learning curve which is fine! I'm having some issues implementing a stealth kill ability. I'd like to start the ability when spherecasting to an unaware enemy (see code below for ability script) which works fine but I'm getting very inconsistent results. Sometimes the player's kill animation just doesn't play, also sometimes it does play but doesn't position behind the enemy, sometimes the player's and enemy's animations don't sync and when crouching it doesn't transition to the kill animation even though the kill is from any state. Also what would be the best way to smoothly lerp behind the enemy too instead of just teleporting there?
Here is the ability parameters
Here are the animator state transitions
Is there any visible reason why I'd be getting these random inconsistent results?
I'm not the best coder and this may be the wrong way to use the controller so happy to hear suggestions on how to use it better!
Stealth Kill Ability Script
Here is the ability parameters
Here are the animator state transitions
Is there any visible reason why I'd be getting these random inconsistent results?
I'm not the best coder and this may be the wrong way to use the controller so happy to hear suggestions on how to use it better!
Stealth Kill Ability Script
Code:
public class StealthKill : Ability
{
// Used to get normalized time of the animation playing.
[SerializeField] private Animator animator;
// Cannot exit the animation before this normalized time.
[SerializeField] private float minimumPlayoutTime = 0.8f;
private EnemyStateMachine enemy;
private bool havePositioned = false;
public override bool CanStartAbility()
{
if (CanStealthKill())
{
return true;
}
return false;
}
protected override void AbilityStarted()
{
base.AbilityStarted();
// Received in the enemy state machine class, checks for enemy instance.
EventHandler.ExecuteEvent(enemy, "StelthKill");
}
public override void UpdatePosition()
{
// After positioning behind the enemy, continue with moving with root motion.
if (!havePositioned)
{
Vector3 newPos = enemy.transform.position + (enemy.transform.forward * -0.4f);
m_CharacterLocomotion.SetPositionAndRotation(newPos, enemy.transform.rotation);
havePositioned = true;
}
base.UpdatePosition();
}
// Ability checks every frame to see if it can be stopped. if the animation time is more than the playout time, we can stop.
public override bool CanStopAbility(bool force)
{
AnimatorStateInfo currentInfo = animator.GetCurrentAnimatorStateInfo(0);
AnimatorStateInfo nextInfo = animator.GetNextAnimatorStateInfo(0);
if (animator.IsInTransition(0))
{
return nextInfo.normalizedTime > minimumPlayoutTime;
}
else if (!animator.IsInTransition(0))
{
return currentInfo.normalizedTime > minimumPlayoutTime;
}
return false;
}
protected override void AbilityStopped(bool force)
{
base.AbilityStopped(force);
}
// Checks for an unaware enemy in front of the player.
private bool CanStealthKill()
{
Ray ray = new Ray(m_Transform.position + new Vector3(0, 1, 0), m_Transform.forward);
Debug.DrawRay(ray.origin, ray.direction, Color.yellow, 1f);
if (Physics.SphereCast(ray.origin, 0.5f, ray.direction, out RaycastHit hit, 1))
{
enemy = hit.transform.GetComponent<EnemyStateMachine>();
if (enemy != null && !enemy.IsAlarmed)
{
return true;
}
return false;
}
return false;
}
}