Box2d one way platform/door

jimjim
edited September 2013 in General discussions
Hey everyone,

I started to look into Scroll with help of Acksys tutorial, I must say, Scroll makes learning orx a breeze. Now to my question, the other day I was searching how to implement one way platform in box2d, as we see many kind of one way stuffs in most of the platformer games. And I found a couple of solution, but they are not possible with default box2d behavior in orx.

1. The first method I have found uses box2d contact event Pre-Solve. In Pre-Solve, you check if your desired objects are collided, for example, if player and floating platform are colliding, then just call the following line, this would disable collision response for current contact.
contact->SetEnabled(false);
From box2d manual regarding pre-solve,
This gives you a chance to disable the contact based on the current configuration. For example, you can implement a one-sided platform using this callback and calling b2Contact::SetEnabled(false).
The contact will be re-enabled each time through collision processing, so you will need to disable the contact every time-step. The pre-solve event may be fired multiple times per time step per contact due to continuous collision detection.
I have checked orx source, Pre-Solve and Post-Solve are not implemented, even if they are added there is no way to access box2d b2Contact data afaik.

2. Another solution I have found, does not require pre-solve, but this requires a simple change in core box2d source, the link is http://www.iforce2d.net/b2dtut/one-way-walls
Here, they commented this in b2Contact.cpp, this prevents re-enabling the contact.
//m_flags |= e_enabledFlag;
Then in BeginContact() disable contact, this would now work because box2d is not re-enabling collision for this contact in each step.
contact->SetEnabled(false);
But have to make sure that in EndContact(), collision for this contact is re-enabled, by calling this
contact->SetEnabled(true);
Second solution seems easier, and must be less expensive than the first one. But I don't see anyway to access the box2d contact data, as orx physics contact are custom listener.

Comments

  • edited September 2013
    And yet, one of the simplest solution that has been used for over 20 years is not of of those. ;)

    The old way was to simply deactivate collision with one-way platforms when a character is going up.
    That can be done in quite a few different ways, one of the simplest is probably to have a different collision flag on one-way platforms and on "hard" ones, something like:
    [OneWayPlatformPart]
    SelfFlags = oneway
    CheckMask = character
    
    [PlatformPart]
    SelfFlags = ground
    CheckMask = character
    
    [CharacterPart]
    SelfFlags = character
    CheckMask = ground # oneway
    
    And during the ascension of a jump, one would change the character's collision part CheckMask using orxBody_SetPartCheckMask() to just ground and restore it to ground + oneway otherwise.
    Of course this can be more data driven to handle more complex situations, but you get my drift. ;)
  • edited September 2013
    As an alternative solution, one could have two separate parts on the character for sensing one way platform and solid ground and when going up, instead of just disabling the one way part, one could turn it to not solid by calling orxBody_SetPartSolid().

    The advantage is that, when reaching the peak of a jump, if the one way part is still in contact with a one way platform (you get notification because the part is active but it won't modify the dynamics as it's not solid) that means the character didn't jump high enough to reach above the one way platform.
    In this case one would not set the part back to solid right away when starting to go down but will wait till that collision goes away.

    Not sure if what I wrote is easy to understand, lemme know if that's not the case. :)
  • jimjim
    edited September 2013
    Hmm, good approach though. I would prefer your alternative method though. Because that way I know how long my body is colliding with the platform. So, as long as I am in jump + my sensors are colliding with platform, I will either disable collision or set that solid part a sensor, which would do the trick I guess.

    But even then, is there any reason not to provide a hook for pre solve and post solve ? To get more contact info like collision impulse or force you need contact impulse which is only possible with post solve.
    http://blog.allanbishop.com/box-2d-2-1a-tutorial-part-6-collision-strength/
  • edited September 2013
    The main reason for not supporting them is that they're non-standard.
    Box2D is only used for one implementation of the physics plugin but the interface needs to be as generic as possible.
    Contact add/remove are generic, pre-solve/post-solve aren't.

    Pre-solve isn't really necessary useful, unless you want to track the evolution of a contact. When a contact has just been added, you don't get more info in pre-solve compared to the add contact.
    Post-solve could be interesting for the reason you mentioned: the impulse being applied to the body. However you can't modify those impulse, it's strictly for checking their values and acting upon them.
    That can also be done when a contact is created as you can guess what's going to happen based on the current speed of your bodies and their attributes, such as mass. For example, if you want to get the energy of the impact, you can use the simple E = 1/2 m.v^2 formula. You can also inspect your new speed after a contact has been made and solved and act upon it (the force/impulse is easy to deduce from the current speed and the mass).
  • jimjim
    edited September 2013
    Yeah, calculation from my part could be done, it would be easier when their is ono-one situation, but I am not sure when there are many force or body acting upon each other, how to get the neat impulse on a single body. It would need too much manual calculation I guess.
  • edited September 2013
    Unfortunately having those callbacks wouldn't help you in this case either as you'll get called for each contact separately.
    A contact is only between 2 shapes (therefore 2 bodies), never more than that: in a post-solve call, you only get information about a single contact and a single impulse.
  • jimjim
    edited September 2013
    But it would spare me the extra bit of calculation I need to get the correct impulse force. Then act upon them. But what you said is not impossible. So, I will try to stick with your solution :)
  • edited September 2013
    :)

    Out of curiosity, for what purpose do you need to inspect the impulse resulting from a contact?
  • jimjim
    edited September 2013
    Now a days I am fiddling with making small game demo it orx+scroll for learning purpose, there is breakout and asteroid in the list. Hopefully they would serve as community tutorial as well. After that an angry bird clone to show the physics capability of Orx. And every tutorial out there on the net of angry bird, they used post-solve method to get collision impulse value. That's why.
  • edited September 2013
    Mmh, ok, but I mean for which exact purpose do they use it?
  • jimjim
    edited September 2013
    You can see that, when something falls on a pig, if falling body is big or falls with enough force the pig is destroyed. If its too slow and small it does not do any damage. Even here they got contact information from post-solve, because its the only method to get contact information if you don't roll your own.
    http://www.benoitfreslon.com/tutorial-how-to-create-a-game-like-angry-birds-in-flash-part4-create-the-pigs-and-the-collision-detectiontut
  • jimjim
    edited September 2013
    I am missing something very basic, I don't see a way to access body part of a body. And set it to non solid.
  • edited September 2013
    orxBody_GetNextPart() to iterate
    orxBody_GetPartName() to identify
    orxBody_SetPartSolid() to modify
  • jimjim
    edited September 2013
    I have found my answer, when I was first searching it did not showed up, only when I set date to any date, I got some one and half year old posts, which gave me my answer. But I am posting them also here, if someone else need them.

    1. To get the orxBODY from an orxOBJECT, use the following method :
    orxBODY *body = orxOBJECT_GET_STRUCTURE(_pstObject, BODY); // _pstObject is any orxOBJECT 
    if (pstBody == orxNULL)// its better to check if something is screwed
    {
    // the object has no body, return or print an error message 
    }
    

    2. Now, to get list of orxBODY_PART of a given orxBODY :
    orxBODY * body = orxOBJECT_GET_STRUCTURE (_pstObject, BODY); // get body from _pstObject
    for (orxBODY_PART * part = orxBody_GetNextPart (body, orxNULL);
         part != NULL;
         part = orxBody_GetNextPart (body, part) )
        {
             // your code related to body part
             orxLOG ("Part Name %s", orxBody_GetPartName (part) );
        }
    
  • edited September 2013
    As for the angry bird tutorials, in the contact add event one has the contact information (parts, position, normal) and one can query the bodies' speed and/or mass, which should give you all you need to simulate angry birds behavior.
  • jimjim
    edited September 2013
    Looks like I was posting mine while you were answering.
  • edited September 2013
    Yep, glad you found your info. :)
    Also don't hesitate to look at the doc folder, it'll always be up to date when you sync.
  • jimjim
    edited September 2013
    Btw, I saw you did something with tagging and string-id, but no more info on them. And yeah, I have also looked into 3d physics engine, they don't provide any contact info like box2d, so box2d is unusual here. It wont be much work for me to do the calculations, cuz I am ready for anything :)
  • jimjim
    edited September 2013
    But what happens in the following situation, bodies can still have zero velocity but can made huge impulse on other object.

    Tbe1R3b.jpg

    If you slightly push the black object on point A, its slowly going to fall to its side, notice it would have zero velocity. Then how to determine the force on red box ? Maybe I need to take account angular velocity too.
  • edited September 2013
    Well, you should be able to make it work no matter the situation.

    In the contact add, you get the contact point, you simply call orxBody_GetSpeedAtWorldPosition() with that position on the body that's "attacking".
    You'll get the actual speed at that point and that's all you need to know (as energy is only dependent on that speed and the body mass). :)
  • edited September 2013
    jim wrote:
    Btw, I saw you did something with tagging and string-id, but no more info on them.

    Sorry, forgot to answer that one!

    Yep, I meant to post about it on the dev group, I'll try to do that soon. :)
  • jimjim
    edited September 2013
    If tagging is what most of the cases means, an alternate for a name, then its cool, because string comparison is slow.
  • edited September 2013
    No, it's not really that.
    String comparison isn't really much more expensive than a simple numeral comparison in most of the case, though if you want to put your mind at peace, there could be a way to do a simple number comparison now that string are hashed and stored in a dictionary, but really that wouldn't save much.
  • jimjim
    edited September 2013
    I could not find any alternative of these functions to change or query body state at run-time, its likely that I am missing something.
    void SetType(b2BodyType type);
    b2BodyType GetType();
    
    void SetBullet(bool flag);
    bool IsBullet() const;
    
    void SetSleepingAllowed(bool flag);
    bool IsSleepingAllowed() const;
    
    void SetAwake(bool flag);
    bool IsAwake() const;
    
  • edited September 2013
    Those are not plugged for runtime modifications, no, do you have any practical use for them?
  • jimjim
    edited September 2013
    Oh, would it take a lot of work to add these ?
    One usage I could see is, in a platform we see some platforms begin to fall as soon as player walks onto them.
    First I would make them static so gravity wont have any effect on them, as soon as player walks on them I could make them dynamic/kinematic so they would begin to fall. Sometime box2d ignores objects that were sleeping so I would make them awake if needed.
  • edited September 2013
    Well the issue for the type is that they are partly abstracted and only depends on the settings you provide at creation. For example, kinetic/static isn't really exposed directly as a type (and it's also something specific to Box2D, for a change ;) ).

    I have the feeling that having dynamic platforms wouldn't work as you'd expect as contact will continuously be updated with the character on top of it and would also influence its velocity and might become a nightmare to obtain something nice.

    Kinematic, on the other hand, wouldn't apply the gravity to your platform as gravity only affects dynamic bodies.

    Your best bet is probably to have them kinematic since creation and then apply a speed/acceleration, either manually or via an orxFX when need be.

    As for the awake property, orx should do the right thing for you behind the scene, and you shouldn't have to worry about it. :)
  • jimjim
    edited September 2013
    I know they are abstracted, but exposing them via orxBody_AllowMoving, orxBody_IsDynamic, orxBody_IsHighSpeed is possible.
    A usage of SetBullet could be, if I am using highspeed body for bullets and when they collide with enemy they normally disappear, but if the collide with certain object or wall then bullets will either fall in the ground or stuck in the wall depending on the type of the wall. To show that bullets could not penetrate, now I could set them setBullet/HighSpeed to false, and make them static. I could do this creating a joints but simply making them static would be much easier then creating a joint.
  • edited September 2013
    The issue with adding functions in a plugin clutters the interface and makes it harder to support different implementation (like bullet, etc...). Also, as I said, those don't really exist in most physics engine and it's better to keep the common denominator for a plugin API, as much as possible.

    I don't understand your user case of changing the bullet property. It's an optimization flag, removing it from of body when you want it "static" doesn't have any effect.

    In this case, I'd suggest completely removing the body if you want to keep your bullet, or if you really need the body to stay (probably more likely for an arrow and not a bullet), you should create a new one and replace the old one. That's usually what is done when using physics engines which don't allow these kind of conversions. There's no need to create a joint, unless you need the specific behaviors that come with it.
  • jimjim
    edited September 2013
    Okay, I got your point.

    Afaik, unity exposes (which uses PhysX) setting up kinematic property at runtime, they have no static property, for static purpose they use a collider. And querying if a body is sleeping, and setting collision type to discrete = no highspeed or CCD = high speed.

    But whatever you said is a valid solution for the problem I proposed, yes I was talking about arrows. So, I will keep that in mind.
  • edited September 2013
    The high-speed property is the most portable one, so if you need it, I can add it.
    The awake one is also portable but the idea was to abstract it so that the user doesn't have to worry about it while doing the right thing behind the scene.
  • jimjim
    edited September 2013
    Hmm, I don't see much usage of awake function though, as I am not needing them right now. I will see if I really need them later, or I might add them myself in my local copy first only if I get enough time.

    One more thing, we could add tool specific stuffs using conditional compilation, so things specific to Box2D could be added under #ifdef PHYSICS_BOX2D #endif, some engines for example cocos2d does it this way, as it has either chipmunk or box2d physics.
  • edited September 2013
    jim wrote:
    Hmm, I don't see much usage of awake function though, as I am not needing them right now. I will see if I really need them later, or I might add them myself in my local copy first only if I get enough time.

    I'm talking about the highspeed one, not the awake one. :)
    One more thing, we could add tool specific stuffs using conditional compilation, so things specific to Box2D could be added under #ifdef PHYSICS_BOX2D #endif, some engines for example cocos2d does it this way, as it has either chipmunk or box2d physics.

    That does not fix the problem as the plugin API (what you see in orxPhysics.h) is generic independent from the actual plugin implementation. Having conditional compiling wouldn't help.
    When you use the orxDisplay.h API, you expect the same result no matter the implementation (which is not always 100% true and irks me, but hopefully that'll be fixed later on): when on PC or iOS, you still expect the same result and not to have to modify your user code with that respect.
    The idea is to prevent as much as possible the user to have to do those kind of conditional compilation on his side.
  • jimjim
    edited September 2013
    Oh, I see.
    Well, end of my weekend, but I will back with questions about box2d time step, animation and scroll soon.
Sign In or Register to comment.