cjddmut / Unity-2D-Platformer-Controller

A customizable 2D platformer motor that handles mechanics such as double jumps, wall jumps, and corner grabs. Includes a player controlled prefab that can be dropped into any scene for immediate support.
MIT License
873 stars 163 forks source link

Applying forces? #62

Open IsaiahByDayah opened 7 years ago

IsaiahByDayah commented 7 years ago

I'm trying to think of how you would properly apply forces to an object that has a motor (Imagine getting hit by an enemy and the player gets "knocked back"). I can figure out restricting input while in this "knockback" state, the question is what do i do with the motor?

Currently I try to disable the motor, set rigidbody2D to dynamic, addForce (impulse) and the character goes flying through the air as expected. However the issue comes with landing/hitting something. In OnCollisionEnter2D (if you hit something in the staticLayerMask) I set the rigidbody2D back to kinematic, re-enable the motor, but "gravity" doesn't kick back in (or maybe the motor in general isnt really turning back on?) and an object may continue to go scaling up a wall or clip though surrounding colliders. Even if I set the rigidbody2D's velocity to zero before re-enabling the motor I feel as though it's maybe an issue with the state of the motor.

I'm willing to try and fix it but I'm not sure where to even begin to see where the issue might be :/

IsaiahByDayah commented 7 years ago

After looking at the code it imagine the solution may be as simple as doing the motor collision logic on enable but I have no idea where exactly that logic is done and how to best call it in the OnEnable function

IsaiahByDayah commented 7 years ago

Maybe state should be falling by default as well on enable?

IsaiahByDayah commented 7 years ago

So i seem to have a decent enough fix for now (not sure if its right though).

I added a call to UpdateState(true) at the very end of OnEnable().

private void OnEnable()
{
    if (_rigidbody2D != null)
    {
        _velocity = _rigidbody2D.velocity;
        _originalKinematic = _rigidbody2D.isKinematic;
        _rigidbody2D.isKinematic = true;
    }

    // Force state check on enable
    UpdateState (true);
}

Then when I want to apply forces to something with a motor this is the process I go through

// Throw the character
void Throw(Vector2 dir, float force) {
    wasThrown = true; // Set wasThrown flag
     _motor.enabled = false; // disable motor
    _rb2d.isKinematic = false; // set rigidbody2D to be dynamic
    _rb2d.AddForce(dir.normalized * force, ForceMode2D.Impulse); // Apply force
}

// Thing goes flying as expected

// Setup collision listener for after being thrown
void OnCollisionEnter2D(Collision2D collision) {
    if (wasThrown) { // Make sure character is in "thrown" state
wasThrown = false; // reset flag
bool hitStaticEnv = _motor.staticEnvLayerMask == (_motor.staticEnvLayerMask | (1 << collision.gameObject.layer)); // See if hit static env
        bool hitMovingPlatform = _motor.movingPlatformLayerMask == (_motor.movingPlatformLayerMask | (1 << collision.gameObject.layer)); see if hit moving platform
        if (hitStaticEnv  || hitMovingPlatform) { i// if hit either
            print ("Hit static env or moving platform");
            _rb2d.isKinematic = true; // Turn rb2d back to be kinematic
            _rb2d.velocity = Vector2.zero; // zero out velocity
            _motor.enabled = true; // re-enable motor which calls UpdateState(true)
        }
    }
}

Haven't thoroughly tested it or anything but this seems to b good enough for the time being. If you know of a better way please don't hesitate to let me know! Can update with more info once if I run into any problems

Also im unsure if changing OnEnable was smart or if it would have been better to just expose the UpdateState(bool) function and call it deliberately ¯_(ツ)_/¯

IsaiahByDayah commented 7 years ago

Also not that I gave the rigidbody2D a PhysicsMaterial2D of 100% bouncey and 0% friction. This seems to fix the clipping into walls issue when you "throw" the character into a wall or something. So far so good

shohan4556 commented 7 years ago

Hello there I also implemented a knockback method when collide with enemy tagged gameobject.

cjddmut commented 7 years ago

The motor was designed to be allowed to be enabled/disabled so you could allow physics to take over control at point. If it's not working in some instances then that would be considered a bug.

IsaiahByDayah commented 7 years ago

@cjddmut so are you saying that the way i did things is a good approach? Its not that I can't disable/enable the motor, its more how best to do it I guess

twomack33 commented 7 years ago

@cjddmut This controller is awesome! You really should think about adding just a few more features (like knockback) and selling it on the Asset Store.

@jordankid93 : What are your settings on the rigidbody? My character flies off the screen with just 1f of force. Thanks for the tip though!

IsaiahByDayah commented 7 years ago

Are you applying force as an impulse? If you look above I mention that's what I do cause I think doing regular force adds up too quickly. Also you could just adjust the mass of your rigidbody

twomack33 commented 7 years ago

@jordankid93 Found my issue, in the engine's disable function I was assigning the velocity of the engine to the velocity of the Rigidbidy2D. This made things bad :) Thanks for sharing the code you did, it works pretty well now! I love this engine, I have tried a ton of them and this one feels just right. I cam glad to see people sharing modifications they have made to the great base!

IsaiahByDayah commented 7 years ago

@twomack33 nice! Glad you were able to figure it out. And yeah, not that my modifications are great haha, but it gets the job done for sure