0
\$\begingroup\$

Our team is creating a 3rd person adventure platformer in Unreal 4.22. One of the mechanics is a grappling hook. Think less-so a 'pull-to-point' grappling hook (Widowmaker, Just cause etc.). However more an actual physical simulation (Closer to that of a pendulum kinematics simulation).

Of course, my task is creating this grappling hook mechanic.


My Approach

I didn't see any way of approaching this that wasn't with vector math, so I went with that.

I created a derivative of the CharacterMovementComponent written by Unreal, and started working with this to attempt to recreate this physical simulation.

Initially, I attempted to create my own PhysCustom implementation. However after a month of development and no results, I switched my direction of attack.

I found, by chance, that Unreal allows you to add force to the CharacterMovementComponent, not to the character themselves, as I had previously thought.

My approach right now can be summed up as follows:

  • Allow the character to be in their MOVE_Falling state (as provided by unreal)

  • Perform all of the force applications in TickComponent


TickComponent

void UPlatformerMovementComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction * ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    // perform tick taught length update if required.
    if (m_bUpdateTaughtDistanceEveryFrame) { UpdateTaughtDistance(); }

    /* If the movement mode is falling and the player is attached to a point: 
       - Apply forces to the player                 */
    float remainder = 0.f;
    if (MovementMode == EMovementMode::MOVE_Falling && m_OwnerGrappleHook_Ref->IsAttached()) {

        // If the rope is taught.Apply a force to the player to keep them at the grapple.
        if (PlayerIsAtOrPastTaughtLength(&remainder)) {

            if (m_bWantsInitialSwingVelChange) {
                //Ver 2 - Used.
                float velSize = Velocity.Size();
                FVector ToGrapple = GetVectorToPoint(); ToGrapple.Normalize();
                Velocity += ToGrapple * velSize;

                m_bWantsInitialSwingVelChange = false;
            }

            FVector Force = GetVectorToPoint() * 980.f;

            AddForce(Force * 2.f);

        }
        // If the rope is not taught, then decay the velocity to prevent bouncing.
        else {
            Velocity *= 0.97f;
        }
    }
}

Some code explanation

remainder and bool PlayerIsAtOrPastTaughtLength(float *)

  • remainder is used to store the distance past the m_TaughtDistance from the grapple point that the player lies at.

  • bool PlayerIsAtOrPastTaughtLength(float *) returns whether the player is past this m_TaughtDistance or not, and places the amount in the float* if true.

m_TaughtDistance

  • The theoretical distance from the grapple point which would reach the radius of the grapple point's 'influence' sphere.

m_OwnerGrappleHook_Ref

  • A reference to the GrappleHookComp object that works with the MovementComponent

GrappleHookComp

  • An object that stores and deals with most of the grapple hook variables, functions and states.

m_bWantsInitialSwingVelChange

  • a Bool that is set to true when initially attaching to a point.

  • Causes a velocity change by adding the same size vector as the player's velocity towards the grapple point.


The problem

This causes a jitter at the bottom of the radius of the circle. Where the player never comes to rest at the m_TaughtDistance point below the grapple point.

Am I missing something in my force applications?

Am I approaching this wrong?

Any help would be appreciated.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.