GarageGames / Torque2D

MIT Licensed Open Source version of Torque 2D game engine from GarageGames
MIT License
1.67k stars 1.56k forks source link

Normals of collision shapes appear to be inverse when created after player object added to scene #403

Closed Mpskydog closed 6 years ago

Mpskydog commented 6 years ago

When working in the sandbox toys, or in modules of my own, collision normals appear to be getting inverted depending on the sequence of adding objects to a scene. Tested it through a variety of Torque development builds but the behavior has remained consistent and I have been unable to determine if it is something I am doing or not.

I create some basic platforms as such:

function PlatformerDemo::createPlatformBlock(%this, %posX, %posY, %sizeX, %sizeY)
{
    %posZ = 0;
    %object = SandboxScene.create( Sprite );
    %object.Size.x = %sizeX;
    %object.Size.y = %sizeY;
    %object.setBodyType("static"); // Platforms float, so we don't want them effected by gravity
    %object.Position = %posX SPC %posY SPC %posZ;
    %object.Image = "ToyAssets:Tiles";
    // Create some collision shapes.    
    %object.createPolygonBoxCollisionShape(%sizeX,%sizeY);
    %object.setSceneLayer(10);
    return %object;
}

When a player collides with the object, I check to see if its the top of a platform or block. If so, I turn off gravity on the player object and set a variable denoting that it is on the ground:

function Player::onCollision(%this, %colide, %details)
{
    %normal = getWord(%details, 2) SPC getWord(%details, 3);
    // Adjust our normal by rounding up a little
    %word0 = getWord(%normal, 0);
    %word1 = getWord(%normal, 1);
    %word0 = mFloatLength(%word0, 2);
    %word1 = mFloatLength(%word1, 2);
    %normal = mFloatLength(%word0, 4) SPC mFloatLength(%word1, 4);
    if (%normal $= "-0.0000 1.0000" || %normal $= "0.0000 1.0000")       // Haven't checked this recently, may be a result of my rounding, but sometimes the normal returns with a -0.0000 value on the first word so I try to account for both here
        {
        %this.onGround = true;
        %this.setGravityScale(0); // turn off gravity while we're grounded
        }
}

If the blocks are added to the scene before the player object, everything functions as expected. If the blocks are added after the player is added to the scene, those blocks act as if their normals were reversed: Landing on the top of the block keeps gravity on and treats the player like they are falling in the air. Touching the underside of the block, turns gravity off as if the player landed on the top of the block, and the player will be able to hang in the air and can run back and forth under the edge of the platform.

Currently I've worked around this by setting a flag on any blocks created when the player object already exists, and checking that flag on collisions. If its true, I reverse the normals before comparing them for the collisions.

greenfire27 commented 6 years ago

This is an interesting bug. According to the documentation:

Both the contact normals and contact points come directly from Box2D itself and Torque 2D does not manipulate them in any way.

But I know that every contact generates two opposite normals, one for each object. It's possible that the engine is returning the wrong normal based on the order that the objects are created. I'll have to investigate further. Thanks for posting up the bug.

Mpskydog commented 6 years ago

No problem, thank you for working on this!

I have something of a development jam with a friend of mine coming up in January so I have been dusting off some of my Torque prototypes and testing them out in the latest builds. I first noticed it when I was testing one-sided collisions like two years ago, and had some custom C++ code so I thought perhaps it was some fault of mine. The player would drop down through those platforms created later, and bump against the underside. That's since been unnecessary after #238 when they added one-sided with edge collision shapes, so now I'm using the stock code and noticed it still happened on other collisions.

greenfire27 commented 6 years ago

I was right! In Scene.cc starting at line 555 we pass the same miscInfoBuffer into the callbacks for both objectA and objectB. We should be inverting the normal for objectB first. I'll get a fix in for it. Thanks again for pointing this out.

greenfire27 commented 6 years ago

Check to see if this has been fixed in the development branch.

Mpskydog commented 6 years ago

I'll take a look at this when I get tonight, thanks!

Mpskydog commented 6 years ago

So after some testing, it actually appears like everything is the opposite now: With my existing code, collisions against objects made before the playerObject appear to be inverted, and collisions against objects made after the playerObject are working normally. If I reverse the logic of my .inverseNormals variable, everything works as I would expect.

I'll try to gather some data from some of the other toys to make sure it isn't something I've done specifically in my platformer concept.


UPDATE: So I added a collision callback to the blocks in the Pyramid toy. Other than adding a class and a collision callback = true to PyramidToy::createPyramid(), and then a Block::onCollision function that just prints the collision details, everything else is stock module code.

When I run it on an earlier build of the Torque 2D development it says the collision normal for landing on the ground is -0.0000 1.0000. When I run it on the version you just updated, it passes me 0.0000 -1.0000. Other than that, everything seems the same. I can probably try to gather some actual data this week that can be examined/reproduced for testing in some stock toys.

greenfire27 commented 6 years ago

And does it still flip if you change the creation order of the ground and blocks?

I'll have to experiment with this further.

greenfire27 commented 6 years ago

The first try fell flat, but I took anther stab at this. Testing with the Pyramid Toy was successful. Try it out and let me know if it works for you.

Mpskydog commented 6 years ago

I didn't see any new commits?

greenfire27 commented 6 years ago

Ack! Forgot to sync...

Mpskydog commented 6 years ago

Boom! Appears that I am no longer getting any strange behavior with the normals, regardless of what order my collision shapes are created in! Bravo!

greenfire27 commented 6 years ago

Glad I could help! If you come across anything else just post it up. Hope your development jam goes well.