[ODE] dBodyAddForce / dBodyAddTorque don't do anything!
Richard Jones
rich at annexia.org
Tue Jun 21 15:49:13 MST 2005
Hi:
I'm doing some bindings for ODE to the Objective CAML language.
As part of these bindings, I'm doing a simple wireframe-only
"roll-em-up" game (think Katamari Damashii for those familiar with
that game), which will just form an example for how to use the
library.
So far it's going quite well - the ball falls down, bounces off
scenery and so on. However I cannot get dBodyAddForce,
dBodyAddTorque, dBodyAddRelForce or dBodyAddRelTorque to do anything
at all. Even when I set the fx/fy/fz to wild numbers, the ball isn't
affected. I've added debugging print statements to the low level
bindings which prove that the C function actually gets called and with
the right parameters.
It seems unlikely that dBodyAddForce, etc. are actually broken. So
can anyone suggest what I'm doing wrong?
Rich.
----------------------------------------------------------------------
(* Toy wireframe version of Katamari Damashii.
* Copyright (C) 2005 Richard W.M. Jones <rich at annexia.org>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*)
open Printf
open ExtList
open Ode.LowLevel
let width, height = 640, 480
(* Stepsize for physics (in secs). *)
let stepsize = 0.005
(* Real time / Physics time. If set to 1., then physics proceeds at the
* same pace as real time. If > 1, then physics is slowed down.
*)
let timescale = 4.
let initial = 0., 0., 1. (* Initial position for katamari. *)
let eye = ref (0., -2., 1.) (* Camera location. *)
let up = ref (0., 1., 2.) (* Up vector. *)
let center = ref (0., 0., 0.5) (* Center of camera. *)
let init_gl () =
GlDraw.viewport ~x:0 ~y:0 ~w:width ~h:height;
GlClear.color (0.9375, 0., 1.);
GlClear.depth 1.0;
GlFunc.depth_func `less;
Gl.enable `depth_test;
GlDraw.shade_model `smooth;
GlMat.mode `projection;
GlMat.load_identity ();
GluMat.perspective ~fovy:45. ~aspect:(float width /. float height)
~z:(0.1, 100.);
GlMat.mode `modelview
let draw_scene kata boxes =
GlClear.clear [ `color; `depth ];
(* Camera. *)
GlMat.load_identity ();
GluMat.look_at ~eye:!eye ~center:!center ~up:!up;
(* Katamari. *)
GlMat.push ();
let x, y, z = dGeomGetPosition kata in
let r = dGeomGetRotation kata in
let matrix = [|
[| r.r11; r.r21; r.r31; 0. |];
[| r.r12; r.r22; r.r32; 0. |];
[| r.r13; r.r23; r.r33; 0. |];
[| x; y; z; 1. |]
|] in
GlMat.mult (GlMat.of_array matrix);
let radius = dGeomSphereGetRadius kata in
Glut.wireSphere ~radius ~slices:10 ~stacks:10;
GlMat.pop ();
(* Boxes. *)
let draw_box box =
GlMat.push ();
let x, y, z = dGeomGetPosition box in
GlMat.translate ~x ~y ~z ();
let lx, ly, lz = dGeomBoxGetLengths box in
GlMat.scale ~x:lx ~y:ly ~z:lz ();
Glut.wireCube ~size:1.;
GlMat.pop ();
in
Array.iter draw_box boxes;
Sdlgl.swap_buffers ()
(* Surface parameters used for all contact points. *)
let surface_params = {
sp_mode = [`dContactBounce];
sp_mu = dInfinity; sp_mu2 = 0.;
sp_bounce = 0.7; sp_bounce_vel = 0.1;
sp_soft_erp = 0.; sp_soft_cfm = 0.;
sp_motion1 = 0.; sp_motion2 = 0.;
sp_slip1 = 0.; sp_slip2 = 0.;
}
let main () =
Random.self_init ();
(* Initialise SDL. *)
Sdl.init [`VIDEO];
Sdlgl.set_attr [];
let surface = Sdlvideo.set_video_mode ~w:width ~h:height ~bpp:32 [`OPENGL] in
(* Create the ODE world. *)
let ode = dWorldCreate () in
dWorldSetGravity ode ~x:0. ~y:0. ~z:(-9.81);
(* Create the objects in the world. *)
let space = dHashSpaceCreate None in
dHashSpaceSetLevels space (-4) 4; (* 1/16 .. 16 units. *)
(* The ground plane goes through the world origin, with the normal
* facing upwards towards +z.
*)
let plane = dCreatePlane (Some space) ~a:0. ~b:0. ~c:1. ~d:0. in
(* Create the katamari. *)
let kata, kata_body =
let radius = 0.5 in
let body = dBodyCreate ode in
dBodySetAutoDisableFlag body false;
let mass = dMassCreate () in
dMassSetZero mass;
dMassSetSphereTotal mass ~total_mass:1. ~radius;
dBodySetMass body mass;
dMassDestroy mass;
let kata = dCreateSphere (Some space) ~radius in
dGeomSetBody kata body;
let x, y, z = initial in
dGeomSetPosition kata ~x ~y ~z;
kata, body in
(* Scatter boxes around. *)
let boxes =
let create_box i =
let lx, ly, lz = Random.float 0.5, Random.float 0.5, Random.float 0.5 in
let box = dCreateBox (Some space) ~lx ~ly ~lz in
let x, y, z = Random.float 10. -. 5., Random.float 10. -. 5., lz/.2. in
dGeomSetPosition box ~x ~y ~z;
box
in
Array.init 20 (fun i -> create_box i) in
(* A group to hold the contact joints. *)
let contact_joint_group = dJointGroupCreate () in
(* Initialise GL state. *)
init_gl ();
(* Current key state. *)
let key_forward = ref false in
let key_backward = ref false in
let key_left = ref false in
let key_right = ref false in
(* Start the clocks counting. *)
let current_time =
let base = Unix.gettimeofday () in
fun () ->
Unix.gettimeofday () -. base
in
(* "Physics time" starts off coincident with real time. *)
let physics_time = ref 0. in
let rec main_loop () =
(* Draw it. *)
draw_scene kata boxes;
(* Act on events. *)
let quit = ref false in
let rec read_events () =
match Sdlevent.poll () with
| None -> ()
| Some event -> do_event event; read_events ()
and do_event = function
| Sdlevent.QUIT -> quit := true (* window closed: quit *)
| Sdlevent.KEYDOWN ke ->
(match ke.Sdlevent.keysym with
| Sdlkey.KEY_ESCAPE -> quit := true (* escape key: quit *)
| Sdlkey.KEY_UP -> key_forward := true
| Sdlkey.KEY_DOWN -> key_backward := true
| Sdlkey.KEY_LEFT -> key_left := true
| Sdlkey.KEY_RIGHT -> key_right := true
| _ -> read_events () (* ignore this key *)
)
| Sdlevent.KEYUP ke ->
(match ke.Sdlevent.keysym with
| Sdlkey.KEY_UP -> key_forward := false
| Sdlkey.KEY_DOWN -> key_backward := false
| Sdlkey.KEY_LEFT -> key_left := false
| Sdlkey.KEY_RIGHT -> key_right := false
| _ -> read_events () (* ignore this key *)
)
| _ -> () (* ignore this event *)
in
read_events ();
let quit = !quit in
(* Run the physics loop until we catch up with real time. *)
let rec physics_loop to_time =
if timescale *. !physics_time < to_time then (
let nr_contacts = ref 0 in
(* Accumulate forces on the katamari according to the current
* key states.
*)
if !key_forward then
dBodyAddTorque kata_body ~fx:0. ~fy:1. ~fz:0.;
if !key_backward then
dBodyAddTorque kata_body ~fx:0. ~fy:(-0.7) ~fz:0.;
(* Collision detection. *)
let near geom1 geom2 =
(* geom1 and geom2 are close. Test if they collide. *)
let contacts = dCollide geom1 geom2 ~max:4 in
if Array.length contacts > 0 then (
(* Get the bodies, if any. *)
let body1 = dGeomGetBody geom1 in
let body2 = dGeomGetBody geom2 in
(* For each collision, create a contact joint. *)
Array.iter (
fun contact_geom ->
incr nr_contacts;
(* Create the contact joint. *)
let contact = {
c_surface = surface_params;
c_geom = contact_geom;
c_fdir1 = { x = 0.; y = 0.; z = 0. }
} in
let joint =
dJointCreateContact ode (Some contact_joint_group) contact in
(* Attach that joint to the two bodies. The bodies may be
* 'None' indicating a collision with the static world, but
* that's OK.
*)
dJointAttach joint body1 body2
) contacts
)
in
dSpaceCollide space near;
(* Take a simulation step. *)
dWorldQuickStep ode stepsize;
physics_time := !physics_time +. stepsize;
(* Remove and destroy the contact joints. *)
dJointGroupEmpty contact_joint_group;
physics_loop to_time
)
in
physics_loop (current_time ());
(* Run the garbage collector at a predictable point. *)
Gc.full_major ();
(* Loop unless user has quit. *)
if not quit then main_loop ()
in
main_loop ();
(* Clean up the world. *)
dGeomDestroy plane;
dSpaceDestroy space;
(* Destroy the ODE world and clean up. *)
dWorldDestroy ode;
dCloseODE ();
(* Quit SDL. *)
Sdl.quit ();
(* Find any memory allocation bugs. *)
Gc.full_major ()
let () =
main ()
--
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com
More information about the ODE
mailing list