chipmunk-ffi 0.2.1 → 1.0.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 +36 -0
- data/Rakefile +12 -6
- data/VERSION +1 -1
- data/chipmunk-ffi.gemspec +25 -5
- data/lib/chipmunk-ffi.rb +1 -1
- data/lib/chipmunk-ffi/arbiter.rb +108 -0
- data/lib/chipmunk-ffi/body.rb +38 -6
- data/lib/chipmunk-ffi/core.rb +6 -3
- data/lib/chipmunk-ffi/shape.rb +48 -6
- data/lib/chipmunk-ffi/space.rb +52 -44
- data/lib/chipmunk-ffi/space_hash.rb +63 -0
- data/lib/chipmunk-ffi/unsafe.rb +47 -0
- data/lib/chipmunk-ffi/vec2.rb +38 -21
- data/spec/body_spec.rb +117 -12
- data/spec/perf.rb +36 -0
- data/spec/shape_spec.rb +45 -3
- data/spec/space_hash_spec.rb +54 -0
- data/spec/space_spec.rb +73 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unsafe_spec.rb +36 -0
- data/spec/vec2_spec.rb +100 -13
- metadata +34 -4
data/lib/chipmunk-ffi/space.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
module CP
|
2
|
+
# used for layers; will only work on 32 bit values
|
3
|
+
# (chipmunk cheats and sets these to -1)
|
4
|
+
ALL_ONES = 2**32-1
|
5
|
+
|
2
6
|
callback :cpCollisionBeginFunc, [:pointer,:pointer,:pointer], :int
|
3
7
|
callback :cpCollisionPreSolveFunc, [:pointer,:pointer,:pointer], :int
|
4
8
|
callback :cpCollisionPostSolveFunc, [:pointer,:pointer,:pointer], :int
|
5
9
|
callback :cpCollisionSeparateFunc, [:pointer,:pointer,:pointer], :int
|
10
|
+
callback :cpSpacePointQueryFunc, [:pointer,:pointer], :void
|
6
11
|
|
7
12
|
class CollisionHandlerStruct < NiceFFI::Struct
|
8
13
|
layout(
|
@@ -16,22 +21,6 @@ module CP
|
|
16
21
|
)
|
17
22
|
end
|
18
23
|
|
19
|
-
class ArbiterStruct < NiceFFI::Struct
|
20
|
-
layout(
|
21
|
-
:num_contacts, :int,
|
22
|
-
:contacts, :pointer,
|
23
|
-
:a, :pointer,
|
24
|
-
:b, :pointer,
|
25
|
-
:e, CP_FLOAT,
|
26
|
-
:u, CP_FLOAT,
|
27
|
-
:surf_vr, Vect.by_value,
|
28
|
-
:stamp, :int,
|
29
|
-
:handler, :pointer,
|
30
|
-
:swapped_col, :char,
|
31
|
-
:first_col, :char
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
24
|
class SpaceStruct < NiceFFI::Struct
|
36
25
|
layout( :iterations, :int,
|
37
26
|
:elastic_iterations, :int,
|
@@ -79,6 +68,8 @@ module CP
|
|
79
68
|
:cpCollisionBeginFunc, :cpCollisionPreSolveFunc, :cpCollisionPostSolveFunc, :cpCollisionSeparateFunc, :pointer], :void
|
80
69
|
func :cpSpaceRemoveCollisionHandler, [:pointer, :uint, :uint], :void
|
81
70
|
|
71
|
+
func :cpSpacePointQuery, [:pointer, Vect.by_value, :uint, :uint, :cpSpacePointQueryFunc, :pointer], :pointer
|
72
|
+
func :cpSpacePointQueryFirst, [:pointer, Vect.by_value, :uint, :uint], :pointer
|
82
73
|
|
83
74
|
class Space
|
84
75
|
attr_reader :struct
|
@@ -133,11 +124,11 @@ module CP
|
|
133
124
|
arbb = swapped ? arb.a : arb.b
|
134
125
|
|
135
126
|
as = ShapeStruct.new(arba)
|
136
|
-
a_obj_id = as.data.
|
127
|
+
a_obj_id = as.data.get_long 0
|
137
128
|
rb_a = ObjectSpace._id2ref a_obj_id
|
138
129
|
|
139
130
|
bs = ShapeStruct.new(arbb)
|
140
|
-
b_obj_id = bs.data.
|
131
|
+
b_obj_id = bs.data.get_long 0
|
141
132
|
rb_b = ObjectSpace._id2ref b_obj_id
|
142
133
|
|
143
134
|
block.call rb_a, rb_b
|
@@ -179,27 +170,17 @@ module CP
|
|
179
170
|
end
|
180
171
|
|
181
172
|
def wrap_collision_callback(a,b,type,handler)
|
173
|
+
arity = handler.method(type).arity
|
182
174
|
callback = Proc.new do |arb_ptr,space_ptr,data_ptr|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
a_obj_id = as.data.get_ulong 0
|
191
|
-
rb_a = ObjectSpace._id2ref a_obj_id
|
192
|
-
|
193
|
-
bs = ShapeStruct.new(arbb)
|
194
|
-
b_obj_id = bs.data.get_ulong 0
|
195
|
-
rb_b = ObjectSpace._id2ref b_obj_id
|
196
|
-
|
197
|
-
ret = handler.send type, rb_a, rb_b
|
198
|
-
if ret
|
199
|
-
1
|
200
|
-
else
|
201
|
-
0
|
175
|
+
arbiter = Arbiter.new(arb_ptr)
|
176
|
+
|
177
|
+
ret = case arity
|
178
|
+
when 1 then handler.send type, arbiter
|
179
|
+
when 2 then handler.send type, *arbiter.shapes
|
180
|
+
when 3 then handler.send type, arbiter, *arbiter.shapes
|
181
|
+
else raise ArgumentError
|
202
182
|
end
|
183
|
+
ret ? 1 : 0
|
203
184
|
end
|
204
185
|
@callbacks[[a,b,type]] = [handler,callback]
|
205
186
|
callback
|
@@ -284,20 +265,47 @@ module CP
|
|
284
265
|
CP.cpSpaceStep @struct.pointer, dt
|
285
266
|
end
|
286
267
|
|
287
|
-
def
|
288
|
-
|
268
|
+
def each_body(&block)
|
269
|
+
@bodies.each &block
|
270
|
+
# typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
|
271
|
+
# void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
|
272
|
+
end
|
273
|
+
|
274
|
+
def shape_point_query(pt)
|
275
|
+
point_query_first pt, ALL_ONES, 0
|
289
276
|
end
|
290
277
|
|
291
|
-
def static_shape_point_query(
|
278
|
+
def static_shape_point_query(pt)
|
292
279
|
raise "Not Implmented yet"
|
293
280
|
end
|
294
281
|
|
295
|
-
def
|
296
|
-
@
|
297
|
-
|
298
|
-
|
282
|
+
def point_query_first(point, layers, group)
|
283
|
+
shape_ptr = CP.cpSpacePointQueryFirst(@struct.pointer, point.struct, layers, group)
|
284
|
+
if shape_ptr.null?
|
285
|
+
nil
|
286
|
+
else
|
287
|
+
shape = ShapeStruct.new(shape_ptr)
|
288
|
+
obj_id = shape.data.get_long 0
|
289
|
+
ObjectSpace._id2ref obj_id
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def active_shapes_hash
|
294
|
+
SpaceHash.new(SpaceHashStruct.new(@struct.active_shapes))
|
299
295
|
end
|
300
296
|
|
297
|
+
def point_query(point, layers, group, &block)
|
298
|
+
return nil unless block_given?
|
299
|
+
|
300
|
+
query_proc = Proc.new do |shape_ptr,data|
|
301
|
+
shape = ShapeStruct.new(shape_ptr)
|
302
|
+
obj_id = shape.data.get_long 0
|
303
|
+
shape = ObjectSpace._id2ref obj_id
|
304
|
+
block.call shape
|
305
|
+
end
|
306
|
+
|
307
|
+
CP.cpSpacePointQuery(@struct.pointer, point.struct, layers, group,query_proc,nil)
|
308
|
+
end
|
301
309
|
|
302
310
|
end
|
303
311
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module CP
|
2
|
+
|
3
|
+
callback :cpSpaceHashBBFunc, [:pointer], BBStruct.by_value
|
4
|
+
callback :cpSpaceHashQueryFunc, [:pointer, :pointer, :pointer], :void
|
5
|
+
|
6
|
+
class SpaceHashStruct < NiceFFI::Struct
|
7
|
+
layout(:num_cells, :int,
|
8
|
+
:cell_dim, CP_FLOAT,
|
9
|
+
:bb_func, :cpSpaceHashBBFunc,
|
10
|
+
:handle_set, :pointer,
|
11
|
+
:table, :pointer,
|
12
|
+
:bins, :pointer,
|
13
|
+
:stamp, :int)
|
14
|
+
end
|
15
|
+
func :cpSpaceHashNew, [CP_FLOAT,:int,:cpSpaceHashBBFunc], :pointer
|
16
|
+
func :cpSpaceHashQuery, [:pointer, :pointer, BBStruct.by_value, :cpSpaceHashQueryFunc, :pointer], :void
|
17
|
+
func :cpSpaceHashInsert, [:pointer, :pointer, :uint, BBStruct.by_value], :void
|
18
|
+
func :cpSpaceHashRemove, [:pointer, :pointer, :uint], :void
|
19
|
+
|
20
|
+
class SpaceHash
|
21
|
+
attr_reader :struct
|
22
|
+
def initialize(*args, &bb_func)
|
23
|
+
case args.size
|
24
|
+
when 1
|
25
|
+
@struct = args.first
|
26
|
+
when 2
|
27
|
+
raise "need bb func" unless block_given?
|
28
|
+
cell_dim = args[0]
|
29
|
+
cells = args[1]
|
30
|
+
@struct = SpaceHashStruct.new(CP.cpSpaceHashNew(cell_dim, cells, bb_func))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def num_cells;@struct.num_cells;end
|
35
|
+
def cell_dim;@struct.cell_dim;end
|
36
|
+
|
37
|
+
def insert(obj, bb)
|
38
|
+
CP.cpSpaceHashInsert(@struct.pointer, obj.struct.pointer, obj.struct.hash_value, bb.struct)
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove(obj)
|
42
|
+
CP.cpSpaceHashRemove(@struct.pointer, obj.struct.pointer, obj.struct.hash_value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def query_func
|
46
|
+
@query_func ||= Proc.new do |obj,other,data|
|
47
|
+
s = ShapeStruct.new(other)
|
48
|
+
obj_id = s.data.get_long 0
|
49
|
+
@shapes << ObjectSpace._id2ref(obj_id)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def query_by_bb(bb)
|
54
|
+
@shapes = []
|
55
|
+
CP.cpSpaceHashQuery(@struct.pointer, nil, bb.struct, query_func, nil)
|
56
|
+
@shapes
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'chipmunk-ffi'
|
2
|
+
|
3
|
+
module CP
|
4
|
+
func :cpCircleShapeSetRadius, [:pointer, CP_FLOAT], :void
|
5
|
+
func :cpCircleShapeSetOffset, [:pointer, Vect.by_value], :void
|
6
|
+
|
7
|
+
func :cpSegmentShapeSetEndpoints, [:pointer, Vect.by_value, Vect.by_value], :void
|
8
|
+
func :cpSegmentShapeSetRadius, [:pointer, CP_FLOAT], :void
|
9
|
+
|
10
|
+
func :cpPolyShapeSetVerts, [:pointer, :int, :pointer, Vect.by_value], :void
|
11
|
+
|
12
|
+
module Shape
|
13
|
+
class Circle
|
14
|
+
def radius=(new_radius)
|
15
|
+
CP.cpCircleShapeSetRadius(@struct, new_radius)
|
16
|
+
end
|
17
|
+
def offset=(new_offset)
|
18
|
+
CP.cpCircleShapeSetOffset(@struct, new_offset.struct)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class Segment
|
22
|
+
def endpoints=(new_endpoints)
|
23
|
+
new_a, new_b = *new_endpoints.map { |v| v.struct }
|
24
|
+
CP.cpSegmentShapeSetEndpoints(@struct, new_a, new_b)
|
25
|
+
end
|
26
|
+
def radius=(new_radius)
|
27
|
+
CP.cpSegmentShapeSetRadius(@struct, new_radius)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class Poly
|
31
|
+
def verts=(new_verts_and_offset)
|
32
|
+
new_verts, new_offset = *new_verts_and_offset
|
33
|
+
|
34
|
+
new_verts_pointer = FFI::MemoryPointer.new Vect, new_verts.count
|
35
|
+
|
36
|
+
size = Vect.size
|
37
|
+
tmp = new_verts_pointer
|
38
|
+
new_verts.each_with_index do |vert, i|
|
39
|
+
tmp.send(:put_bytes, 0, vert.struct.to_bytes, 0, size)
|
40
|
+
tmp += size unless i == new_verts.length - 1 # avoid OOB
|
41
|
+
end
|
42
|
+
|
43
|
+
CP.cpPolyShapeSetVerts(@struct.pointer, new_verts.count, new_verts_pointer, new_offset.struct)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/chipmunk-ffi/vec2.rb
CHANGED
@@ -1,7 +1,24 @@
|
|
1
1
|
module CP
|
2
|
-
class Vect <
|
2
|
+
class Vect < FFI::Struct
|
3
3
|
layout( :x, CP_FLOAT,
|
4
|
-
|
4
|
+
:y, CP_FLOAT )
|
5
|
+
|
6
|
+
def self.release( ptr )
|
7
|
+
free ptr
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize( ptr )
|
11
|
+
case ptr
|
12
|
+
when FFI::MemoryPointer, FFI::Buffer, FFI::AutoPointer
|
13
|
+
super ptr
|
14
|
+
else
|
15
|
+
super FFI::AutoPointer.new(ptr, self.class.method(:release))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_bytes
|
20
|
+
return self.pointer.get_bytes(0, self.size)
|
21
|
+
end
|
5
22
|
end
|
6
23
|
|
7
24
|
cp_static_inline :cpv, [CP_FLOAT,CP_FLOAT], Vect.by_value
|
@@ -9,8 +26,8 @@ module CP
|
|
9
26
|
cp_static_inline :cpvadd, [Vect.by_value,Vect.by_value], Vect.by_value
|
10
27
|
cp_static_inline :cpvsub, [Vect.by_value,Vect.by_value], Vect.by_value
|
11
28
|
cp_static_inline :cpvmult, [Vect.by_value,CP_FLOAT], Vect.by_value
|
12
|
-
cp_static_inline :cpvdot, [Vect.by_value,Vect.by_value],
|
13
|
-
cp_static_inline :cpvcross, [Vect.by_value,Vect.by_value],
|
29
|
+
cp_static_inline :cpvdot, [Vect.by_value,Vect.by_value], CP_FLOAT
|
30
|
+
cp_static_inline :cpvcross, [Vect.by_value,Vect.by_value], CP_FLOAT
|
14
31
|
|
15
32
|
cp_static_inline :cpvperp, [Vect.by_value], Vect.by_value
|
16
33
|
cp_static_inline :cpvrperp, [Vect.by_value], Vect.by_value
|
@@ -20,13 +37,13 @@ module CP
|
|
20
37
|
|
21
38
|
cp_static_inline :cpvlengthsq, [Vect.by_value], CP_FLOAT
|
22
39
|
|
23
|
-
cp_static_inline :cpvlerp, [Vect.by_value,Vect.by_value], Vect.by_value
|
40
|
+
cp_static_inline :cpvlerp, [Vect.by_value,Vect.by_value,CP_FLOAT], Vect.by_value
|
24
41
|
|
25
42
|
cp_static_inline :cpvnormalize, [Vect.by_value], Vect.by_value
|
26
43
|
cp_static_inline :cpvnormalize_safe, [Vect.by_value], Vect.by_value
|
27
44
|
|
28
45
|
cp_static_inline :cpvclamp, [Vect.by_value,Vect.by_value], Vect.by_value
|
29
|
-
cp_static_inline :cpvlerpconst, [Vect.by_value,Vect.by_value], Vect.by_value
|
46
|
+
cp_static_inline :cpvlerpconst, [Vect.by_value,Vect.by_value, CP_FLOAT], Vect.by_value
|
30
47
|
cp_static_inline :cpvdist, [Vect.by_value,Vect.by_value], CP_FLOAT
|
31
48
|
cp_static_inline :cpvdistsq, [Vect.by_value,Vect.by_value], CP_FLOAT
|
32
49
|
|
@@ -48,23 +65,23 @@ module CP
|
|
48
65
|
when 2
|
49
66
|
@struct = CP.cpv(*args)
|
50
67
|
else
|
51
|
-
raise "wrong number of
|
68
|
+
raise "wrong number of arguments (#{args.size} for 2)"
|
52
69
|
end
|
53
70
|
end
|
54
71
|
|
55
72
|
def x
|
56
|
-
@struct
|
73
|
+
@struct[:x]
|
57
74
|
end
|
58
75
|
def x=(new_x)
|
59
|
-
raise TypeError "
|
60
|
-
@struct
|
76
|
+
raise TypeError, "can't modify frozen vec2" if frozen?
|
77
|
+
@struct[:x] = new_x
|
61
78
|
end
|
62
79
|
def y
|
63
|
-
@struct
|
80
|
+
@struct[:y]
|
64
81
|
end
|
65
82
|
def y=(new_y)
|
66
|
-
raise TypeError "
|
67
|
-
@struct
|
83
|
+
raise TypeError, "can't modify frozen vec2" if frozen?
|
84
|
+
@struct[:y] = new_y
|
68
85
|
end
|
69
86
|
|
70
87
|
def self.for_angle(angle)
|
@@ -80,7 +97,7 @@ module CP
|
|
80
97
|
end
|
81
98
|
|
82
99
|
def to_a
|
83
|
-
[@struct
|
100
|
+
[@struct[:x],@struct[:y]]
|
84
101
|
end
|
85
102
|
|
86
103
|
def -@
|
@@ -117,7 +134,7 @@ module CP
|
|
117
134
|
end
|
118
135
|
|
119
136
|
def rperp
|
120
|
-
Vec2.new CP.
|
137
|
+
Vec2.new CP.cpvrperp(@struct)
|
121
138
|
end
|
122
139
|
|
123
140
|
def project(other_vec)
|
@@ -136,8 +153,8 @@ module CP
|
|
136
153
|
CP.cpvlengthsq(@struct)
|
137
154
|
end
|
138
155
|
|
139
|
-
def lerp(other_vec)
|
140
|
-
Vec2.new CP.cpvlerp(@struct, other_vec.struct)
|
156
|
+
def lerp(other_vec, t)
|
157
|
+
Vec2.new CP.cpvlerp(@struct, other_vec.struct, t)
|
141
158
|
end
|
142
159
|
|
143
160
|
def normalize
|
@@ -157,16 +174,16 @@ module CP
|
|
157
174
|
Vec2.new CP.cpvclamp(@struct)
|
158
175
|
end
|
159
176
|
|
160
|
-
def lerpconst(other_vec)
|
161
|
-
Vec2.new CP.cpvlerpconst(@struct)
|
177
|
+
def lerpconst(other_vec, d)
|
178
|
+
Vec2.new CP.cpvlerpconst(@struct, other_vec.struct, d)
|
162
179
|
end
|
163
180
|
|
164
181
|
def dist(other_vec)
|
165
|
-
CP.cpvdist(@struct)
|
182
|
+
CP.cpvdist(@struct, other_vec.struct)
|
166
183
|
end
|
167
184
|
|
168
185
|
def distsq(other_vec)
|
169
|
-
CP.cpvdistsq(@struct)
|
186
|
+
CP.cpvdistsq(@struct, other_vec.struct)
|
170
187
|
end
|
171
188
|
|
172
189
|
def near?(other_vec, dist)
|
data/spec/body_spec.rb
CHANGED
@@ -9,6 +9,7 @@ describe 'A new Body' do
|
|
9
9
|
b = CP::Body.new(5, 7)
|
10
10
|
b.m = 900
|
11
11
|
b.m.should == 900
|
12
|
+
b.m_inv.should be_close(1.0/900, 0.001)
|
12
13
|
end
|
13
14
|
|
14
15
|
it 'can set its pos' do
|
@@ -31,21 +32,125 @@ describe 'A new Body' do
|
|
31
32
|
b.v.y.should == 6
|
32
33
|
end
|
33
34
|
|
34
|
-
it 'can set its moment'
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
it 'can
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
35
|
+
it 'can set its moment' do
|
36
|
+
b = CP::Body.new(5, 7)
|
37
|
+
b.moment = 37
|
38
|
+
b.moment.should == 37
|
39
|
+
b.moment_inv.should be_close(1.0/37, 0.001)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can set its force' do
|
43
|
+
b = CP::Body.new(5, 7)
|
44
|
+
b.f.x.should == 0
|
45
|
+
b.f.y.should == 0
|
46
|
+
|
47
|
+
b.f = vec2(4,6)
|
48
|
+
b.f.x.should == 4
|
49
|
+
b.f.y.should == 6
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'can set its angle' do
|
53
|
+
b = CP::Body.new(5, 7)
|
54
|
+
b.a = 37
|
55
|
+
b.a.should == 37
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'can set its angle_vel' do
|
59
|
+
b = CP::Body.new(5, 7)
|
60
|
+
b.w = 37
|
61
|
+
b.w.should == 37
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'can set its torque' do
|
65
|
+
b = CP::Body.new(5, 7)
|
66
|
+
b.t = 37
|
67
|
+
b.t.should == 37
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'can get its rot' do
|
71
|
+
b = CP::Body.new(5, 7)
|
72
|
+
b.rot.x.should == 1
|
73
|
+
b.rot.y.should == 0
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'can set its v_limit' do
|
77
|
+
b = CP::Body.new(5, 7)
|
78
|
+
b.v_limit = 37
|
79
|
+
b.v_limit.should == 37
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'can get its v_limit' do
|
83
|
+
b = CP::Body.new(5, 7)
|
84
|
+
b.v_limit.should === CP::INFINITY
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'can set its w_limit' do
|
88
|
+
b = CP::Body.new(5, 7)
|
89
|
+
b.w_limit = 37
|
90
|
+
b.w_limit.should == 37
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'can get its w_limit' do
|
94
|
+
b = CP::Body.new(5, 7)
|
95
|
+
b.w_limit.should === CP::INFINITY
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'can get local2world' do
|
99
|
+
b = CP::Body.new(5, 7)
|
100
|
+
b.pos = vec2(4,6)
|
101
|
+
v = b.local2world(vec2(0,0))
|
102
|
+
v.x.should == 4
|
103
|
+
v.y.should == 6
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'can get world2local' do
|
107
|
+
b = CP::Body.new(5, 7)
|
108
|
+
b.pos = vec2(4,6)
|
109
|
+
v = b.world2local(vec2(4,6))
|
110
|
+
v.x.should == 0
|
111
|
+
v.y.should == 0
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'can reset its forces' do
|
115
|
+
b = CP::Body.new(5, 7)
|
116
|
+
b.f = vec2(4,6)
|
117
|
+
b.reset_forces
|
118
|
+
b.f.x.should == 0
|
119
|
+
b.f.y.should == 0
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'can apply force' do
|
123
|
+
b = CP::Body.new(5, 7)
|
124
|
+
b.apply_force(vec2(1,0), ZERO_VEC_2)
|
125
|
+
b.f.x.should == 1
|
126
|
+
b.f.y.should == 0
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'can apply impulse' do
|
130
|
+
b = CP::Body.new(5, 7)
|
131
|
+
b.apply_impulse(vec2(1,0), ZERO_VEC_2)
|
132
|
+
# shouldn't mess with force
|
133
|
+
b.f.x.should == 0
|
134
|
+
b.f.y.should == 0
|
135
|
+
|
136
|
+
b.v.x.should == 0.2
|
137
|
+
b.v.y.should == 0
|
138
|
+
end
|
46
139
|
|
47
140
|
it 'should be able to update its position' do
|
48
141
|
b = CP::Body.new(5, 7)
|
142
|
+
b.apply_impulse(vec2(1,0), ZERO_VEC_2)
|
49
143
|
b.update_position 25
|
144
|
+
b.p.x.should be_close(5,0.001)
|
145
|
+
b.p.y.should be_close(0,0.001)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'can update its velocity over a timestep' do
|
149
|
+
b = CP::Body.new(5, 7)
|
150
|
+
b.apply_impulse(vec2(1,0), ZERO_VEC_2)
|
151
|
+
b.update_velocity vec2(0,0), 0.5, 25
|
152
|
+
b.v.x.should be_close(0.1,0.001)
|
153
|
+
b.v.y.should be_close(0,0.001)
|
50
154
|
end
|
155
|
+
|
51
156
|
end
|