How to make proper joints

Discuss issues specific the Javascript port of Box2D
silv3r_m00n
Posts: 5
Joined: Wed Oct 05, 2011 5:02 am

How to make proper joints

Postby silv3r_m00n » Wed Oct 05, 2011 7:10 am

Hello

http://projects.omikrosys.com/gaming/racing/moving.html

If you move the car using arrow keys , the wheels would go out of track and start hanging out of the main car body.

The wheel should stick to its position on the wheel.
What is wrong with the code :

Code: Select all

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
   ,     b2Shape = Box2D.Collision.Shapes.b2Shape
   ,   b2RevoluteJointDef = Box2D.Dynamics.Joints.b2RevoluteJointDef
   ,   b2Joint = Box2D.Dynamics.Joints.b2Joint
   ,   b2PrismaticJointDef = Box2D.Dynamics.Joints.b2PrismaticJointDef
   ;
         

var game = {
   
   'key_down' : function(e)
   {
      var code = (e.keyCode);
      
      var v = 100;
      
      //left
      if(code == 37)
      {
         steering_angle = -1 * max_steer_angle;
      }
      //up
      if(code == 38)
      {
         engine_speed = -1*top_speed;
      }
      
      //right
      if(code == 39)
      {
         steering_angle = max_steer_angle;
      }
      
      //down
      if(code == 40)
      {
         engine_speed = top_speed;
      }
   } ,
   
   'key_up' : function(e)
   {
      engine_speed = 0;
      steering_angle = 0;
   } ,
   
};

var engine_speed = 0;
var steering_angle = 0;
var steer_speed = 1.5;
var max_steer_angle = Math.PI/3;
var top_speed = 5000;
var world;
var ctx;
var canvasWidth;
var canvasHeight;
var canvasTop;
var canvasLeft;
var car;

/*
   Draw a world
   this method is called in a loop to redraw the world
*/   
function drawWorld(world, context)
{
   for (var j = world.GetJointList() ; j ; j = j.GetNext())
   {
      drawJoint(j, context);
   }
   
   
   for( var b = world.GetBodyList() ; b ; b = b.GetNext())
   {
      for( var f = b.GetFixtureList() ; f != null ; f = f.GetNext())
      {
         var shape = f.GetShape();
         var shapeType = shape.GetType();
         if(isNaN(b.GetPosition().x))
         {
            alert('Invalid Position : ' + b.GetPosition().x);
         }
         else
         {
            drawShape(b , shape , context);
         }
      }
   }
   
   ctx.font = 'bold 18px arial';
   ctx.textAlign = 'center';
   ctx.fillStyle = '#000000';
   ctx.fillText("Use arrow keys to move the car", 400, 20);
   //ctx.font = 'bold 14px arial';
   //ctx.fillText("Performance will vary by browser", 400, 40);

}

function drawJoint(joint, context)
{
   var b1 = joint.GetBodyA();
   var b2 = joint.GetBodyB();
   
   var x1 = b1.GetPosition();
   var x2 = b2.GetPosition();
   
   var p1 = joint.GetAnchorA();
   var p2 = joint.GetAnchorB();
   context.strokeStyle = '#00eeee';
   context.beginPath();
   
   switch (joint.m_type)
   {
      case b2Joint.e_distanceJoint:
         context.moveTo(p1.x, p1.y);
         context.lineTo(p2.x, p2.y);
         break;
   
      case b2Joint.e_pulleyJoint:
         // TODO
         break;
   
      default:
         if (b1 == world.m_groundBody)
         {
            context.moveTo(p1.x, p1.y);
            context.lineTo(x2.x, x2.y);
         }
         
         else if (b2 == world.m_groundBody)
         {
            context.moveTo(p1.x, p1.y);
            context.lineTo(x1.x, x1.y);
         }
         
         else
         {
            context.moveTo(x1.x, x1.y);
            context.lineTo(p1.x, p1.y);
            context.lineTo(x2.x, x2.y);
            context.lineTo(p2.x, p2.y);
         }
         
         break;
   }
   
   context.stroke();
}

function drawShape(body , shape, context)
{
   context.strokeStyle = '#000';
   
   if (shape.density == 1.0)
   {
      context.fillStyle = "red";
   }
   
   else
   {
      context.fillStyle = "#fff";
   }
   
   context.beginPath();
   
   switch (shape.GetType())
   {
      case b2Shape.e_polygonShape:
      {
         var poly = shape;
         var vert = shape.GetVertices();
         
         var position = body.GetPosition();
         //b2Math.MulMV(b.m_xf.R , vert[0]);
         var tV = position.Copy();
         var a = vert[0].Copy();
         a.MulM( body.GetTransform().R );
         tV.Add(a);
         
         //var tV = b2Math.AddVV( position , b2Math.MulMV(b.m_xf.R, vert[0]) );
         
         context.moveTo(tV.x, tV.y);
         
         for (var i = 0; i < vert.length; i++)
         {
            var v = vert[i].Copy();
            //v.MulM( body.m_xf.R );
            v.MulM( body.GetTransform().R );
            v.Add(position);
            //var v = b2Math.AddVV(position, b2Math.MulMV(b.m_xf.R, vert[i]));
            context.lineTo(v.x, v.y);
         }
         
         context.lineTo(tV.x, tV.y);
         
         /*
         //m_position is a (x, y) vector having positions of the body
         var tV = b2Math.AddVV( poly.m_position , b2Math.b2MulMV(poly.m_R , poly.m_vertices[0]) );
         context.moveTo(tV.x, tV.y);
         
         //for square things there are 4 vertices :)
         //for sqyare things m_r is 1 , 0 | 0 , 1 matrix ?? what does it means ? unit matrix of order 2 ?
         
         for (var i = 0; i < poly.m_vertexCount; i++)
         {
            var v = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
            context.lineTo(v.x, v.y);
         }
         
         context.lineTo(tV.x, tV.y);*/
      }
      
      break;
   }
   //this will fill a shape
   //context.fill();
   
   //this will create the outline of a shape
   context.stroke();
}

/*
   Create box2d world object
*/
function createWorld()
{
   var gravity = new b2Vec2(0, 0);
   var doSleep = true;
   
   world = new b2World(gravity , doSleep);
   
   return world;
}      


/*
   Create standard boxes of given height , width at x,y
*/
function createBox(world, x, y, width, height, options)
{
    //default setting
   options = $.extend(true, {
      'density' : 1.0 ,
      'friction' : 1.0 ,
      'restitution' : 0.2 ,
      
      'linearDamping' : 0.0 ,
      'angularDamping' : 0.0 ,
      
      'gravityScale' : 1.0 ,
      'type' : b2Body.b2_dynamicBody
   }, options);
   
   var body_def = new b2BodyDef();
   var fix_def = new b2FixtureDef;
   
   fix_def.density = options.density;
   fix_def.friction = options.friction;
   fix_def.restitution = options.restitution;
   
   fix_def.shape = new b2PolygonShape();
   
   fix_def.shape.SetAsBox( width , height );
   
   body_def.position.Set(x , y);
   
   body_def.linearDamping = options.linearDamping;
   body_def.angularDamping = options.angularDamping;
   
   body_def.type = options.type;
   body_def.gravityScale = 0;
   
   var b = world.CreateBody( body_def );
   var f = b.CreateFixture(fix_def);
   
   return b;
}

/*
   This method will draw the world again and again
   called by settimeout , self looped
*/
function step(cnt)
{
   var stepping = false;
   
   //fps = 60 , time steps
   var fps = 60;
   var timeStep = 1.0/fps;
   var iteration = 1;
   
   //move the world ahead , step ahead man!!
   world.Step(timeStep, iteration);
   update_car();
   
   //first clear the canvas
   ctx.clearRect( 0 , 0 , game.canvas_width, game.canvas_height );
   
   //redraw the world
   drawWorld(world , ctx);
   
   //call this function again after 10 seconds
   setTimeout('step(' + (cnt || 0) + ')', 10);
}

// main entry point
$(function()
{
   //first create the world
   world = createWorld();
   
   game.ctx = ctx = $('#canvas').get(0).getContext('2d');
   var canvas = $('#canvas');
   
   game.canvas_width = canvasWidth = parseInt(canvas.width());
   game.canvas_height = canvasHeight = parseInt(canvas.height());
   
   //canvasTop = parseInt(canvasElm.style.top);
   //canvasLeft = parseInt(canvasElm.style.left);
   
   create_car();
   
   $('body').keydown(function(e)
   {
      game.key_down(e);
   });
   
   $('body').keyup(function(e)
   {
      game.key_up(e);
   });
   
   step();
});

function create_car()
{
   car_pos = new b2Vec2(300,300);
   car_dim = new b2Vec2(20 ,35);
   car = createBox(world , car_pos.x , car_pos.y , car_dim.x , car_dim.y , true , {});
   
   var wheel_dim = new b2Vec2(4 , 8);
   
   
   //front wheels
   left_wheel = createBox(world , car_pos.x - car_dim.x , car_pos.y - car_dim.y / 2 , wheel_dim.x , wheel_dim.y , {});
   right_wheel = createBox(world , car_pos.x + car_dim.x, car_pos.y - car_dim.y / 2 , wheel_dim.x , wheel_dim.y , {});
   
   //rear wheels
   left_rear_wheel = createBox(world , car_pos.x - car_dim.x , car_pos.y + car_dim.y / 2 , wheel_dim.x , wheel_dim.y , {});
   right_rear_wheel = createBox(world , car_pos.x + car_dim.x, car_pos.y + car_dim.y / 2 , wheel_dim.x , wheel_dim.y , {});
   
   var front_wheels = {'left_wheel' : left_wheel , 'right_wheel' : right_wheel};
   
   for (var i in front_wheels)
   {
      var wheel = front_wheels[i];
      
      var joint_def = new b2RevoluteJointDef();
      joint_def.Initialize(car , wheel, wheel.GetWorldCenter());
   
      //after enablemotor , setmotorspeed is used to make the joins rotate , remember!
      joint_def.enableMotor = true;
      joint_def.maxMotorTorque = 100000;
      
      car[i + '_joint'] = world.CreateJoint(joint_def);
   }
   
   var rear_wheels = {'left_rear_wheel' : left_rear_wheel , 'right_rear_wheel' : right_rear_wheel};
   
   for (var i in rear_wheels)
   {
      var wheel = rear_wheels[i];
      
      var joint_def = new b2PrismaticJointDef();
      joint_def.Initialize( car , wheel, wheel.GetWorldCenter(), new b2Vec2(1,0) );
   
      joint_def.enableLimit = true;
      joint_def.lowerTranslation = joint_def.upperTranslation = 0.0;
      
      car[i + '_joint'] = world.CreateJoint(joint_def);
   }
   
   car.left_wheel = left_wheel;
   car.right_wheel = right_wheel;
   car.left_rear_wheel = left_rear_wheel;
   car.right_rear_wheel = right_rear_wheel;
   
   
   return car;
}

//This function applies a "friction" in a direction orthogonal to the body's axis.
function killOrthogonalVelocity(b)
{
   var localPoint = new b2Vec2(0,0);
   var velocity = b.GetLinearVelocityFromLocalPoint(localPoint);
 
   var sidewaysAxis = b.GetTransform().R.col2.Copy();
   
   //multiply vector with a constant;
   sidewaysAxis.Multiply( velocity.x*sidewaysAxis.x + velocity.y*sidewaysAxis.y)
 
   b.SetLinearVelocity(sidewaysAxis); //b.GetWorldPoint(localPoint));
}

function update_car()
{
   killOrthogonalVelocity(car.left_wheel);
   killOrthogonalVelocity(car.right_wheel);
   killOrthogonalVelocity(car.left_rear_wheel);
   killOrthogonalVelocity(car.right_rear_wheel);
 
   var wheels = ['left' , 'right'];
   
   //Driving
   for(var i in wheels)
   {
      var d = wheels[i] + '_wheel';
      var wheel = car[d];
      
      var direction = wheel.GetTransform().R.col2.Copy();
      direction.Multiply( engine_speed );
      
      wheel.ApplyForce( direction , wheel.GetPosition() );
   }   
   
   //Steering
   for(var i in wheels)
   {
      var d = wheels[i] + '_wheel_joint';
      var wheel_joint = car[d];
      
      //set the motor speed
      var mspeed;
      //max speed - current speed , should be the motor speed , so when max speed reached , speed = 0;
      mspeed = steering_angle - wheel_joint.GetJointAngle();
      wheel_joint.SetMotorSpeed(mspeed * steer_speed);
   }
   
}


Regards
Silver

silv3r_m00n
Posts: 5
Joined: Wed Oct 05, 2011 5:02 am

Re: How to make proper joints

Postby silv3r_m00n » Wed Oct 05, 2011 9:19 pm

OK , I fixed it. world step iteration was incorrect.

world.Step(timeStep, 8 , 3); solved it.

Silver

irresistible force
Posts: 1988
Joined: Tue Jun 24, 2008 8:25 pm
Location: Tokyo
Contact:

Re: How to make proper joints

Postby irresistible force » Wed Oct 05, 2011 10:17 pm

Great!
Just a note for the future - I don't think anyone is going to look through an enormous block of code like that to answer the very broad question "What is wrong?" You'll have to narrow it down to a more reasonable scope first.


Return to “Javascript”



Who is online

Users browsing this forum: No registered users and 4 guests