Box2D Forums

It is currently Sat May 25, 2013 12:34 am

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Tue Feb 08, 2011 4:02 pm 
Offline

Joined: Mon Apr 07, 2008 3:06 am
Posts: 99
I'm working on a platformer game and having problems finding the ground normal beneath the player's character. I have no problem testing whether my character is on the ground using this little function:

Code:
      private function _onGround(sensor:BodyShape):Boolean {
         var list:ContactList = contacts[sensor];
         list.clean();
         return (list.values.length > 0);
      }


...but when I try to find the normal using the exact same ContactList as the above function, there's never any information there. I've tried copying the code directly out of parseInput() from BoxMan.as. Although the manifold object receives a value, it's normal property is always null. Here's my code as it stands...

Code:
      public function groundNormal(sensor:BodyShape):Number {
         var list:ContactList = contacts[sensor];
         if(!list.isEmpty()) {
            list.forEach(function(keys:Array, item:ContactEvent) {
               var wm:b2WorldManifold = item.getWorldManifold();
               if (wm.normal) return wm.normal.angle();
            });
         }
         return 0;
      }


Top
 Profile  
 
PostPosted: Tue Feb 08, 2011 4:10 pm 
Offline

Joined: Fri Dec 14, 2007 8:07 pm
Posts: 913
Contacts involving a sensor don't generate normals. It's an optimization - the engine assumes they're not needed. You can force it to generate a normal by calling b2Contact->Evaluate() (it might be b2Contact->Update(), just can't remember for sure, and I can't remember if you can call it inside the timestep).

The method I prefer is to just check the direction of the normal to see if the player's on the ground, rather than use a "foot" sensor.


Top
 Profile  
 
PostPosted: Tue Feb 08, 2011 8:05 pm 
Offline

Joined: Mon Apr 07, 2008 3:06 am
Posts: 99
Quote:
The method I prefer is to just check the direction of the normal to see if the player's on the ground, rather than use a "foot" sensor.


OK. Sounds good... how would I do that?


Top
 Profile  
 
PostPosted: Wed Feb 09, 2011 7:37 am 
Offline

Joined: Fri Dec 14, 2007 8:07 pm
Posts: 913
dot product the normal with a vector pointing straight down. If it's zero, the contact is a vertical wall. If it's 1 or -1 it's either a ceiling or the floor. anything in between is a sloped ceiling or floor.


Top
 Profile  
 
PostPosted: Wed Feb 09, 2011 6:05 pm 
Offline

Joined: Mon Apr 07, 2008 3:06 am
Posts: 99
Argh. I can't seem to get any method working. Would you mind perhaps adding a groundNormal check to BoxMan for an example?


Top
 Profile  
 
PostPosted: Tue Feb 15, 2011 2:44 pm 
Offline

Joined: Fri Dec 14, 2007 8:07 pm
Posts: 913
Actually it already in there. Take a look at the code. I added some comments to explain whats going on:
Code:
      public function parseInput(e:Event):void {
         var manifold:b2WorldManifold = null;
         var dot:Number = -1;
         
         // Search for the most ground/floor-like contact.
         if(!contacts.isEmpty()) {
            contacts.forEach(function(keys:Array, c:ContactEvent) {
               var wm:b2WorldManifold = c.getWorldManifold();
               if(wm.normal) {
                  
                  // Dot producting the contact normal with gravity indicates how floor-like the
                  // contact is. If the dot product = 1, it is a flat foor. If it is -1, it is
                  // a ceiling. If it's 0.5, it's a sloped floor. Save the contact manifold
                  // that is the most floor like.
                  var d:Number = wm.normal.dot(gravity);
                  if(!manifold || d > dot) {
                     manifold = wm;
                     dot = d;
                  }
               }
            });
            contacts.clean();
         }
         var left:Boolean = Input.kd('A', 'LEFT');
         var right:Boolean = Input.kd('D', 'RIGHT');
         var jump:Boolean = Input.kp(' ', 'UP');
         var v:V2;
         
         // Here we could add a dot product threshold for disallowing the player from jumping
         // off of walls, ceilings, etc. For example:
         // if(jump && manifold && dot > 0) {
         if(jump && manifold) {
            v = manifold.normal.clone().multiplyN(-2);
            b2body.ApplyImpulse(v, b2body.GetWorldCenter());
         }
         else if(left) {
            b2body.ApplyImpulse(new V2(-0.1, 0), b2body.GetWorldCenter());
         }
         else if(right) {
            b2body.ApplyImpulse(new V2(0.1, 0), b2body.GetWorldCenter());            
         }
      }


Top
 Profile  
 
PostPosted: Wed Feb 16, 2011 12:22 pm 
Offline

Joined: Fri Sep 17, 2010 10:12 pm
Posts: 5
Little annoyance I discovered for anyone else trying to do this: If your player object has "fixed rotation", this doesn't work (I don't know why, but when you get the world manifold its just gibberish unintialised data).

This article has a good method for dealing with this http://dev.chadgodsey.com/2010/03/chara ... ysics.html (modified with this method http://en.wikipedia.org/wiki/PID_controller )
Or you could just render the player unrotated, regardless of what his body is doing, although this'd probably cause problems.

Anyone comes up with an alternative solution that lets you use fixed rotation, do let me know :)


Top
 Profile  
 
PostPosted: Wed Feb 16, 2011 12:48 pm 
Offline

Joined: Mon Apr 07, 2008 3:06 am
Posts: 99
Ah ha!!! Yes, that must be the problem I'm having. I'll check that link out and post any further solutions I can come up with. Thanks, deek0146

...and thank you Jesse for the documentation.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group