Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collision issues when character collides with corner of platform #6

Closed
RyanNielson opened this issue Dec 21, 2013 · 16 comments
Closed

Comments

@RyanNielson
Copy link

I have the CharacterController2D script on a character. In my test level I have some 2d colliders that are set as the ground. If I jump diagonally into a corner of the collider with my character, my character clips through the platform like in the picture attached. I'm assuming this is because rays are sent out vertically and horizontally, and I'm hitting right on my character's corner.

Blue block on the right jumped and corner hit the platformer, causing him to clip through and get stuck within the platform.
capture

@RyanNielson
Copy link
Author

@prime31 Tagging you in case you aren't watching the repo. Have any good solutions to this one? Kinda makes it a no go for me in the game I'm working on.

@prime31
Copy link
Owner

prime31 commented Dec 21, 2013

If you up your horizontal and vertical ray count it should remedy that.
Just play around with the numbers to get the right amount. Once Unity gets
us proper sweep tests (hopefully in 4.4) this will be handled without the
extra rays.

Mike

On Fri, Dec 20, 2013 at 8:18 PM, Ryan Nielson notifications@github.comwrote:

@prime31 https://github.com/prime31 Tagging you in case you aren't
watching the repo. Have any good solutions to this one? Kinda makes it a no
go for me in the game I'm working on.


Reply to this email directly or view it on GitHubhttps://github.com//issues/6#issuecomment-31056444
.

@RyanNielson
Copy link
Author

Ya, I upped it to 20 horizontal and 20 vertical rays and I can still produce it consistently. Bummer.

@prime31
Copy link
Owner

prime31 commented Dec 21, 2013

One other quicky solution you can do is add a diagonal ray check in the
directly of movement before the horizontal and vertical ones. That should
catch the edge cases.

Mike

On Fri, Dec 20, 2013 at 8:32 PM, Ryan Nielson notifications@github.comwrote:

Ya, I upped it to 20 horizontal and 20 vertical rays and I can still
produce it consistently. Bummer.


Reply to this email directly or view it on GitHubhttps://github.com//issues/6#issuecomment-31056609
.

@RyanNielson
Copy link
Author

Ya, I'll have to give that a go and see how it works. Thanks.

@prime31
Copy link
Owner

prime31 commented Dec 23, 2013

Do you happen to have a simple repro project you can send my way? If so, send it over to mike (at) prime31.com

@RyanNielson
Copy link
Author

I can try to set something up this evening and send it your way. —
Sent from Mailbox for iPhone

On Mon, Dec 23, 2013 at 2:02 PM, Mike notifications@github.com wrote:

Do you happen to have a simple repro project you can send my way? If so, send it over to mike (at) prime31.com

Reply to this email directly or view it on GitHub:
#6 (comment)

@RyanNielson
Copy link
Author

@prime31 Sent, hopefully you can repro it and find a decent solution.

@prime31
Copy link
Owner

prime31 commented Dec 24, 2013

So, a quick and dirty fix for the issue until we get some more Physics2D methods exposed by Unity is to just add the following method to the CharacterController2D class:

private void performDiagonalChecks( ref Vector3 deltaMovement )
{
    Vector2 ray;

    // figure out which ray origin to use based on movement direction
    if( deltaMovement.x > 0 && deltaMovement.y > 0 )
        ray = new Vector2( _raycastOrigins.topRight.x, _raycastOrigins.topRight.y );
    else if( deltaMovement.x > 0 && deltaMovement.y < 0 )
        ray = new Vector2( _raycastOrigins.bottomRight.x, _raycastOrigins.bottomRight.y );
    else if( deltaMovement.x < 0 && deltaMovement.y > 0 )
        ray = new Vector2( _raycastOrigins.topLeft.x, _raycastOrigins.topLeft.y );
    else
        ray = new Vector2( _raycastOrigins.bottomLeft.x, _raycastOrigins.bottomLeft.y );

    DrawRay( ray, new Vector3( ray.x, ray.y, 0 ) + deltaMovement, Color.white );
    _raycastHit = Physics2D.Raycast( ray, deltaMovement, deltaMovement.magnitude, platformMask & ~oneWayPlatformMask );
    if( _raycastHit )
    {
        deltaMovement.x = _raycastHit.point.x - ray.x;
        deltaMovement.y = _raycastHit.point.y - ray.y;
    }
}

Then add the 2 lines in the screenshot below to the move method.

screen shot 2013-12-24 at 9 25 56 am

@RyanNielson
Copy link
Author

Awesome, thanks! Seems to get rid of the clipping issue. Only problem that exists because of this code, is when my character jumps while moving left or right into a wall he doesn't jump the normal height.

You can repro this by holding the left key when you're touching a wall, and jumping.

@prime31
Copy link
Owner

prime31 commented Dec 24, 2013

Aha. Good point. An extra check will be needed in there to account for when moving left/right while already having a collision on the left/right. In those cases the diagonal check should be skipped.

Mike

On Tue, Dec 24, 2013 at 9:45 AM, Ryan Nielson notifications@github.com
wrote:

Awesome, thanks! Seems to get rid of the clipping issue. Only problem that exists because of this code, is when my character jumps while moving left or right into a wall he doesn't jump the normal height.

You can repro this by holding the left key when you're touching a wall, and jumping.

Reply to this email directly or view it on GitHub:
#6 (comment)

@savethejets
Copy link

Just for anyone else, I was having trouble getting prime31's last fix comment to work. I think I have it working so here is the code that I modified if it helps anyone...

    public void move( Vector3 deltaMovement )
    {
        // save off our current grounded state
        var wasGroundedBeforeMoving = collisionState.below;
        var wasCollidingLeftOrRight = collisionState.left || collisionState.right;

        // clear our state
        collisionState.reset();

        var desiredPosition = transform.position + deltaMovement;
        primeRaycastOrigins( desiredPosition, deltaMovement );

        // first we check movement in the horizontal dir
        if( deltaMovement.x != 0 )
            moveHorizontally( ref deltaMovement );

        // next, check movement in the vertical dir
        if( deltaMovement.y != 0 )
            moveVertically( ref deltaMovement );

        if( deltaMovement.x != 0 && deltaMovement.y != 0 && !wasCollidingLeftOrRight)
            performDiagonalChecks( ref deltaMovement );


        // move then update our state
        if( usePhysicsForMovement )
        {
            rigidbody2D.velocity = deltaMovement / Time.fixedDeltaTime;
            velocity = rigidbody2D.velocity;
        } 
        else 
        {
            transform.Translate( deltaMovement );
            velocity = deltaMovement / Time.deltaTime;
        }

        // set our becameGrounded state based on the previous and current collision state
        if (!wasGroundedBeforeMoving && collisionState.below) {
            collisionState.becameGroundedThisFrame = true;          
        }
    }

@prime31
Copy link
Owner

prime31 commented Mar 4, 2014

Just in case you havent seen it yet, I believe the latest commit should avoid any and all issues with corner penetration: b6fc72f

@prime31 prime31 closed this as completed Mar 4, 2014
@RyanNielson
Copy link
Author

@prime31 Oh neat, thanks for the update. I'll have to take a look at it again.

@savethejets
Copy link

I dug into this more since I was still getting this issue...

If you're using Tk2dTilemaps, the way Tk2d creates the physics colliders is by creating a bunch of edge colliders.

Unfortunately if the CharacterController falls in between the edge colliders there is no "volume" to speak of and the ray casts will treat the inside of the edge as the ground.

I would say this is actually a flaw with tk2d and not with the CharacterController.

Another way would be for tk2d to use polygon or box colliders instead. But looking on the tk2d forums it seems like the author is against that for performance reasons. Any thoughts on a way to prevent this with our ray casts?

@prime31
Copy link
Owner

prime31 commented Jan 30, 2015

Perhaps doing a diagonal raycast from the forward corner's position before movement to its position after movement would do the trick.

Mike

On Jan 29, 2015, at 10:53 PM, Kyle Reczek notifications@github.com wrote:

I dug into this more since I was still getting this issue...

If you're using Tk2dTilemaps the way Tk2d creates the physics colliders is by creating a bunch of edge colliders.

Unfortunately if the CharacterController falls in between the edge colliders there is no "volume" to speak of and the ray casts will treat the inside of the edge as the ground.

I would say this is actually a flaw with tk2d and not with the CharacterController.

Any thoughts on a way to prevent this with our ray casts? Another way would be for tk2d to use polygon or box colliders instead...


Reply to this email directly or view it on GitHub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants