From be264bd75505e8f1e18caab44d03bafb4fc5c0d3 Mon Sep 17 00:00:00 2001 From: philomory Date: Fri, 9 Apr 2010 10:51:04 -1000 Subject: [PATCH] Added accessors for a Body's velocity_func and position_func. --- lib/chipmunk-ffi/body.rb | 62 ++++++++++++++++++++++++++++++++++++++-- spec/body_spec.rb | 44 ++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/lib/chipmunk-ffi/body.rb b/lib/chipmunk-ffi/body.rb index 730972f..e2a0f5f 100644 --- a/lib/chipmunk-ffi/body.rb +++ b/lib/chipmunk-ffi/body.rb @@ -5,8 +5,8 @@ module CP class BodyStruct < NiceFFI::Struct layout( - :bodyVelocityFunc, :cpBodyVelocityFunc, - :bodyPositionFunc, :cpBodyPositionFunc, + :velocity_func, :cpBodyVelocityFunc, + :position_func, :cpBodyPositionFunc, :m, CP_FLOAT, :m_inv, CP_FLOAT, :i, CP_FLOAT, @@ -54,9 +54,12 @@ def initialize(*args) when 2 ptr = CP.cpBodyNew(*args) @struct = BodyStruct.new ptr + set_data_pointer else raise "wrong number of args for Body, got #{args.size}, but expected 2" end + set_default_velocity_lambda + set_default_position_lambda end def m @@ -194,5 +197,60 @@ def update_position(dt) CP.cpBodyUpdatePosition(@struct.pointer,dt) end + def velocity_func + @user_level_velocity_lambda + end + + def velocity_func=(l) + @user_level_velocity_lambda = l + + # We keep the lambda in an ivar to keep it from being GCed + @body_velocity_lambda = Proc.new do |body_ptr,g,dmp,dt| + body_struct = BodyStruct.new(body_ptr) + obj_id = body_struct.data.get_long(0) + body = ObjectSpace._id2ref(obj_id) + l.call(body,g,dmp,dt) + end + @struct.velocity_func = @body_velocity_lambda + end + + def position_func + @user_level_position_lambda + end + + def position_func=(l) + @user_level_position_lambda = l + + # We keep the lambda in an ivar to keep it from being GCed + @body_position_lambda = Proc.new do |body_ptr,dt| + body_struct = BodyStruct.new(body_ptr) + obj_id = body_struct.data.get_long(0) + body = ObjectSpace._id2ref(obj_id) + l.call(body,dt) + end + @struct.position_func = @body_position_lambda + end + + private + def set_data_pointer + mem = FFI::MemoryPointer.new(:long) + mem.put_long 0, object_id + # this is needed to prevent data corruption by GC + @body_pointer = mem + @struct.data = mem + end + + def set_default_velocity_lambda + @user_level_velocity_lambda = Proc.new do |body,g,dmp,dt| + body.update_velocity(g,dmp,dt) + end + end + + def set_default_position_lambda + @user_level_position_lambda = Proc.new do |body,dt| + body.update_position(dt) + end + end + end end diff --git a/spec/body_spec.rb b/spec/body_spec.rb index d760fb0..8765414 100644 --- a/spec/body_spec.rb +++ b/spec/body_spec.rb @@ -152,5 +152,49 @@ b.v.x.should be_close(0.1,0.001) b.v.y.should be_close(0,0.001) end + + it 'can get its velocity function' do + b = CP::Body.new(5, 7) + b.apply_impulse(vec2(1,0), ZERO_VEC_2) + b.velocity_func.call(b,vec2(0,0), 0.5, 25) + b.v.x.should be_close(0.1,0.001) + b.v.y.should be_close(0,0.001) + end + + it 'can set its velocity function' do + b = CP::Body.new(5, 7) + + b.velocity_func = Proc.new do |body,gravity,damping,dt| + d = body.p - vec2(5,5) + g = (d * (-500.0/(d.dot(d)))) + body.update_velocity(g,damping,dt) + end + + b.velocity_func.call(b,ZERO_VEC_2,0.5,25) + b.v.x.should be_close(1250.0,10) + b.v.y.should be_close(1250.0,10) + + end + + it 'can get its position function' do + b = CP::Body.new(5, 7) + b.apply_impulse(vec2(1,0), ZERO_VEC_2) + b.position_func.call(b,25) + b.p.x.should be_close(5,0.001) + b.p.y.should be_close(0,0.001) + end + + it 'can set its position function' do + b = CP::Body.new(5,7) + + b.position_func = Proc.new do |body,dt| + body.p = vec2(5,5) + end + + b.position_func.call(b,25) + b.p.should == vec2(5,5) + end + + end