Car Physics

Previous topic - Next topic

FutureCow

Many times I've had people on the street stop and ask me "Hey FutureCow - how do I do car physics in GLBasic?" My reply is always "I don't know, leave me alone - I'm on my lunchbreak!"  8)

I've just converted the code off the Blitz forums by Vorderman for car physics. I don't claim to be an expert in it. It needs tweaking before it could be used in a game (well, you could use it as is, but you'd have a lot of very slow moving cars...)

The original work doesn't have any licencing agreement listed, so to be on the safe side, it's probably best to credit Vorderman (James Kett) if you use it.

Arrows to move, space for handbrake.
Code (glbasic) Select

// --------------------------------- //
// Project: car physics
// Start: Friday, February 19, 2010
// IDE Version: 7.230

// Car Physics by Vorderman (James Kett) on the BlitzBasic forums.
// Translated to GLBasic by FutureCow (Shane Hockings)
//
// There are two versions of FUNC_do_physics included.
// original listing from Marco Monster's code. Use AS is AND retrieve CAR position x,y TO position car IN-game.
// second listing : tidied up physics routine with variable front/rear/4 wheel drive option and thus the ability to maintain drifts / slides.
//NOTE : FUNC_do_physics includes screen boundary checking AND looping right at the bottom of the function. You'll need TO change this FOR a 2D screen res other THEN 800,600 OR remove IF FOR 3d game.
//


//physics variables
GLOBAL delta_t# = 0.01
GLOBAL M_PI# = 3.1415926
GLOBAL DRAG# = 5.0
GLOBAL RESISTANCE# = 30.0
GLOBAL CA_R# = -5.20
GLOBAL CA_F# = -5.0
GLOBAL MAX_GRIP# = 2.0   
GLOBAL MULT# = 57
GLOBAL MULT2# = 0.01745

GLOBAL CAR1_cartype = 1
GLOBAL CAR1_cartype_b# = 1.0
GLOBAL CAR1_cartype_c# = 1.0
GLOBAL CAR1_cartype_wheelbase# = CAR1_cartype_b# + CAR1_cartype_c#
GLOBAL CAR1_cartype_h# = 1.0
GLOBAL CAR1_cartype_mass# = 1500
GLOBAL CAR1_cartype_inertia# = 1500
GLOBAL CAR1_cartype_width# = 1.5
GLOBAL CAR1_cartype_length# = 3.0
GLOBAL CAR1_cartype_wheellength# = 0.7
GLOBAL CAR1_cartype_wheelwidth# = 0.3
GLOBAL CAR1_car_position_wc_x# = 400.0
GLOBAL CAR1_car_position_wc_y# = 300.0
GLOBAL CAR1_car_velocity_wc_x# = 0
GLOBAL CAR1_car_velocity_wc_y# = 0
GLOBAL CAR1_car_angle# = 0
GLOBAL CAR1_car_angularvelocity# = 0
GLOBAL CAR1_car_steerangle# = 0
GLOBAL CAR1_car_throttle# = 0
GLOBAL CAR1_car_brake# = 0

GLOBAL front_slip = 0
GLOBAL rear_slip = 0

GLOBAL velocity_x#
GLOBAL velocity_y#
GLOBAL yawspeed#
GLOBAL sn#, cs#
GLOBAL xpos#, ypos#
GLOBAL rot_angle#
GLOBAL sideslip#
GLOBAL slipanglefront#
GLOBAL slipanglerear#
GLOBAL flatf_x#, flatf_y#
GLOBAL flatr_x#, flatr_y#
GLOBAL weight#
GLOBAL ftraction_x#, ftraction_y#
GLOBAL resistance_x#, resistance_y#
GLOBAL force_x#, force_y#
GLOBAL torque#
GLOBAL acceleration_x#, acceleration_y#, angular_acceleration#
GLOBAL acceleration_wc_x#, acceleration_wc_y#


//TYPE of car - 1=rear 2=front 3=four
GLOBAL CAR1_car_drivetype = 3

GOSUB Main

//######################################################################################################

SUB Main:
//Main loop
LOCAL Quit = 0
// WHILE ( KeyHit(1)=0 )
WHILE Quit = 0
//     Cls
IF KEY(1) = 1
Quit = 1
ENDIF

    FUNC_do_input()
   
    FUNC_do_physics()
       
//     Flip
SHOWSCREEN    
WEND
ENDSUB


//######################################################################################################


//INPUT routine from joystick/pad/wheel
FUNCTION FUNC_do_input:
//IF ( JoyYDir() = -1 )
IF KEY(200) = 1
CAR1_car_throttle# = 2000.0
ELSE
CAR1_car_throttle# = 0.0
ENDIF

//IF ( JoyYDir() = 0 )
// CAR1_car_throttle# = 0.0
// ENDIF

// IF ( JoyYDir() = 1 )
IF KEY(208) = 1
    CAR1_car_throttle# = 0.0
    CAR1_car_brake# = 100.0
ELSE
    CAR1_car_brake# = 0.0
ENDIF

CAR1_car_steerangle# = 0.0
// IF ( JoyXDir() = 1 )
IF KEY(205) = 1
CAR1_car_steerangle# = (-M_PI# / 4.0) * 0.15 //* MULT2#
ENDIF

// IF ( JoyXDir() = -1 )
IF KEY(203) = 1
CAR1_car_steerangle# = (M_PI# / 4.0) * 0.15 // MULT2#
ENDIF

rear_slip = 0
// IF ( JoyDown(1) )
IF KEY(57) = 1
rear_slip = 1
ENDIF

//temp display of vars
PRINT (CAR1_car_position_wc_x#),0,0
PRINT (CAR1_car_position_wc_y#),0,12
PRINT (CAR1_car_steerangle#),0,24

CAR1_car_angle#=CAR1_car_angle#+(CAR1_car_steerangle# * 0.25)

xpos# = CAR1_car_position_wc_x#
ypos# = CAR1_car_position_wc_y#

//render a small moving car rep.
renda1# =( -CAR1_car_angle# * MULT# ) - 60
IF (renda1#<0.0) THEN renda1#=360.0+renda1#
renda2# =( -CAR1_car_angle# * MULT# ) + 60
IF (renda2#>359.0) THEN renda2#=renda2#-360.0
renda3# =( -CAR1_car_angle# * MULT# ) - 120
IF (renda3#<0.0) THEN renda3#=360.0+renda3#
renda4# =( -CAR1_car_angle# * MULT# ) + 120
IF (renda4#>359.0) THEN renda4#=renda4#-360.0

rendx1#=25*COS(renda1#)
rendy1#=25*SIN(renda1#)

rendx2#=25*COS(renda2#)
rendy2#=25*SIN(renda2#)

rendx3#=25*COS(renda3#)
rendy3#=25*SIN(renda3#)

rendx4#=25*COS(renda4#)
rendy4#=25*SIN(renda4#)

DRAWLINE rendx1#+xpos#,rendy1#+ypos#,rendx2#+xpos#,rendy2#+ypos#,RGB(255,255,255)
DRAWLINE rendx2#+xpos#,rendy2#+ypos#,rendx4#+xpos#,rendy4#+ypos#,RGB(255,255,255)
DRAWLINE rendx4#+xpos#,rendy4#+ypos#,rendx3#+xpos#,rendy3#+ypos#,RGB(255,255,255)
DRAWLINE rendx3#+xpos#,rendy3#+ypos#,rendx1#+xpos#,rendy1#+ypos#,RGB(255,255,255)

ENDFUNCTION


//######################################################################################################

// Original FUNC_do_physics code

//
//FUNCTION FUNC_do_physics()
//
//    sn# = SIN(CAR1_car_angle# * MULT#) * MULT2#
//    cs# = COS(CAR1_car_angle# * MULT#) * MULT2#
//
//    Text 400,0,"sn="+Str(sn#)+" cs="+Str(cs#)
//
//     SAE convention: x is TO the front of the car, y is TO the Right, z is down
//     transform velocity IN world reference frame TO velocity IN car reference frame
//    velocity_x# = cs# * CAR1_car_velocity_wc_y# + sn# * CAR1_car_velocity_wc_x#
//    velocity_y# = -sn# * CAR1_car_velocity_wc_y# + cs# * CAR1_car_velocity_wc_x#
//
//     Lateral force on wheels
//     Resulting velocity of the wheels AS result of the yaw rate of the car body
//     v = yawrate * r where r is distance of wheel TO CG (approx. half wheel base)
//     yawrate (ang.velocity) must be IN rad/s
//    yawspeed# = CAR1_cartype_wheelbase# * 0.5 * CAR1_car_angularvelocity#
//
//    IF( velocity_x# = 0 )
//        rot_angle# = 0
//    ELSE
//        rot_angle# = ATan2( (yawspeed# * MULT#) , (velocity_x# * MULT#) )
//        rot_angle# = ATan2( (yawspeed# ) , (velocity_x#) ) * MULT2#
//    ENDIF
//
//     Calculate the side slip angle of the car (a.k.a. beta)
//    IF( velocity_x# = 0 )
//        sideslip# = 0.0
//    ELSE
//        sideslip# = ATan2( (velocity_y# * MULT#) , (velocity_x# * MULT#) )       
//        sideslip# = ATan2( (velocity_y# ) , (velocity_x#) )    * MULT2#   
//    ENDIF
//
//     Calculate slip angles FOR front AND rear wheels (a.k.a. alpha)
//    slipanglefront# = sideslip# + rot_angle# - CAR1_car_steerangle#
//    slipanglerear# = sideslip# - rot_angle#
//
//     weight per axle = half car mass times 1G (=9.8m/s^2)
//    weight# = CAR1_cartype_mass# * 9.8 * 0.5
//   
//     lateral force on front wheels = (Ca * slip angle) capped TO friction circle * load
//    flatf_x# = 0.0
//    flatf_y# = CA_F# * slipanglefront#
//
//    IF ( flatf_y# > MAX_GRIP# ) flatf_y# = MAX_GRIP#
//    IF ( flatf_y# < -MAX_GRIP# ) flatf_y# = -MAX_GRIP#
//
//    flatf_y# = flatf_y# * weight#
//   
//     allow front wheels TO slip
//    IF(front_slip=1) flatf_y# = flatf_y# * 0.5
//
//     lateral force on rear wheels
//    flatr_x# = 0.0
//    flatr_y# = CA_R# * slipanglerear#
//
//    IF ( flatr_y# > MAX_GRIP# ) flatr_y# = MAX_GRIP#
//    IF ( flatr_y# < -MAX_GRIP# ) flatr_y# = -MAX_GRIP#
//
//    flatr_y# = flatr_y# * weight#
//   
//    IF(rear_slip = 1) flatr_y# = flatr_y# * 0.5
//
//     longtitudinal force on rear wheels - very simple traction model
//    ftraction_x# = 100.0 * (CAR1_car_throttle# - CAR1_car_brake# * SGN(velocity_x#))
//    ftraction_y# = 0.0
//
//    IF(rear_slip = 1) ftraction_x# = ftraction_x# * 0.5
//
//     Forces AND torque on body
//     drag AND rolling resistance
//    resistance_x# = -( RESISTANCE# * velocity_x# + DRAG# * velocity_x# * ABS( velocity_x# ) )
//    resistance_y# = -( RESISTANCE# * velocity_y# + DRAG# * velocity_y# * ABS( velocity_y# ) )
//
//     sum forces
//    force_x# = ftraction_x# + (SIN( CAR1_car_steerangle# * MULT# )) * flatf_x# + flatr_x# + resistance_x#
//    force_y# = ftraction_y# + (COS( CAR1_car_steerangle# * MULT# )) * flatf_y# + flatr_y# + resistance_y#   
//
//     torque on body from lateral forces
//    torque# = CAR1_cartype_b# * flatf_y# - CAR1_cartype_c# * flatr_y#
//
//     Acceleration
//     Newton F = m.a, therefore a = F/m
//    acceleration_x# = force_x# / CAR1_cartype_mass#
//    acceleration_y# = force_y# / CAR1_cartype_mass#
//   
//    angular_acceleration# = torque# / CAR1_cartype_inertia#
//
//     Velocity AND position
//     transform acceleration from car reference frame TO world reference frame
//    acceleration_wc_x# = cs# * acceleration_y# + sn# * acceleration_x#
//    acceleration_wc_y# = -sn# * acceleration_y# + cs# * acceleration_x#
//
//     velocity is integrated acceleration
//    CAR1_car_velocity_wc_x# = CAR1_car_velocity_wc_x# + (delta_t# * acceleration_wc_x#)
//    CAR1_car_velocity_wc_y# = CAR1_car_velocity_wc_y# + (delta_t# * acceleration_wc_y#)
//
//     position is integrated velocity
//    CAR1_car_position_wc_x# = CAR1_car_position_wc_x# + (delta_t# * CAR1_car_velocity_wc_x#)
//    CAR1_car_position_wc_y# = CAR1_car_position_wc_y# + (delta_t# * CAR1_car_velocity_wc_y#)
//
//     Angular velocity AND heading
//     integrate angular acceleration TO get angular velocity
//    CAR1_car_angularvelocity# = CAR1_car_angularvelocity# + (delta_t# * angular_acceleration#)
//
//     integrate angular velocity TO get angular orientation
//    CAR1_car_angle# = CAR1_car_angle# + (delta_t# * CAR1_car_angularvelocity#)
//
//    IF ( CAR1_car_position_wc_x# < 0.0 ) CAR1_car_position_wc_x# = 800.0
//    IF ( CAR1_car_position_wc_x# > 800.0 ) CAR1_car_position_wc_x# = 0.0
//    IF ( CAR1_car_position_wc_y# < 0.0 ) CAR1_car_position_wc_y# = 600.0
//    IF ( CAR1_car_position_wc_y# > 600.0 ) CAR1_car_position_wc_y# = 0.0
//   
//END FUNCTION
//








FUNCTION FUNC_do_physics:
    // SAE convention: x is TO the front of the car, y is TO the Right, z is down
    //--------------------------
    // TRANSFORM VELOCITY
    //--------------------------
        // transform velocity IN world reference frame TO velocity IN car reference frame
        sn# = SIN(CAR1_car_angle# * MULT#)// * MULT2#
        cs# = COS(CAR1_car_angle# * MULT#) //* MULT2#
        velocity_x# = cs# * CAR1_car_velocity_wc_y# + sn# * CAR1_car_velocity_wc_x#
        velocity_y# = -sn# * CAR1_car_velocity_wc_y# + cs# * CAR1_car_velocity_wc_x#


    //--------------------------
    // LATERAL FORCES ON WHEELS
    //--------------------------
        // Resulting velocity of the wheels AS result of the yaw rate of the car body
        // v = yawrate * r where r is distance of wheel TO CG (approx. half wheel base)
        // yawrate (ang.velocity) must be IN rad/s

        // 0.5 IN this line becomes front/rear pos of COG - alter this later
        yawspeed# = CAR1_cartype_wheelbase# * 0.5 * CAR1_car_angularvelocity#
        IF( velocity_x# = 0 )
            rot_angle# = 0
        ELSE
//            rot_angle# = ATan2( (yawspeed# ) , (velocity_x#) ) * MULT2#
            rot_angle# = ATAN( (yawspeed# ) , (velocity_x#) ) * MULT2#
        ENDIF


    //-------------------------
    // SIDESLIP ANGLE
    //-------------------------
        // Calculate the side slip angle of the car (a.k.a. beta)
        IF( velocity_x# = 0 )
            sideslip# = 0.0
        ELSE
//            sideslip# = ATan2( (velocity_y# ) , (velocity_x#) )    * MULT2#   
            sideslip# = ATAN( (velocity_y# ) , (velocity_x#) )    * MULT2#   
        ENDIF


    //-------------------------
    // SLIP ANGLES FRONT/REAR
    //-------------------------
        // Calculate slip angles FOR front AND rear wheels (a.k.a. alpha)
        slipanglefront# = sideslip# + rot_angle# - CAR1_car_steerangle#
        slipanglerear# = (sideslip# - rot_angle#)


    //-------------------------
    // WEIGHT PER AXLE
    //-------------------------
        // weight per axle = half car mass times 1G (=9.8m/s^2)
        // need TO split this into front AND rear masses - according TO position of COG
        weight# = CAR1_cartype_mass# * 9.8 * 0.5


    //--------------------------
    // LATERAL FORCES ON WHEELS
    //--------------------------
        // (Ca * slip angle) capped TO friction circle * load
        flatf_x# = 0.0
        flatr_x# = 0.0

        //check FOR front / rear / 4 wheel drive
        IF ( CAR1_car_drivetype = 1 )

            //rear wheel drive
            flatr_y# = CA_R# * slipanglerear# / ((CAR1_car_throttle# / 5000.0)+1)
            flatf_y# = CA_F# * slipanglefront#

        ELSEIF ( CAR1_car_drivetype = 2 )

            //front wheel drive
            flatr_y# = CA_R# * slipanglerear#
            flatf_y# = CA_F# * slipanglefront# / ((CAR1_car_throttle# / 5000.0)+1)

        ELSEIF ( CAR1_car_drivetype = 3 )
   
            //4 wheel drive
            flatr_y# = CA_R# * slipanglerear# / ((CAR1_car_throttle# / 5000.0)+1)
            flatf_y# = CA_F# * slipanglefront# / ((CAR1_car_throttle# / 5000.0)+1)
       
        ENDIF
           
        flatf_y# = flatf_y# * weight#
        flatr_y# = flatr_y# * weight#

        // allow FOR handbrake / reduced grip levels - use this FOR different surfaces later   
        IF (front_slip=1)
        flatf_y# = flatf_y# * 0.5
        ENDIF
       
        IF (rear_slip = 1)
        flatr_y# = flatr_y# * 0.5
        ENDIF


    //-----------------------------
    // LONGITUDINAL FORCES
    //-----------------------------
        // longtitudinal force on rear wheels - very simple traction model
        ftraction_x# = 100.0 * (CAR1_car_throttle# - CAR1_car_brake# * SGN(velocity_x#))
        ftraction_y# = 0.0

        // allow FOR handbrake
        IF (rear_slip = 1)
        ftraction_x# = ftraction_x# * 0.5
        ENDIF



    //-------------------------------
    // SUM FORCES AND TORQUE ON BODY
    //-------------------------------
        // drag AND rolling resistance
        resistance_x# = -( RESISTANCE# * velocity_x# + DRAG# * velocity_x# * ABS( velocity_x# ) )
        resistance_y# = -( RESISTANCE# * velocity_y# + DRAG# * velocity_y# * ABS( velocity_y# ) )

        // sum forces
        force_x# = ftraction_x# + (SIN( CAR1_car_steerangle# * MULT# )) * flatf_x# + flatr_x# + resistance_x#
        force_y# = ftraction_y# + (COS( CAR1_car_steerangle# * MULT# )) * flatf_y# + flatr_y# + resistance_y#   

       
        // torque on body from lateral forces
        torque# = CAR1_cartype_b# * flatf_y# - CAR1_cartype_c# * flatr_y#

        // Acceleration - Newton F = m.a, therefore a = F/m
        acceleration_x# = force_x# / CAR1_cartype_mass#
        acceleration_y# = force_y# / CAR1_cartype_mass#
   
        // angular acceleration around COG
        angular_acceleration# = torque# / CAR1_cartype_inertia#

        // Velocity AND position
        // transform acceleration from car reference frame TO world reference frame
        acceleration_wc_x# = cs# * acceleration_y# + sn# * acceleration_x#
        acceleration_wc_y# = -sn# * acceleration_y# + cs# * acceleration_x#

        // velocity is integrated acceleration
        CAR1_car_velocity_wc_x# = CAR1_car_velocity_wc_x# + (delta_t# * acceleration_wc_x#)
        CAR1_car_velocity_wc_y# = CAR1_car_velocity_wc_y# + (delta_t# * acceleration_wc_y#)

        // position is integrated velocity
        CAR1_car_position_wc_x# = CAR1_car_position_wc_x# + (delta_t# * CAR1_car_velocity_wc_x#)
        CAR1_car_position_wc_y# = CAR1_car_position_wc_y# + (delta_t# * CAR1_car_velocity_wc_y#)

        // Angular velocity AND heading
        // integrate angular acceleration TO get angular velocity
        CAR1_car_angularvelocity# = CAR1_car_angularvelocity# + (delta_t# * angular_acceleration#)

        // move COG left / right according TO body's angular rotation
        CAR1_car_COGx# = (CAR1_car_angularvelocity# * 10.0)
        CAR1_car_COGy# = CAR1_car_throttle# / 100.0
       
        // integrate angular velocity TO get angular orientation
        CAR1_car_angle# = CAR1_car_angle# + (delta_t# * CAR1_car_angularvelocity#)






    //TEMP - SCREEN LIMITS
    IF ( CAR1_car_position_wc_x# < 0.0 )
    CAR1_car_position_wc_x# = 800.0
    ENDIF
    IF ( CAR1_car_position_wc_x# > 800.0 )
    CAR1_car_position_wc_x# = 0.0
    ENDIF
    IF ( CAR1_car_position_wc_y# < 0.0 )
    CAR1_car_position_wc_y# = 600.0
    ENDIF
    IF ( CAR1_car_position_wc_y# > 600.0 )
    CAR1_car_position_wc_y# = 0.0
    ENDIF
ENDFUNCTION


Kitty Hello

Oh wow! That's sophisticated stuff.
Excellent Work!

FutureCow

#2
I'm planning on trying to implement it into a car game for my next project. Fingers crossed I can do something good with it!  :)

FutureCow

My answer to that is...

err...


um....



Maybe?  =D

FutureCow

Hmm... Might need more conversion then. I just replaced commands with equivalent ones until it worked ;D
Is the degrees/radians conversion going to make a big difference? It looks like it works like it's supposed to...
Maybe I'll crank up the original version in Blitz (if I can find where it is on my computer) and see if it "plays" any differently.

FutureCow

#5
I haven't dealt with this sort of stuff since high school days. I've done some digging though so I understand what you're talking about now (1 radian = ~57 degrees - so the results are a littttttle bit different).
Having said that though, Blitz also works in degrees. The code seems to do all the conversions to radians so everything looks fine to me.