chipmunk-ffi 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|