chipmunk-ffi 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +4 -3
- data/VERSION +1 -1
- data/chipmunk-ffi.gemspec +5 -3
- data/lib/chipmunk-ffi.rb +7 -2
- data/lib/chipmunk-ffi/body.rb +60 -2
- data/lib/chipmunk-ffi/constraint.rb +26 -0
- data/lib/chipmunk-ffi/constraints/damped_rotary_spring.rb +58 -0
- data/lib/chipmunk-ffi/constraints/damped_spring.rb +36 -2
- data/lib/chipmunk-ffi/constraints/gear_joint.rb +13 -1
- data/lib/chipmunk-ffi/constraints/groove_joint.rb +6 -1
- data/lib/chipmunk-ffi/constraints/pin_joint.rb +6 -1
- data/lib/chipmunk-ffi/constraints/pivot_joint.rb +6 -1
- data/lib/chipmunk-ffi/constraints/ratchet_joint.rb +6 -1
- data/lib/chipmunk-ffi/constraints/rotary_limit_joint.rb +6 -1
- data/lib/chipmunk-ffi/constraints/simple_motor.rb +6 -1
- data/lib/chipmunk-ffi/constraints/slide_joint.rb +6 -1
- data/lib/chipmunk-ffi/core.rb +1 -1
- data/lib/chipmunk-ffi/shape.rb +32 -3
- data/lib/chipmunk-ffi/space.rb +136 -54
- data/lib/chipmunk-ffi/space_hash.rb +2 -0
- data/lib/chipmunk-ffi/struct_accessor.rb +48 -0
- data/lib/chipmunk-ffi/vec2.rb +7 -1
- data/spec/body_spec.rb +44 -0
- data/spec/constraint_spec.rb +289 -1
- data/spec/shape_spec.rb +66 -1
- data/spec/space_spec.rb +70 -0
- data/spec/vec2_spec.rb +8 -1
- metadata +40 -21
@@ -10,10 +10,15 @@ module CP
|
|
10
10
|
func :cpSimpleMotorNew, [:pointer, :pointer, CP_FLOAT], :pointer
|
11
11
|
|
12
12
|
class SimpleMotor
|
13
|
-
|
13
|
+
include Constraint
|
14
|
+
struct_accessor SimpleMotorStruct, :rate
|
14
15
|
def initialize(a_body, b_body, rate)
|
16
|
+
@body_a, @body_b = a_body, b_body
|
15
17
|
@struct = SimpleMotorStruct.new(CP.cpSimpleMotorNew(
|
16
18
|
a_body.struct.pointer,b_body.struct.pointer,rate))
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
22
|
+
|
23
|
+
# Alias for compatibility with chipmunk C-Ruby bindings.
|
24
|
+
CP::Constraint::SimpleMotor = CP::SimpleMotor
|
@@ -18,10 +18,15 @@ module CP
|
|
18
18
|
func :cpSlideJointNew, [:pointer, :pointer, Vect.by_value, Vect.by_value, CP_FLOAT, CP_FLOAT], :pointer
|
19
19
|
|
20
20
|
class SlideJoint
|
21
|
-
|
21
|
+
include Constraint
|
22
|
+
struct_accessor SlideJointStruct, :anchr1, :anchr2, :min, :max
|
22
23
|
def initialize(a_body, b_body, anchr_one, anchr_two, min, max)
|
24
|
+
@body_a, @body_b = a_body, b_body
|
23
25
|
@struct = SlideJointStruct.new(CP.cpSlideJointNew(
|
24
26
|
a_body.struct.pointer,b_body.struct.pointer,anchr_one.struct,anchr_two.struct,min,max))
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
30
|
+
|
31
|
+
# Alias for compatibility with chipmunk C-Ruby bindings.
|
32
|
+
CP::Constraint::SlideJoint = CP::SlideJoint
|
data/lib/chipmunk-ffi/core.rb
CHANGED
@@ -30,7 +30,7 @@ module CP
|
|
30
30
|
|
31
31
|
func :cpMomentForSegment, [CP_FLOAT,Vect.by_value,Vect.by_value], CP_FLOAT
|
32
32
|
def self.moment_for_segment(m,v1,v2)
|
33
|
-
|
33
|
+
cpMomentForSegment(m, v1.struct, v2.struct)
|
34
34
|
end
|
35
35
|
|
36
36
|
func :cpMomentForPoly, [CP_FLOAT,:int,:pointer,Vect.by_value], CP_FLOAT
|
data/lib/chipmunk-ffi/shape.rb
CHANGED
@@ -51,6 +51,7 @@ module CP
|
|
51
51
|
func :cpResetShapeIdCounter, [], :void
|
52
52
|
func :cpShapePointQuery, [:pointer, Vect.by_value], :int
|
53
53
|
func :cpShapeSegmentQuery, [:pointer, Vect.by_value, Vect.by_value, :pointer], :int
|
54
|
+
func :cpPolyValidate, [:pointer, :int], :int
|
54
55
|
|
55
56
|
module Shape
|
56
57
|
class SegmentQueryInfo
|
@@ -200,6 +201,15 @@ module CP
|
|
200
201
|
include Shape
|
201
202
|
def initialize(body, verts, offset_vec)
|
202
203
|
@body = body
|
204
|
+
verts = CP::Shape::Poly.make_vertices_valid(verts)
|
205
|
+
mem_pointer = CP::Shape::Poly.pointer_for_verts(verts)
|
206
|
+
|
207
|
+
ptr = CP.cpPolyShapeNew body.struct.pointer, verts.size, mem_pointer, offset_vec.struct
|
208
|
+
@struct = ShapeStruct.new ptr
|
209
|
+
set_data_pointer
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.pointer_for_verts(verts)
|
203
213
|
mem_pointer = FFI::MemoryPointer.new Vect, verts.size
|
204
214
|
vert_structs = verts.collect{|s|s.struct}
|
205
215
|
|
@@ -209,9 +219,28 @@ module CP
|
|
209
219
|
tmp.send(:put_bytes, 0, i.to_bytes, 0, size)
|
210
220
|
tmp += size unless j == vert_structs.length-1 # avoid OOB
|
211
221
|
}
|
212
|
-
|
213
|
-
|
214
|
-
|
222
|
+
return mem_pointer
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.strictly_valid_vertices?(verts)
|
226
|
+
mem_pointer = CP::Shape::Poly.pointer_for_verts(verts)
|
227
|
+
result = CP.cpPolyValidate(mem_pointer,verts.size)
|
228
|
+
return (result != 0)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.valid_vertices?(verts)
|
232
|
+
CP::Shape::Poly.strictly_valid_vertices?(verts) ||
|
233
|
+
CP::Shape::Poly.strictly_valid_vertices?(verts.reverse)
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.make_vertices_valid(verts)
|
237
|
+
if CP::Shape::Poly.strictly_valid_vertices?(verts)
|
238
|
+
return verts
|
239
|
+
elsif CP::Shape::Poly.strictly_valid_vertices?(verts.reverse)
|
240
|
+
return verts.reverse
|
241
|
+
else
|
242
|
+
raise "Chipmunk-FFI Error: Vertices do not form convex polygon."
|
243
|
+
end
|
215
244
|
end
|
216
245
|
end
|
217
246
|
end
|
data/lib/chipmunk-ffi/space.rb
CHANGED
@@ -8,6 +8,7 @@ module CP
|
|
8
8
|
callback :cpCollisionPostSolveFunc, [:pointer,:pointer,:pointer], :int
|
9
9
|
callback :cpCollisionSeparateFunc, [:pointer,:pointer,:pointer], :int
|
10
10
|
callback :cpSpacePointQueryFunc, [:pointer,:pointer], :void
|
11
|
+
callback :cpSpaceSegmentQueryFunc, [:pointer, :float, Vect.by_value, :pointer], :void
|
11
12
|
|
12
13
|
class CollisionHandlerStruct < NiceFFI::Struct
|
13
14
|
layout(
|
@@ -26,6 +27,7 @@ module CP
|
|
26
27
|
:elastic_iterations, :int,
|
27
28
|
:gravity, Vect.by_value,
|
28
29
|
:damping, CP_FLOAT,
|
30
|
+
:locked, :int,
|
29
31
|
:stamp, :int,
|
30
32
|
:static_shapes, :pointer,
|
31
33
|
:active_shapes, :pointer,
|
@@ -42,7 +44,6 @@ module CP
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
|
46
47
|
func :cpSpaceNew, [], :pointer
|
47
48
|
func :cpSpaceFreeChildren, [:pointer], :void
|
48
49
|
|
@@ -71,7 +72,10 @@ module CP
|
|
71
72
|
func :cpSpacePointQuery, [:pointer, Vect.by_value, :uint, :uint, :cpSpacePointQueryFunc, :pointer], :pointer
|
72
73
|
func :cpSpacePointQueryFirst, [:pointer, Vect.by_value, :uint, :uint], :pointer
|
73
74
|
|
74
|
-
|
75
|
+
func :cpSpaceSegmentQuery, [:pointer, Vect.by_value, Vect.by_value, :uint, :uint, :cpSpaceSegmentQueryFunc, :pointer], :int
|
76
|
+
func :cpSpaceSegmentQueryFirst, [:pointer, Vect.by_value, Vect.by_value, :uint, :uint, :pointer], :pointer
|
77
|
+
|
78
|
+
class Space
|
75
79
|
attr_reader :struct
|
76
80
|
def initialize
|
77
81
|
@struct = SpaceStruct.new(CP.cpSpaceNew)
|
@@ -81,6 +85,7 @@ module CP
|
|
81
85
|
@constraints = []
|
82
86
|
@blocks = {}
|
83
87
|
@callbacks = {}
|
88
|
+
@test_callbacks = Hash.new {|h,k| h[k] = {:begin => nil, :pre => nil, :post => nil, :sep => nil}}
|
84
89
|
end
|
85
90
|
|
86
91
|
def iterations
|
@@ -111,58 +116,58 @@ module CP
|
|
111
116
|
@struct.gravity.pointer.put_bytes 0, v.struct.to_bytes, 0,Vect.size
|
112
117
|
end
|
113
118
|
|
114
|
-
def add_collision_func(a,b,&block)
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
end
|
158
|
-
|
159
|
-
def remove_collision_func(a,b)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
119
|
+
#def add_collision_func(a,b,&block)
|
120
|
+
# beg = nil
|
121
|
+
# pre = nil
|
122
|
+
# unless block.nil?
|
123
|
+
# pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
|
124
|
+
# begin
|
125
|
+
# arb = ArbiterStruct.new(arb_ptr)
|
126
|
+
#
|
127
|
+
# swapped = arb.swapped_col == 0 ? false : true
|
128
|
+
# arba = swapped ? arb.b : arb.a
|
129
|
+
# arbb = swapped ? arb.a : arb.b
|
130
|
+
#
|
131
|
+
# as = ShapeStruct.new(arba)
|
132
|
+
# a_obj_id = as.data.get_long 0
|
133
|
+
# rb_a = ObjectSpace._id2ref a_obj_id
|
134
|
+
#
|
135
|
+
# bs = ShapeStruct.new(arbb)
|
136
|
+
# b_obj_id = bs.data.get_long 0
|
137
|
+
# rb_b = ObjectSpace._id2ref b_obj_id
|
138
|
+
#
|
139
|
+
# block.call rb_a, rb_b
|
140
|
+
# 1
|
141
|
+
# rescue Exception => ex
|
142
|
+
# puts ex.message
|
143
|
+
# puts ex.backtrace
|
144
|
+
# 0
|
145
|
+
# end
|
146
|
+
# end
|
147
|
+
# else
|
148
|
+
# # needed for old chipmunk style
|
149
|
+
# pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
|
150
|
+
# 0
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
# post = nil
|
154
|
+
# sep = nil
|
155
|
+
# data = nil
|
156
|
+
# a_id = a.object_id
|
157
|
+
# b_id = b.object_id
|
158
|
+
# CP.cpSpaceAddCollisionHandler(@struct.pointer, a_id, b_id,
|
159
|
+
# beg,pre,post,sep,data)
|
160
|
+
# @blocks[[a_id,b_id]] = pre
|
161
|
+
# nil
|
162
|
+
#end
|
163
|
+
|
164
|
+
#def remove_collision_func(a,b)
|
165
|
+
# a_id = a.object_id
|
166
|
+
# b_id = b.object_id
|
167
|
+
# CP.cpSpaceRemoveCollisionHandler(@struct.pointer, a_id, b_id)
|
168
|
+
# @blocks.delete [a_id,b_id]
|
169
|
+
# nil
|
170
|
+
#end
|
166
171
|
|
167
172
|
def set_default_collision_func(&block)
|
168
173
|
raise "Not Implmented yet"
|
@@ -183,6 +188,7 @@ module CP
|
|
183
188
|
ret ? 1 : 0
|
184
189
|
end
|
185
190
|
@callbacks[[a,b,type]] = [handler,callback]
|
191
|
+
@test_callbacks[[a,b]][type] = callback
|
186
192
|
callback
|
187
193
|
end
|
188
194
|
|
@@ -201,6 +207,35 @@ module CP
|
|
201
207
|
a_id, b_id, beg,pre,post,sep,data)
|
202
208
|
end
|
203
209
|
|
210
|
+
def add_collision_func(a,b,type=:pre,&block)
|
211
|
+
arity = block.arity
|
212
|
+
callback = Proc.new do |arb_ptr,space_ptr,data_ptr|
|
213
|
+
arbiter = Arbiter.new(arb_ptr)
|
214
|
+
ret = case arity
|
215
|
+
when 1 then block.call(arbiter)
|
216
|
+
when 2 then block.call(*arbiter.shapes)
|
217
|
+
when 3 then block.call(arbiter,*arbiter.shapes)
|
218
|
+
else raise ArgumentError
|
219
|
+
end
|
220
|
+
ret ? 1 : 0
|
221
|
+
end
|
222
|
+
@test_callbacks[[a,b]][type] = callback
|
223
|
+
setup_callbacks(a,b)
|
224
|
+
end
|
225
|
+
|
226
|
+
def remove_collision_func(a,b,type=:pre)
|
227
|
+
@test_callbacks[[a,b]][type] = nil
|
228
|
+
setup_callbacks(a,b)
|
229
|
+
end
|
230
|
+
|
231
|
+
def setup_callbacks(a,b)
|
232
|
+
a_id = a.object_id
|
233
|
+
b_id = b.object_id
|
234
|
+
cbs = @test_callbacks[[a,b]]
|
235
|
+
CP.cpSpaceAddCollisionHandler(@struct.pointer,a_id,b_id,
|
236
|
+
cbs[:begin],cbs[:pre],cbs[:post],cbs[:sep],nil)
|
237
|
+
end
|
238
|
+
|
204
239
|
def add_shape(shape)
|
205
240
|
CP.cpSpaceAddShape(@struct.pointer, shape.struct.pointer)
|
206
241
|
@active_shapes << shape
|
@@ -307,6 +342,53 @@ module CP
|
|
307
342
|
CP.cpSpacePointQuery(@struct.pointer, point.struct, layers, group,query_proc,nil)
|
308
343
|
end
|
309
344
|
|
345
|
+
class SegmentQueryInfo
|
346
|
+
attr_reader :hit,:shape, :t, :n
|
347
|
+
def initialize(hit,shape,t=nil,n=nil,info=nil)
|
348
|
+
@hit = hit
|
349
|
+
@shape = shape
|
350
|
+
@t = t
|
351
|
+
@n = n
|
352
|
+
@info = info
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def shape_segment_query(a,b,layers=ALL_ONES,group=0)
|
357
|
+
segment_query_first(a,b,layers,group).shape
|
358
|
+
end
|
359
|
+
|
360
|
+
def info_segment_query(a,b,layers=ALL_ONES,group=0)
|
361
|
+
segment_query_first(a,b,layers,group)
|
362
|
+
end
|
363
|
+
|
364
|
+
def segment_query_first(a,b,layers,group)
|
365
|
+
out_ptr = FFI::MemoryPointer.new(SegmentQueryInfoStruct.size)
|
366
|
+
info = SegmentQueryInfoStruct.new out_ptr
|
367
|
+
|
368
|
+
shape_ptr = CP.cpSpaceSegmentQueryFirst(@struct.pointer, a.struct.pointer, b.struct.pointer,layers,group,out_ptr)
|
369
|
+
if shape_ptr.null?
|
370
|
+
SegmentQueryInfo.new(false,nil,nil,nil,info)
|
371
|
+
else
|
372
|
+
shape_struct = ShapeStruct.new(shape_ptr)
|
373
|
+
obj_id = shape_struct.data.get_long(0)
|
374
|
+
shape = ObjectSpace._id2ref(obj_id)
|
375
|
+
n_vec = Vec2.new(info.n)
|
376
|
+
SegmentQueryInfo.new(true,shape,info.t,n_vec,info)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def segment_query(a,b,layers,group,&block)
|
381
|
+
return nil unless block_given?
|
382
|
+
query_proc = Proc.new do |shape_ptr,t,n,data|
|
383
|
+
shape_struct = ShapeStruct.new(shape_ptr)
|
384
|
+
obj_id = shape_struct.data.get_long(0)
|
385
|
+
shape = ObjectSpace._id2ref(obj_id)
|
386
|
+
block.call(shape,t,n)
|
387
|
+
end
|
388
|
+
|
389
|
+
CP.cpSpaceSegmentQuery(@struct.pointer, a.struct, b.struct, layers, group, query_proc, nil)
|
390
|
+
end
|
391
|
+
|
310
392
|
end
|
311
393
|
end
|
312
394
|
|
@@ -8,8 +8,10 @@ module CP
|
|
8
8
|
:cell_dim, CP_FLOAT,
|
9
9
|
:bb_func, :cpSpaceHashBBFunc,
|
10
10
|
:handle_set, :pointer,
|
11
|
+
:pooled_handles, :pointer,
|
11
12
|
:table, :pointer,
|
12
13
|
:bins, :pointer,
|
14
|
+
:allocated_buffers, :pointer,
|
13
15
|
:stamp, :int)
|
14
16
|
end
|
15
17
|
func :cpSpaceHashNew, [CP_FLOAT,:int,:cpSpaceHashBBFunc], :pointer
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CP
|
2
|
+
module StructAccessor
|
3
|
+
private
|
4
|
+
|
5
|
+
def struct_reader(struct,*args)
|
6
|
+
raise(ArgumentError,"First argument must be an FFI::Struct subclass, got #{struct.inspect} instead.") unless struct < FFI::Struct
|
7
|
+
args.each {|attribute| add_struct_reader(struct,attribute) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def struct_writer(struct,*args)
|
11
|
+
raise(ArgumentError,"First argument must be an FFI::Struct subclass, got #{struct.inspect} instead.") unless struct < FFI::Struct
|
12
|
+
args.each {|attribute| add_struct_writer(struct,attribute) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def struct_accessor(struct,*args)
|
16
|
+
struct_reader(struct,*args)
|
17
|
+
struct_writer(struct,*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_struct_reader(struct,attribute)
|
21
|
+
type = resolve_type(struct,attribute)
|
22
|
+
if type == CP::Vect
|
23
|
+
define_method(attribute) { Vec2.new(self.struct[attribute]) }
|
24
|
+
else
|
25
|
+
define_method(attribute) { self.struct[attribute] }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_struct_writer(struct,attribute)
|
30
|
+
type = resolve_type(struct,attribute)
|
31
|
+
if type == CP::Vect
|
32
|
+
define_method("#{attribute}=") {|val| self.struct[attribute].pointer.put_bytes(0,val.struct.to_bytes,0,Vect.size) }
|
33
|
+
else
|
34
|
+
define_method("#{attribute}=") {|val| self.struct[attribute] = val }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def resolve_type(struct,attribute)
|
39
|
+
t = struct.layout[attribute].type
|
40
|
+
if t.is_a?(FFI::StructByValue)
|
41
|
+
t.struct_class
|
42
|
+
else
|
43
|
+
t
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/chipmunk-ffi/vec2.rb
CHANGED
@@ -195,9 +195,15 @@ module CP
|
|
195
195
|
CP::cpvlength @struct
|
196
196
|
end
|
197
197
|
|
198
|
+
def ==(other)
|
199
|
+
self.x == other.x && self.y == other.y
|
200
|
+
end
|
201
|
+
|
198
202
|
end
|
199
203
|
ZERO_VEC_2 = Vec2.new(0,0).freeze
|
200
|
-
|
204
|
+
def zero
|
205
|
+
ZERO_VEC_2
|
206
|
+
end
|
201
207
|
end
|
202
208
|
def vec2(x,y)
|
203
209
|
CP::Vec2.new x, y
|
data/spec/body_spec.rb
CHANGED
@@ -152,5 +152,49 @@ describe 'A new Body' do
|
|
152
152
|
b.v.x.should be_close(0.1,0.001)
|
153
153
|
b.v.y.should be_close(0,0.001)
|
154
154
|
end
|
155
|
+
|
156
|
+
it 'can get its velocity function' do
|
157
|
+
b = CP::Body.new(5, 7)
|
158
|
+
b.apply_impulse(vec2(1,0), ZERO_VEC_2)
|
159
|
+
b.velocity_func.call(b,vec2(0,0), 0.5, 25)
|
160
|
+
b.v.x.should be_close(0.1,0.001)
|
161
|
+
b.v.y.should be_close(0,0.001)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'can set its velocity function' do
|
165
|
+
b = CP::Body.new(5, 7)
|
166
|
+
|
167
|
+
b.velocity_func = Proc.new do |body,gravity,damping,dt|
|
168
|
+
d = body.p - vec2(5,5)
|
169
|
+
g = (d * (-500.0/(d.dot(d))))
|
170
|
+
body.update_velocity(g,damping,dt)
|
171
|
+
end
|
172
|
+
|
173
|
+
b.velocity_func.call(b,ZERO_VEC_2,0.5,25)
|
174
|
+
b.v.x.should be_close(1250.0,10)
|
175
|
+
b.v.y.should be_close(1250.0,10)
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'can get its position function' do
|
180
|
+
b = CP::Body.new(5, 7)
|
181
|
+
b.apply_impulse(vec2(1,0), ZERO_VEC_2)
|
182
|
+
b.position_func.call(b,25)
|
183
|
+
b.p.x.should be_close(5,0.001)
|
184
|
+
b.p.y.should be_close(0,0.001)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'can set its position function' do
|
188
|
+
b = CP::Body.new(5,7)
|
189
|
+
|
190
|
+
b.position_func = Proc.new do |body,dt|
|
191
|
+
body.p = vec2(5,5)
|
192
|
+
end
|
193
|
+
|
194
|
+
b.position_func.call(b,25)
|
195
|
+
b.p.should == vec2(5,5)
|
196
|
+
end
|
197
|
+
|
198
|
+
|
155
199
|
|
156
200
|
end
|