Forces don't apply

Hello, I am having an issue with the application of forces upon my player character. Both the PlayerAttackState.TryApplyForce() and ForceReceiver.AddForce(Vector3 force) are being called at the appropriate times, I have verified this with debug logs, but no forces are being applied to my character.
I have set up the fields in the inspector, I receive no errors, but even when I crank the numbers up to 1000, nothing happens.
Edit:
Actually after further testing, it seems it is being applied but like WAY late… after all three animations have completed and the character is back at Idle.

My attack state

public class PlayerAttackState : PlayerBaseState
{
    bool alreadyAppliedForce;
    Attack attack;
    float previousFrameTime;
    public PlayerAttackState(PlayerStateMachine stateMachine, int attackIndex) : base(stateMachine)
    {
        attack = stateMachine.Attacks[attackIndex];
    }

    public override void Enter()
    {
        stateMachine.Animator.CrossFadeInFixedTime(attack.AnimationName, attack.TransitionDuration);
    }
    public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        FaceTarget();
        float normalizedTime = GetNormalizedTime();
        if (normalizedTime > previousFrameTime && normalizedTime < 1)
        {
            if(stateMachine.InputReader.isAttacking)
            {
                if (normalizedTime >= attack.ForceTime)
                {
                    TryApplyForce();
                }
                TryComboAttack(normalizedTime);
                
            }
        }
        else
        {
            //go back to prvious locomotion state
        }
    }

    private void TryComboAttack(float normalizedTime)
    {
        if (attack.ComboStateIndex == -1) 
        { 
            return;
        }
        if (normalizedTime < attack.ComboAttackTime) { return; }
        

        stateMachine.SwitchState(new PlayerAttackState(stateMachine, attack.ComboStateIndex));
    }
    private void TryApplyForce()
    {
        
        if (alreadyAppliedForce) return;
        Debug.Log("Attack applying force");
        stateMachine.ForceReciever.AddForce(stateMachine.transform.forward * attack.Force);
        alreadyAppliedForce = true;
    }
    public override void Exit()
    {
       
    }

    private float GetNormalizedTime()
    {
        AnimatorStateInfo currentStateInfo = stateMachine.Animator.GetCurrentAnimatorStateInfo(0);
        AnimatorStateInfo nextStateInfo = stateMachine.Animator.GetNextAnimatorStateInfo(0);
        if (stateMachine.Animator.IsInTransition(0) && nextStateInfo.IsTag("Attack"))
        {
            return nextStateInfo.normalizedTime;
        }
        else if (!stateMachine.Animator.IsInTransition(0) && currentStateInfo.IsTag("Attack"))
        {
            return currentStateInfo.normalizedTime;
        }
        else 
        {
            return 0;
        }
    }

}

my Force Receiver

public class ForceReciever : MonoBehaviour
{
    //Customizable Parameters:
    [Title("Force Reciever", "Playing with physics...", TitleAlignments.Centered),BoxGroup("Force Receiver", centerLabel:true),SerializeField] 
    CharacterController controller;
    [BoxGroup("Force Receiver"),SerializeField] float drag = 0.3f;

    //Private fields:
    private float verticalVelocity;
    private Vector3 impactForce;
    private Vector3 dampingVelocity;

    //Public Properties:
    public Vector3 movement => impactForce + Vector3.up * verticalVelocity;


    private void Update()
    {
        if(verticalVelocity < 0f && controller.isGrounded)
        {
            verticalVelocity = Physics.gravity.y * Time.deltaTime;
        }
        else
        {
            verticalVelocity += Physics.gravity.y * Time.deltaTime;
        }
        impactForce = Vector3.SmoothDamp(impactForce, Vector3.zero, ref dampingVelocity, drag);
    }

    public void AddForce(Vector3 force)
    {
        Debug.Log("Reciever - Adding Force");
        impactForce += force;
    }
}

I’m guessing your animations are animating the absolute position values as opposed to animating the relative position values to the gameObject with the rigidbody. If that’s the case, you’re essentially overriding the physics with your animations.

The code looks correct.

Can you also paste in your Move() method from PlayerBaseState()?

Sure thing!

public abstract class PlayerBaseState : State
{
    protected PlayerStateMachine stateMachine;

    public PlayerBaseState(PlayerStateMachine stateMachine)
    {
        this.stateMachine = stateMachine;
    }

    protected void Move(float deltaTime)
    {
        Move(Vector3.zero, 0, deltaTime);

    }

    protected void Move(Vector3 motion, float movementSpeed, float deltaTime)
    {
        Vector3 movement = motion + stateMachine.ForceReciever.movement;


        stateMachine.Controller.Move(movement * movementSpeed * deltaTime);
    }

    protected void FaceTarget()
    {
        if (!stateMachine.Targeter.CurrentTarget) return;

        Vector3 lookDir = stateMachine.Targeter.CurrentTarget.transform.position - stateMachine.transform.position;

        lookDir.y = 0f;

        stateMachine.transform.rotation = Quaternion.LookRotation(lookDir);   
    }

  
}

It’s starting to look like @MichaelP is on the right track for this one. If you want to zip up your project and upload it to https://gdev.tv/projectupload I’ll take a look and confirm (or rule it out and hopefully find the issue). Be sure to remove the Library folder from the zip to conserve space.

Unfortunately, I’m working in an existing Project that is already pretty big, and to be perfectly honest this seem pretty small at the moment, and I don’t want to take the time to extract the part of the project I’m talking about. I appreciate it though, and If I cant figure it out, or get it to my liking, I may hit you up! Thanks!

Me too i have the same problem i used diffrenet animations but i dont know how to fix it

The fix is to animate it relative to the base game object, not absolute space.

i dont understand … i bought animation from asset store and im using it now … i didn’t understand what do u mean with animate it relative or to absolute space

I’ll try to explain.

Say you’ve got an object in a scene and you move its transform.position, you’re moving it in the full world of 3d space. When you have a child object, you have an option to move it relative to the parent object.

So say you’re animating an object to move to position 1,1,1 in world space (not absolute, don’t ask me why I said absolute) it’ll move to 1,1,1 full stop. If you’re animating it to move say between 1,1,1 and 2,2,2, it’ll move in absolute space. Any kind of gravity/movement of the parent object would be overridden with the animation telling it to go to a particular position.

A lot of the time, people animate the position in world space as opposed to relative position to an object and get a result they didn’t expect.

Does that make sense?

I have a (totally unqualified because I haven’t done the course yet) comment.

The attack state is calling an overloaded Move that in turn supplies a motion of Vector3.zero and a movementSpeed of 0. This, multiplied by whatever force is currently being applied, results in no movement - or Vector3.zero. After this, it tries to apply more force which, on next update, will result in more movement of Vector3.zero.

I will have to look at the videos and code to see if this is intended, but from my unblemished eyes it doesn’t look right.


Edit
I had a look at the code in the repo.
The code looks different. There is no movementSpeed in the repo

    protected void Move(float deltaTime)
    {
        Move(Vector3.zero, deltaTime);
    }

    protected void Move(Vector3 motion, float deltaTime)
    {
        stateMachine.Controller.Move((motion + stateMachine.ForceReceiver.Movement) * deltaTime);
    }

I suspect the code was refactored to have the movementSpeed passed in as opposed to it being calculated outside the function. If that’s the case, the calculation inside is wrong.

From what I can see, the usage in the repo is
((motion * speed) + force) * deltaTime
In this case, if speed == 0, the result will still be whatever force is applied (multiplied by deltaTime)

But what the posted code does is
(motion + force) * speed * deltaTime
Here, if speed == 0, the result will always be Vector3.zero

1 Like

I’ll try correcting for this! Thanks for the insight. I actually came back to this because the application of the forces works on Impact, so I knew something in my code had to be incorrect.
And, You are correct, I misunderstood the instruction and thought we were passing in the movement speed of the current state, and since I have a FreeRunState, and a FreeWalkState, I was trying to pass in the correct movement speed. Thank you for catching this! I’ll let you know if it works!

This was it!!! Thank you!
I did a slight refactor, and it fixed my issue!

    protected void Move(Vector3 motion, float movementSpeed, float deltaTime)
    {
        Vector3 movement = motion * movementSpeed;


        stateMachine.Controller.Move((movement + stateMachine.ForceReciever.movement) * deltaTime);
    }
3 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms