Top View Car Simulation Experiment

Hi,

Recently I’m developing a race game and I need a top view car simulation in Box2D.

I just found this example: (1st example)
http://www.emanueleferonato.com/2009/04/06/two-ways-to-make-box2d-cars/

I’ve ported the it to Lua:
[lua]display.setStatusBar( display.HiddenStatusBar )

local physics

local CAR_WIDTH = 40
local CAR_HEIGHT = 75
local CAR_SPEED = 4
local car

local motor0
local motor1
local motor2
local motor3

local motor0Joint
local motor1Joint
local motor2Joint
local motor3Joint

local positionController = display.newRect(0,0,320,480)
positionController.alpha = 0.01

local createPhysics = function ()
physics = require( “physics” )
physics.start()
physics.setGravity(0,0)
physics.setDrawMode( “debug” )
end

local createCar = function()
car = display.newRect(0,0,40,75)
car.x = 320*.5 -20
car.y = 480-80
physics.addBody(car,“dynamic”,{density=3,friction=0,bounce=0.5})

motor0 = display.newRect(car.x-CAR_WIDTH*0.5-3.5,car.y-CAR_HEIGHT*0.5,7,14)
physics.addBody(motor0,dynamic,{density=0.1,friction=0,bounce=0})

motor1 = display.newRect(car.x+CAR_WIDTH*0.5-3.5,car.y-CAR_HEIGHT*0.5,7,14)
physics.addBody(motor1,dynamic,{density=0.1,friction=0,bounce=0})

motor2 = display.newRect(car.x-CAR_WIDTH*0.5-3.5,car.y+CAR_HEIGHT*0.5-14,7,14)
physics.addBody(motor2,dynamic,{density=0.1,friction=0,bounce=0})

motor3 = display.newRect(car.x+CAR_WIDTH*0.5-3.5,car.y+CAR_HEIGHT*0.5-14,7,14)
physics.addBody(motor3,dynamic,{density=0.1,friction=0,bounce=0})

motor0Joint = physics.newJoint( “pivot”, car, motor0, motor0.x,motor0.y )
motor1Joint = physics.newJoint( “pivot”, car, motor1, motor1.x,motor1.y )
motor2Joint = physics.newJoint( “pivot”, car, motor2, motor2.x,motor2.y )
motor3Joint = physics.newJoint( “pivot”, car, motor3, motor3.x,motor3.y )

motor0Joint.isMotorEnabled = true
motor0Joint.motorSpeed = 0
motor0Joint.maxMotorTorque = 100
motor0Joint.isLimitEnabled = true
motor0Joint:setRotationLimits(-30,30)

motor1Joint.isMotorEnabled = true
motor1Joint.motorSpeed = 0
motor1Joint.maxMotorTorque = 100
motor1Joint.isLimitEnabled = true
motor1Joint:setRotationLimits(-30,30)

motor2Joint.isLimitEnabled = true
motor2Joint:setRotationLimits(0,0)

motor3Joint.isLimitEnabled = true
motor3Joint:setRotationLimits(0,0)

motor0.isSensor = true
motor1.isSensor = true
motor2.isSensor = true
motor3.isSensor = true

end

local bodySpeedX
local bodySpeedY

local bodySideWayX
local bodySideWayY

local killOrthogonalVelocity = function(body)
bodySpeedX,bodySpeedY = body:getLinearVelocity()

bodySideWayX = math.sin(body.rotation/180*math.pi)
bodySideWayY = math.cos(body.rotation/180*math.pi)

– multipyl with dot(,)
bodySideWayX = bodySideWayX * (bodySideWayXbodySpeedX + bodySpeedYbodySideWayY)
bodySideWayY = bodySideWayY * (bodySideWayXbodySpeedX + bodySpeedYbodySideWayY)

body:setLinearVelocity(bodySideWayX,bodySideWayY)
end
local wheelDirectionX
local wheelDirectionY

local targetWheelAngle
local targetSteer = 0

local render = function (e)

killOrthogonalVelocity(motor0)
killOrthogonalVelocity(motor1)
killOrthogonalVelocity(motor2)
killOrthogonalVelocity(motor3)

wheelDirectionX = math.sin(-motor0.rotation/180math.pi)
wheelDirectionY = math.cos(-motor0.rotation/180
math.pi)
motor0:applyForce(-wheelDirectionXCAR_SPEED,-wheelDirectionYCAR_SPEED,motor0.x,motor0.y)
motor1:applyForce(-wheelDirectionXCAR_SPEED,-wheelDirectionYCAR_SPEED,motor1.x,motor0.y)

targetWheelAngle = (targetSteer30 - motor0Joint.jointAngle)
motor0Joint.motorSpeed = targetWheelAngle * 10

targetWheelAngle = (targetSteer
30 - motor1Joint.jointAngle)
motor1Joint.motorSpeed = targetWheelAngle * 10
end
local controll = function (event)
if event.phase ~= “ended” or event.phase ~= “cancelled” then
targetSteer = ((event.x/320)-.5)*2
end
end

local start = function()
Runtime:addEventListener( “enterFrame”, render )
positionController:addEventListener(“touch”,controll)
end
createPhysics()
createCar()
start()[/lua]
The problem is at killOrthogonalVelocity method. When I change the linear velocity of wheels which are bunch of rectangle objects connected to car body by pivot joint, It doesn’t set the velocity. Even If I set the velocities of wheels to 0,0 car keeps moving.

Is this a bug or?

Thank you! [import]uid: 5629 topic_id: 11567 reply_id: 311567[/import]

Did you ever find a solution to this? I am going to check it out. [import]uid: 8192 topic_id: 11567 reply_id: 42524[/import]

So the wheels are rectangles?

[lua]radius = 45[/lua] [import]uid: 25216 topic_id: 11567 reply_id: 42525[/import]

I am not sure what this command is.

var sidewaysAxis = targetBody.GetXForm().R.col2.Copy();  
 sidewaysAxis.Multiply(b2Math.b2Dot(velocity,sidewaysAxis))  

Once I know what it is I will be able to fix the equation. [import]uid: 8192 topic_id: 11567 reply_id: 42602[/import]

slightly modified version, It should work

[code]
display.setStatusBar( display.HiddenStatusBar )

local physics

local CAR_WIDTH = 40
local CAR_HEIGHT = 75
local CAR_SPEED = 5
local car

local motor0
local motor1
local motor2
local motor3

local motor0Joint
local motor1Joint
local motor2Joint
local motor3Joint

local STEER_SPEED = 100
local MAX_STEER_ANGLE = 30

local leftBtn = display.newRect( 10, 420, 50, 50)
local rightBtn = display.newRect( 70, 420, 50, 50)

local createPhysics = function ()
physics = require( “physics” )
physics.start()
physics.setGravity(0,0)
physics.setDrawMode( “hybrid” )
physics.setVelocityIterations( 10 )
end

local createCar = function()
car = display.newRect(0,0,40,75)
car.x = 320*.5 -20
car.y = 480-80
physics.addBody(car,“dynamic”,{density=3,friction=0,bounce=0.5})

car.linearDamping = 1
car.angularDamping = 1

motor0 = display.newRect(car.x-CAR_WIDTH*0.5-3.5,car.y-CAR_HEIGHT*0.5,7,14)
physics.addBody(motor0,dynamic,{density=0.1,friction=0,bounce=0})

motor1 = display.newRect(car.x+CAR_WIDTH*0.5-3.5,car.y-CAR_HEIGHT*0.5,7,14)
physics.addBody(motor1,dynamic,{density=0.1,friction=0,bounce=0})

motor2 = display.newRect(car.x-CAR_WIDTH*0.5-3.5,car.y+CAR_HEIGHT*0.5-14,7,14)
physics.addBody(motor2,dynamic,{density=0.1,friction=0,bounce=0})

motor3 = display.newRect(car.x+CAR_WIDTH*0.5-3.5,car.y+CAR_HEIGHT*0.5-14,7,14)
physics.addBody(motor3,dynamic,{density=0.1,friction=0,bounce=0})

motor0Joint = physics.newJoint( “pivot”, car, motor0, motor0.x,motor0.y )
motor1Joint = physics.newJoint( “pivot”, car, motor1, motor1.x,motor1.y )
motor2Joint = physics.newJoint( “pivot”, car, motor2, motor2.x,motor2.y )
motor3Joint = physics.newJoint( “pivot”, car, motor3, motor3.x,motor3.y )

motor0Joint.isMotorEnabled = true
motor0Joint.motorSpeed = 0
motor0Joint.maxMotorTorque = 100
motor0Joint.isLimitEnabled = true
motor0Joint:setRotationLimits(-30,30)

motor1Joint.isMotorEnabled = true
motor1Joint.motorSpeed = 0
motor1Joint.maxMotorTorque = 100
motor1Joint.isLimitEnabled = true
motor1Joint:setRotationLimits(-30,30)

motor2Joint.isLimitEnabled = true
motor2Joint:setRotationLimits(0,0)

motor3Joint.isLimitEnabled = true
motor3Joint:setRotationLimits(0,0)

motor0.isSensor = true
motor1.isSensor = true
motor2.isSensor = true
motor3.isSensor = true

end

local bodySpeedX
local bodySpeedY

local bodySideWayX
local bodySideWayY

local killOrthogonalVelocity = function(body)

bodySpeedX,bodySpeedY = body:getLinearVelocity()

bodySideWayX = math.sin(body.rotation/180*math.pi)
bodySideWayY = math.cos(body.rotation/180*math.pi)

– multipyl with dot(,)
bodySideWayX = bodySideWayX * (bodySideWayXbodySpeedX + bodySpeedYbodySideWayY)
lbodySideWayY = bodySideWayY * (bodySideWayXbodySpeedX + bodySpeedYbodySideWayY)

body:setLinearVelocity(bodySideWayX,bodySideWayY)
end


local wheelDirectionX
local wheelDirectionY

ocal steeringAngle = 0

local render = function (e)

killOrthogonalVelocity(motor0)
killOrthogonalVelocity(motor1)
killOrthogonalVelocity(motor2)
killOrthogonalVelocity(motor3)

--Driving
wheelLDirectionX = math.sin(motor0.rotation/180math.pi) * CAR_SPEED
wheelLDirectionY = math.cos(motor0.rotation/180
math.pi) * CAR_SPEED

wheelRDirectionX = math.sin(motor1.rotation/180math.pi) * CAR_SPEED
wheelRDirectionY = math.cos(motor1.rotation/180
math.pi) * CAR_SPEED

motor0:applyForce(wheelLDirectionX,-wheelLDirectionY,motor0.x,motor0.y)
motor1:applyForce(wheelRDirectionX,-wheelRDirectionY,motor1.x,motor1.y)

--Steering
local mspeed
mspeed = math.rad( steeringAngle - motor0Joint.jointAngle )
motor0Joint.motorSpeed = mspeed * STEER_SPEED

mspeed = math.rad( steeringAngle - motor1Joint.jointAngle )
motor1Joint.motorSpeed = mspeed * STEER_SPEED

end

local onRightController = function (event)
if event.phase == “began” then
steeringAngle = MAX_STEER_ANGLE
elseif event.phase == “ended” then
steeringAngle = 0
end
end

local onLeftController = function (event)
if event.phase == “began” then
steeringAngle = -MAX_STEER_ANGLE
elseif event.phase == “ended” then
steeringAngle = 0
end
end

local start = function()
Runtime:addEventListener( “enterFrame”, render )

leftBtn:addEventListener(“touch”, onLeftController)
rightBtn:addEventListener(“touch”, onRightController)
end

createPhysics()
createCar()
start()
[/code] [import]uid: 12088 topic_id: 11567 reply_id: 42770[/import]

Thank you yuewah! It works great now :slight_smile:

Would you please explain the what you’ve fixed? The next step is to do this with forces. Because we set the velocity directly, drifting is impossible I think.

[lua]body:applyLinearImpulse(bodySideWayX-bodySpeedX,bodySideWayY-bodySpeedY)[/lua]

I can’t test it right now but maybe it can solve.

Cheers! [import]uid: 5629 topic_id: 11567 reply_id: 42847[/import]

Hi everyone,
I was surfing around on the box2d thread mentioned above and found this.

http://code.google.com/p/quickb2/

I have been in touch with the developer doug. He told me that this could be ported to Corona. He has no time to do it currently, but I’d be willing to pitch in some time with the help of others. We could start from the Topdown module for the cars.

It seems like his model has loads, frictions and the whole rest of fun things that we want. He told me which files to look at to port them over to Corona. The only command that is used is applyForce() he does not think that it would be a problem.

[import]uid: 8192 topic_id: 11567 reply_id: 42934[/import]

Most importantly, adding the following properties to the car body fix your previous code
car.linearDamping = 1
car.angularDamping = 1

Btw, if killOrthogonalVelocity is commented, seems no change to its behaviour. [import]uid: 12088 topic_id: 11567 reply_id: 42970[/import]

that is some great piece of code, thanx a lot for sharing :slight_smile:
at higher speeds, you must add more angular damping (like 5).
Have you devoloped this code more?
If Jonathan Beebe can make a code example of this, it would be great!
I’m also looking for ways to do a top-view golf like game, where you can simulate hills, but the ball is stuck at the hill when it stops, it don’t go down… [import]uid: 44010 topic_id: 11567 reply_id: 60056[/import]

Hi.

I am studying this project for my thesis.

I altered some parts and added some functionalities.

I made the car not to move automatically by adding another button for it to move and this: 

local onForwardController = function (event) if event.phase == "began" then CAR\_SPEED = 30 steeringAngle = 0 elseif event.phase == "ended" then CAR\_SPEED = 0 end

But when I make the car move, it moves forward and at the same time it rotates to the right.

What I want to happen is for it to move forward only. How could I do that?

TIA.

Hi.

I am studying this project for my thesis.

I altered some parts and added some functionalities.

I made the car not to move automatically by adding another button for it to move and this: 

local onForwardController = function (event) if event.phase == "began" then CAR\_SPEED = 30 steeringAngle = 0 elseif event.phase == "ended" then CAR\_SPEED = 0 end

But when I make the car move, it moves forward and at the same time it rotates to the right.

What I want to happen is for it to move forward only. How could I do that?

TIA.