2
\$\begingroup\$

I would like to move a kinematic box by pressing the down arrow. As is noted by the console logs, the keydown actually does change the box's velocity... but for reasons beyond my grasp it still doesn't move.

Note that if you place the SetLinearVelocity() call in a spot where it runs immediately, the box will move, but if it is in a setTimeout, or as in my example, called from an event, the box stays frozen despite its y velocity property changing to 1.

I created the simplest example I could to show my problem.

Note: I am using the latest release of Box2dWeb

//std variables
     var   b2Vec2 = Box2D.Common.Math.b2Vec2
        ,   b2BodyDef = Box2D.Dynamics.b2BodyDef
        ,   b2Body = Box2D.Dynamics.b2Body
        ,   b2FixtureDef = Box2D.Dynamics.b2FixtureDef
        ,   b2Fixture = Box2D.Dynamics.b2Fixture
        ,   b2World = Box2D.Dynamics.b2World
        ,   b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
        ,   b2DebugDraw = Box2D.Dynamics.b2DebugDraw;

//create world and gravity
     var world = new b2World(
           new b2Vec2(0, 10)
        ,  true
     );

//fixture defs
     var fixDef = new b2FixtureDef;
     fixDef.density = 1.0;
     fixDef.friction = 0.5;
     fixDef.restitution = .2;

//body defs
     var bodyDef = new b2BodyDef;
     fixDef.shape = new b2PolygonShape;
     fixDef.shape.SetAsBox(2,2);
     bodyDef.type = b2Body.b2_kinematicBody;
     bodyDef.position.x = 3;
     bodyDef.position.y = 0;  

//body and fixture creation
     var body1 = world.CreateBody(bodyDef);
     body1.CreateFixture(fixDef);

//"Before" console log
     console.log("Claimed velocity before down is pressed: " + body1.GetLinearVelocity().y);

//Listener and keycode switch for intended velocity change
     window.addEventListener("keydown", onKeyDown, false);
     function onKeyDown(e) {
        switch(e.keyCode) {
            case 40://down
                body1.SetLinearVelocity(new b2Vec2(0,1));
                console.log("Claimed velocity after down is pressed: " + body1.GetLinearVelocity().y);
        }
     }

//debug drawing 
     var debugDraw = new b2DebugDraw();
        debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
        debugDraw.SetDrawScale(30.0);
        debugDraw.SetFillAlpha(0.5);
        debugDraw.SetLineThickness(1.0);
        debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
        world.SetDebugDraw(debugDraw);

     window.setInterval(update, 1000 / 60);

//loop
     function update() {
        world.Step(1 / 60, 10, 10);
        world.DrawDebugData();
        world.ClearForces();
     }

\$\endgroup\$
  • \$\begingroup\$ So if you print out the velocity from inside the update() function, it never changes? How about if instead of using any variables directly inside onKeyDown, you put that stuff into a function of its own, and called that function from onKeyDown? I'm guessing that when addEventListener is called, the variable body1 might be copied instead of using a reference to it. See also: stackoverflow.com/questions/183214/javascript-callback-scope \$\endgroup\$ – iforce2d Feb 27 '14 at 15:43
  • \$\begingroup\$ No, the velocity DOES change. Ostensibly. I have used console logs in every position of the code and it always says the box has a y velocity of 1 after having pressed the down key, yet the box still stays motionless despite this. And I tried using a called function like you suggested to no success. Thanks though. \$\endgroup\$ – Brimby Feb 27 '14 at 17:12
  • \$\begingroup\$ @iforce2d Also just wanted to say that your tutorials are great and that I'm def going to be purchasing RUBE from your site soon. Are you getting the same result when you run my code? \$\endgroup\$ – Brimby Feb 27 '14 at 17:17
1
\$\begingroup\$

The bodies are apparently asleep and therefore need to be woken up before they respond.

This is taken from this link:

http://www.box2d.org/manual.html

From the Box2d site:

A sleeping body doesn't require any simulation.

What does sleep mean? Well it is expensive to simulate bodies, so the less we have to simulate the better. When a body comes to rest we would like to stop simulating it.

When Box2D determines that a body (or group of bodies) has come to rest, the body enters a sleep state which has very little CPU overhead. If a body is awake and collides with a sleeping body, then the sleeping body wakes up. Bodies will also wake up if a joint or contact attached to them is destroyed. You can also wake a body manually.

The body definition lets you specify whether a body can sleep and whether a body is created sleeping.

 bodyDef.allowSleep = true;

 bodyDef.awake = true;
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Sorry I can't upvote you with my beginner reputation. \$\endgroup\$ – Brimby Mar 1 '14 at 20:34
1
\$\begingroup\$

I think this may be a bug in box2dweb. If I add this to the body definition, it works:

 bodyDef.linearVelocity.x = 1;
 bodyDef.linearVelocity.y = 1;

But of course, if you want the body to start motionless, you would do:

 bodyDef.linearVelocity.x = 0;
 bodyDef.linearVelocity.y = 0;

... which does not work. Trying to trick it by using a very small value like 0.0001 caused the body to move for a very short while, after which the velocity became zero and setting it to anything else after that had no effect. But for values of about 0.01 and above, the velocity remained constant.

Changing the body type to dynamic also made everything work correctly.

Something seriously screwy is going on there. Hope this helps :D

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Not sure if it's a bug or the intentional function of the programmer. Although I would argue that it does lack certain useful functionality if it is intentional.

As far as I can tell, the way it works is that kinematic bodies cannot change velocity after coming to a rest. They must begin with a significant velocity, and from there can change velocity based on events, but if they stop, or if they begin with no velocity, they will remain still.

Below I have included some code which allows my previous program to function somewhat how it's supposed to. However, it's not good enough for application in my opinion because of the small movements always taking place, despite them being nearly unnoticeable.

//std variables
     var   b2Vec2 = Box2D.Common.Math.b2Vec2
        ,  b2AABB = Box2D.Collision.b2AABB
        ,   b2BodyDef = Box2D.Dynamics.b2BodyDef
        ,   b2Body = Box2D.Dynamics.b2Body
        ,   b2FixtureDef = Box2D.Dynamics.b2FixtureDef
        ,   b2Fixture = Box2D.Dynamics.b2Fixture
        ,   b2World = Box2D.Dynamics.b2World
        ,   b2MassData = Box2D.Collision.Shapes.b2MassData
        ,   b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
        ,   b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
        ,   b2DebugDraw = Box2D.Dynamics.b2DebugDraw
        ,  b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
        ;

//create world and gravity
     var world = new b2World(
           new b2Vec2(0, 0)
        ,  true
     );

//fixture defs
     var fixDef = new b2FixtureDef;
     fixDef.shape = new b2PolygonShape;
     fixDef.shape.SetAsBox(2,2);

//body defs
     var bodyDef = new b2BodyDef;
     bodyDef.type = b2Body.b2_kinematicBody;
     bodyDef.position.x = 3;
     bodyDef.position.y = 3;  
     bodyDef.linearVelocity.y = .05;
//body and fixture creation
     var body1 = world.CreateBody(bodyDef);
     body1.CreateFixture2(fixDef.shape,1);

//Listener and keycode switch for intended velocity change
     window.addEventListener("keydown", onKeyDown, false);
     window.addEventListener("keyup", onKeyUp, false);       
     function onKeyDown(e) {
        switch(e.keyCode) {
            case 37:
                body1.SetLinearVelocity(new b2Vec2(-1,0));      
                break;
            case 38:
                body1.SetLinearVelocity(new b2Vec2(0,-1));
                break;
            case 39:
                body1.SetLinearVelocity(new b2Vec2(1,0));
                break;
            case 40:
                body1.SetLinearVelocity(new b2Vec2(0,1));
                break;
        }
     }
     function onKeyUp(e) {
        switch(e.keyCode) {
            case 37:
                body1.SetLinearVelocity(new b2Vec2(0.01,0.01)); 
                break;
            case 38:
                body1.SetLinearVelocity(new b2Vec2(0.01,0.01));
                break;
            case 39:
                body1.SetLinearVelocity(new b2Vec2(0.01,0.01));
                break;
            case 40://down
                body1.SetLinearVelocity(new b2Vec2(0.01,0.01));
                break;
        }
     }

//debug drawing 
     var debugDraw = new b2DebugDraw();
        debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
        debugDraw.SetDrawScale(30.0);
        debugDraw.SetFillAlpha(0.5);
        debugDraw.SetLineThickness(1.0);
        debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
        world.SetDebugDraw(debugDraw);

     window.setInterval(update, 1000 / 60);

//loop
     function update() {
        world.Step(1 / 60, 10, 10);
        world.DrawDebugData();
        world.ClearForces();
     }

My final note is that the direction I will be taking to move forward with my application is coding my own acceleration and velocity function for the kinematic bodies based on setting their positions.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This is intended. It is called sleep. The bodies are put to sleep to reduce computation code if they do not move for a few tics. The intended way to resolve this is to wake bodies after you change their velocity. \$\endgroup\$ – AturSams Mar 1 '14 at 19:49
  • \$\begingroup\$ @Arthur You're right. Change your comment to an answer and I'll check it as correct. \$\endgroup\$ – Brimby Mar 1 '14 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.