chipmunk-ffi 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|