I've just had a mess around and created a primitive 'Pong meets Breakout' in about an hour. It uses my Constructor library that my tute introduced. However, I've found that .pdf is lousy for copy+paste code, so I'll dupe the library here.
Save this as 'ODE_Object_Library.bb;
And here's the program...
I reuse the material names in the ODE_Object_Lib as I couldn't be bothered to change them, but in a proper program you'd obviously spend a little more time documenting and structuring the program.
Also note I use an array of objects and store index value to reference different ODE objects. This makes it easy to save and restore level data. I'm sure there's a squillion optimizations and improvements people can make, but it's nice to see how quick and straightforward it is to create a physics based game. There's really no excuse not to include physics in everything!!
Save this as 'ODE_Object_Library.bb;
Const RESOLUTION_SPHERE = 12 Const RESOLUTION_CYLINDER = 12 ; Enumerated types for materials Const CON_WOOD=1,CON_GOLD=2,CON_RUBBER=3 ; Enumerated Types for geometries Const GEOM_CUBE=1,GEOM_SPHERE=2,GEOM_CYLINDER=3 ; Constants for pointer and forces Global NUM_OBJECTS Global mat_wood.material, mat_gold.material, mat_rubber.material Global ODE_world, ODE_space, ODE_scenery_space, ODE_contactGroup Type vector Field x# Field y# Field z# End Type Type material Field index ; Index for determining type of material Field density# Field friction# Field restitution# End Type Type ODE_object Field body Field geom Field mesh Field mass Field mat.material End Type Type actor Field geom ; index of geometry type Field pos.vector Field rot.vector Field siz.vector Field mat ; matieral index End Type ; Define Material Properties mat_wood.material=New material mat_wood\index = CON_WOOD mat_wood\friction = 10.0 mat_wood\restitution = 0.4 mat_wood\density = 0.9 mat_gold.material=New material mat_gold\index = CON_GOLD mat_gold\friction = 3.0 mat_gold\restitution = 0.2 mat_gold\density = 10.0 mat_rubber.material=New material mat_rubber\index = CON_RUBBER mat_rubber\friction = 500.0 mat_rubber\restitution = 0.9 mat_rubber\density = 1.5 Function create_Box_Mesh(obj.ODE_object) obj\mesh=CreateCube() Select obj\mat\index Case CON_WOOD EntityColor obj\mesh,120,80,40 EntityShininess obj\mesh,0.2 Case CON_GOLD EntityColor obj\mesh,200,120,40 EntityShininess obj\mesh,0.95 Case CON_RUBBER EntityColor obj\mesh,70,70,80 EntityShininess obj\mesh,0.2 End Select End Function Function create_Sphere_Mesh(obj.ODE_object) obj\mesh=CreateSphere(RESOLUTION_SPHERE) Select obj\mat\index Case CON_WOOD EntityColor obj\mesh,120,80,40 EntityShininess obj\mesh,0.2 Case CON_GOLD EntityColor obj\mesh,200,120,40 EntityShininess obj\mesh,0.95 Case CON_RUBBER EntityColor obj\mesh,70,70,80 EntityShininess obj\mesh,0.2 End Select End Function Function create_Cylinder_Mesh(obj.ODE_object) obj\mesh=CreateCylinder(RESOLUTION_CYLINDER) Select obj\mat\index Case CON_WOOD EntityColor obj\mesh,120,80,40 EntityShininess obj\mesh,0.2 Case CON_GOLD EntityColor obj\mesh,200,120,40 EntityShininess obj\mesh,0.95 Case CON_RUBBER EntityColor obj\mesh,70,70,80 EntityShininess obj\mesh,0.2 End Select End Function Function create_Box(obj.ODE_object, x_pos#, y_pos#, z_pos#, width#, length#, depth#, x_rot#, y_rot#, z_rot#) obj\body=dBodyCreate(ODE_world) dMassSetBox(obj\mass,obj\mat\density, width, length, depth) dBodySetMass(obj\body,obj\mass) dBodySetRotation(obj\body, x_rot, y_rot, z_rot) dBodySetPosition(obj\body, x_pos, y_pos, z_pos) dBodySetAutoDisableFlag(obj\body,1) obj\geom=dCreateBox(ODE_space,width, length, depth) dGeomSetBody(obj\geom,obj\body) dGeomContactSetBounce(obj\geom,obj\mat\restitution) dGeomContactSetMu(obj\geom,obj\mat\friction) create_Box_Mesh(obj) ; Blitz box lengths 2x longer than ODE box length ScaleMesh obj\mesh,width/2,length/2,depth/2 End Function Function create_Rigid_Box(obj.ODE_object, x_pos#, y_pos#, z_pos#, width#, length#, depth#, x_rot#, y_rot#, z_rot#) obj\geom=dCreateBox(ODE_scenery_space,width, length, depth) dGeomSetRotation(obj\geom, x_rot, y_rot, z_rot) dGeomSetPosition(obj\geom, x_pos, y_pos, z_pos) ; Blitz box lengths 2x longer than ODE box length create_Box_Mesh(obj) ScaleMesh obj\mesh,width/2,length/2,depth/2 RotateEntity obj\mesh,dGeomGetPitch#(obj\geom),dGeomGetYaw#(obj\geom),dGeomGetRoll#(obj\geom) PositionEntity obj\mesh,dGeomGetPositionX#(obj\geom),dGeomGetPositionY#(obj\geom),dGeomGetPositionZ#(obj\geom) End Function Function create_Sphere(obj.ODE_object, x_pos#, y_pos#, z_pos#, radius#, x_rot#, y_rot#, z_rot#) obj\body=dBodyCreate(ODE_world) dMassSetSphere(obj\mass,obj\mat\density, radius) dBodySetMass(obj\body,obj\mass) dBodySetRotation(obj\body, x_rot, y_rot, z_rot) dBodySetPosition(obj\body, x_pos, y_pos, z_pos) dBodySetAutoDisableFlag(obj\body,1) obj\geom=dCreateSphere(ODE_space,radius) dGeomSetBody(obj\geom,obj\body) dGeomContactSetBounce(obj\geom,obj\mat\restitution) dGeomContactSetMu(obj\geom,obj\mat\friction) create_Sphere_Mesh(obj) ScaleMesh obj\mesh,radius,radius,radius End Function Function create_Rigid_Sphere(obj.ODE_object, x_pos#, y_pos#, z_pos#, radius#, x_rot#, y_rot#, z_rot#) obj\geom=dCreateSphere(ODE_scenery_space,radius) dGeomSetRotation(obj\geom, x_rot, y_rot, z_rot) dGeomSetPosition(obj\geom, x_pos, y_pos, z_pos) create_Sphere_Mesh(obj) ScaleMesh obj\mesh,radius,radius,radius RotateEntity obj\mesh,dGeomGetPitch#(obj\geom),dGeomGetYaw#(obj\geom),dGeomGetRoll#(obj\geom) PositionEntity obj\mesh,dGeomGetPositionX#(obj\geom),dGeomGetPositionY#(obj\geom),dGeomGetPositionZ#(obj\geom) End Function Function create_Cylinder(obj.ODE_object, x_pos#, y_pos#, z_pos#, radius#, length#, x_rot#, y_rot#, z_rot#) obj\body=dBodyCreate(ODE_world) ; dMassSetSphere(v,obj\mat\density, radius) dMassSetCylinder(obj\mass,obj\mat\density,1, radius,length) dBodySetMass(obj\body,obj\mass) dBodySetRotation(obj\body, x_rot, y_rot, z_rot) dBodySetPosition(obj\body, x_pos, y_pos, z_pos) dBodySetAutoDisableFlag(obj\body,1) obj\geom=dCreateCylinder(ODE_space,radius,length) dGeomSetBody(obj\geom,obj\body) dGeomContactSetBounce(obj\geom,obj\mat\restitution) dGeomContactSetMu(obj\geom,obj\mat\friction) ; Blitz cylinder mesh is 2x longer than ODE cylinder length create_Cylinder_Mesh(obj) ScaleMesh obj\mesh,radius,length/2,radius End Function Function create_Rigid_Cylinder(obj.ODE_object, x_pos#, y_pos#, z_pos#, radius#,length#, x_rot#, y_rot#, z_rot#) obj\geom=dCreateCylinder(ODE_scenery_space,radius,length) dGeomSetRotation(obj\geom, x_rot, y_rot, z_rot) dGeomSetPosition(obj\geom, x_pos, y_pos, z_pos) ; Blitz cylinder mesh is 2x longer than ODE cylinder length create_Cylinder_Mesh(obj) ScaleMesh obj\mesh,radius,length/2,radius RotateEntity obj\mesh,dGeomGetPitch#(obj\geom),dGeomGetYaw#(obj\geom),dGeomGetRoll#(obj\geom) PositionEntity obj\mesh,dGeomGetPositionX#(obj\geom),dGeomGetPositionY#(obj\geom),dGeomGetPositionZ#(obj\geom) End Function Function set_material(obj.ODE_object,m.material) obj\mat\index = m\index obj\mat\friction = m\friction obj\mat\density = m\density obj\mat\restitution = m\restitution End Function
And here's the program...
Include "JV-ode.bb" Include "ODE_Object_Library.bb" Graphics3D 800,600,0,0 HidePointer() Const FPS=60, GRAVITY#=-0.981 Const PERIOD=1000/FPS Const MAX_OBJECTS=50 index_ball=0 ; index for ball index_paddle1=0 ; Index for paddle 1 index_paddle2=0 ; index for paddle 2 Dim objects.ODE_object(MAX_OBJECTS) ODE_world=dWorldCreate() ODE_space=dHashSpaceCreate(0) ODE_scenery_space=dHashSpaceCreate(ODE_Space) ; Sub-space for static scenery ODE_contactGroup=dJointGroupCreate(0) dSetInternalContactSurfaceMode(1) ; Sets bounce value to Max(a,b) for collisions dSetInternalSpaceCollideMode(0) ; Turns off internal space collision ; Change Rubber Properties mat_rubber\friction = 0.0 mat_rubber\restitution = 1.0 mat_rubber\density = 5.0 ; Change 'wood' material properties for better racket friction mat_wood\friction = 40.0 mat_wood\restitution = 1.3 ; Adds energy per bounce mat_wood\density = 0.9 ; Change 'gold' material properties for better bricks mat_gold\friction = 5.0 mat_gold\restitution = 0.2 ; Adds energy per bounce mat_gold\density = 0.1 For n=0 To MAX_OBJECTS objects(n) = New ODE_object objects(n)\mass=dMassCreate() objects(n)\mat.material = New material Next ; initialise ODE objects array dWorldSetAutoDisableFlag(ODE_world,1) ; Turn on auto disable dWorldSetGravity(ODE_world,0,GRAVITY#,0) ; Gravity in m/s/s dWorldSetERP(ODE_world,0.5) ; Global 'error correction' dWorldSetCFM(ODE_world,0.000001) dContactSetMode(dContactBounce+dContactSlip1) dContactSetBounce(0.2) dContactSetMu(0.0) AmbientLight 128,148,168 light1=CreateLight() TurnEntity light1,45,40,0 LightColor light1,180,160,110 light2=CreateLight() TurnEntity light2,15,-40,0 LightColor light2,110,160,110 rostrum_pan=CreatePivot() rostrum_tilt=CreatePivot(rostrum_pan) camera=CreateCamera(rostrum_tilt) PointEntity rostrum_pan,camera PointEntity camera,rostrum_pan CameraZoom camera,3 PositionEntity camera,0,40,-80 RotateEntity camera,30,0,0 SeedRnd(MilliSecs()) ; Create Pong 'court' current_object=Create_Court() ; create Ball current_object=current_object+1 pos_x# = 3 pos_y# = 0.5 pos_z# = 3 siz_x# = 0.5 rot_x# = 0 rot_y# = 0 rot_z# = 0 set_material(objects(current_object),mat_rubber) create_Sphere(objects(current_object),pos_x,pos_y,pos_z,siz_x,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,220,220 ; Apply random force to sphere for initial movement dBodyAddForce(objects(current_object)\body,150+Rnd(-10,10),0,150+Rnd(-10,10)) index_ball=current_object ; create_paddle_1 current_object=current_object+1 pos_x# = 0 pos_y# = 1.5 pos_z# = -29 siz_x# = 5 siz_y# = 2.5 siz_z# = 2 rot_x# = 0 rot_y# = 0 rot_z# = 0 set_material(objects(current_object),mat_wood) create_Rigid_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,50,50,220 index_paddle1=current_object ; create_paddle_2 current_object=current_object+1 pos_x# = 0 pos_y# = 1.5 pos_z# = 29 siz_x# = 5 siz_y# = 2.5 siz_z# = 2 rot_x# = 0 rot_y# = 0 rot_z# = 0 set_material(objects(current_object),mat_wood) create_Rigid_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,50,220,50 index_paddle2=current_object ; Add bricks current_object=current_object+1 pos_x# = -9 pos_y# = 0.6 pos_z# = 0 siz_x# = 2 siz_y# = 1 siz_z# = 1 rot_x# = 0 rot_y# = 0 rot_z# = 0 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = -6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = -3 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 0 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 3 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 9 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = -7.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = -4.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = -1.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 1.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 4.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 current_object=current_object+1 pos_x# = 7.5 pos_y# = 1.6 set_material(objects(current_object),mat_gold) create_Box(objects(current_object),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(current_object)\mesh,220,50,50 NUM_objects=current_object ; Number of ODE objects in our array Floor.ODE_Object = New ODE_Object Floor\geom = dCreatePlane(ODE_space,0,1,0,0) Floor\mesh = CreatePlane() EntityColor Floor\mesh,120,120,120 MoveMouse GraphicsWidth()/2,GraphicsHeight()/2 player_x=MouseX() While Not KeyHit(1) ; Computer controlled paddle dGeomSetPosition objects(index_paddle2)\geom, dGeomGetPositionX(objects(index_ball)\geom), 1, 29 ; Player controlled paddle player_x=MouseX() set_paddle_position_from_2D(camera, objects(index_paddle1), MouseX(), 0, 3) ; Update objects For n=0 To NUM_OBJECTS If objects(n)\geom RotateEntity objects(n)\mesh,dGeomGetPitch#(objects(n)\geom),dGeomGetYaw#(objects(n)\geom),dGeomGetRoll#(objects(n)\geom) PositionEntity objects(n)\mesh,dGeomGetPositionX#(objects(n)\geom),dGeomGetPositionY#(objects(n)\geom),dGeomGetPositionZ#(objects(n)\geom) End If Next dSpaceCollide(ODE_space,ODE_world,ODE_contactGroup) dWorldQuickStep(ODE_world,0.10) dJointGroupEmpty(ODE_contactGroup) UpdateWorld RenderWorld Flip Wend dJointGroupDestroy(ODE_contactGroup) dSpaceDestroy(ODE_space) dWorldDestroy(ODE_world) dCloseODE() End Function Create_Court() ; Package court creation into a function to keep the main code tidy n=0 ; First object - left wall pos_x# = -20 pos_y# = 3 pos_z# = 0 siz_x# = 3 siz_y# = 6 siz_z# = 60 rot_x# = 0 rot_y# = 0 rot_z# = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,155,60,60 n=n+1 ; Second object - right wall pos_x = 20 pos_y = 3 pos_z = 0 siz_x = 3 siz_y = 6 siz_z = 60 rot_x = 0 rot_y = 0 rot_z = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,155,60,60 n=n+1 ; Third object - left back endpiece pos_x = -15 pos_y = 3 pos_z = 31.5 siz_x = 3 siz_y = 6 siz_z = 10 rot_x = 0 rot_y = 90 rot_z = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,60,155,60 n=n+1 ; Fourth object - right back endpiece pos_x = 15 pos_y = 3 pos_z = 31.5 siz_x = 3 siz_y = 6 siz_z = 10 rot_x = 0 rot_y = 90 rot_z = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,60,155,60 n=n+1 ; Fifth object - left back endpiece pos_x = -15 pos_y = 3 pos_z = -31.5 siz_x = 3 siz_y = 6 siz_z = 10 rot_x = 0 rot_y = 90 rot_z = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,60,60,155 EntityAlpha objects(n)\mesh,0.5 n=n+1 ; Sixth object - right back endpiece pos_x = 15 pos_y = 3 pos_z = -31.5 siz_x = 3 siz_y = 6 siz_z = 10 rot_x = 0 rot_y = 90 rot_z = 0 set_material(objects(n),mat_rubber) create_rigid_Box(objects(n),pos_x,pos_y,pos_z,siz_x,siz_y,siz_z,rot_x,rot_y,rot_z) EntityColor objects(n)\mesh,60,60,155 EntityAlpha objects(n)\mesh,0.5 Return n End Function Function set_paddle_position_from_2D(usecam, obj.ODE_object, x2d#, positionGlobal = 0, camZoom# = 1) gw = GraphicsWidth () gh = GraphicsHeight () x# = -((gw / 2) - x2d) y# = (gh / 2) - y2d parent = GetParent (obj\mesh) EntityParent obj\mesh, usecam z3d# = Abs (EntityZ(obj\mesh)) div# = (gw / (2 / camZoom)) / z3d PositionEntity obj\mesh, x / div, y / div, z3d, positionGlobal dGeomSetPosition (obj\geom,EntityX(obj\mesh,1),1, -29) EntityParent obj\mesh, parent End Function
I reuse the material names in the ODE_Object_Lib as I couldn't be bothered to change them, but in a proper program you'd obviously spend a little more time documenting and structuring the program.
Also note I use an array of objects and store index value to reference different ODE objects. This makes it easy to save and restore level data. I'm sure there's a squillion optimizations and improvements people can make, but it's nice to see how quick and straightforward it is to create a physics based game. There's really no excuse not to include physics in everything!!