gamebox 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/gamebox.gemspec +2 -6
- data/lib/gamebox.rb +5 -1
- data/lib/gamebox/actors/collidable_debugger.rb +4 -4
- data/lib/gamebox/actors/fps.rb +4 -19
- data/lib/gamebox/arbiter.rb +3 -8
- data/lib/gamebox/behaviors/physical.rb +2 -2
- data/lib/gamebox/input_manager.rb +24 -19
- data/lib/gamebox/physics.rb +26 -29
- data/lib/gamebox/resource_manager.rb +1 -1
- data/lib/gamebox/sound_manager.rb +4 -2
- data/lib/gamebox/spatial_bucket.rb +9 -0
- data/lib/gamebox/spatial_hash.rb +38 -36
- data/lib/gamebox/stage.rb +16 -5
- data/lib/gamebox/version.rb +1 -1
- data/lib/gamebox/views/graphical_actor_view.rb +2 -2
- data/lib/gamebox/wrapped_screen.rb +1 -0
- data/script/perf_collisions.rb +72 -0
- data/script/perf_drawables.rb +51 -0
- data/spec/physical_spec.rb +102 -99
- data/spec/spatial_hash_spec.rb +16 -11
- data/spec/spatial_stagehand_spec.rb +2 -6
- metadata +42 -61
data/lib/gamebox/stage.rb
CHANGED
@@ -94,12 +94,15 @@ class Stage
|
|
94
94
|
|
95
95
|
def draw(target)
|
96
96
|
z = 0
|
97
|
-
|
97
|
+
# TODO PERF cache this array and invalidate when new layers come in?
|
98
|
+
@parallax_layers.each do |parallax_layer|
|
99
|
+
# @drawables.keys.sort.reverse.each do |parallax_layer|
|
98
100
|
|
99
101
|
drawables_on_parallax_layer = @drawables[parallax_layer]
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
+
if drawables_on_parallax_layer
|
104
|
+
@layer_orders[parallax_layer].each do |layer|
|
105
|
+
# drawables_on_parallax_layer.keys.sort.each do |layer|
|
103
106
|
|
104
107
|
trans_x = @viewport.x_offset parallax_layer
|
105
108
|
trans_y = @viewport.y_offset parallax_layer
|
@@ -125,13 +128,20 @@ class Stage
|
|
125
128
|
|
126
129
|
def clear_drawables
|
127
130
|
@drawables = {}
|
131
|
+
@layer_orders = {}
|
128
132
|
end
|
129
133
|
|
130
134
|
def register_drawable(drawable)
|
131
135
|
layer = drawable.layer
|
132
136
|
parallax = drawable.parallax
|
133
|
-
@drawables[parallax]
|
134
|
-
|
137
|
+
unless @drawables[parallax]
|
138
|
+
@drawables[parallax] = {}
|
139
|
+
@parallax_layers = @drawables.keys.sort.reverse
|
140
|
+
end
|
141
|
+
unless @drawables[parallax][layer]
|
142
|
+
@drawables[parallax][layer] = []
|
143
|
+
@layer_orders[parallax] = @drawables[parallax].keys.sort
|
144
|
+
end
|
135
145
|
@drawables[parallax][layer] << drawable
|
136
146
|
end
|
137
147
|
|
@@ -140,6 +150,7 @@ class Stage
|
|
140
150
|
def move_layer(from_parallax, from_layer, to_parallax, to_layer)
|
141
151
|
drawable_list = @drawables[from_parallax].delete from_layer
|
142
152
|
|
153
|
+
|
143
154
|
if drawable_list
|
144
155
|
prev_drawable_list = @drawables[to_parallax].delete to_layer
|
145
156
|
@drawables[to_parallax][to_layer] = drawable_list
|
data/lib/gamebox/version.rb
CHANGED
@@ -14,9 +14,9 @@ class GraphicalActorView < ActorView
|
|
14
14
|
alpha = actor.respond_to?(:alpha) ? actor.alpha : 0xFF
|
15
15
|
color = Color.new(alpha,0xFF,0xFF,0xFF)
|
16
16
|
|
17
|
-
x_scale = actor.x_scale
|
18
|
-
y_scale = actor.y_scale
|
19
17
|
|
18
|
+
x_scale = actor.respond_to?(:x_scale) ? actor.x_scale : 1
|
19
|
+
y_scale = actor.respond_to?(:y_scale) ? actor.y_scale : 1
|
20
20
|
if actor.is? :physical
|
21
21
|
img_w = img.width
|
22
22
|
img_h = img.height
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
$: << File.dirname(__FILE__)+"/../lib/gamebox"
|
3
|
+
require 'gamebox'
|
4
|
+
|
5
|
+
|
6
|
+
NUM_RUNS = 800
|
7
|
+
PROFILE = true
|
8
|
+
|
9
|
+
def run
|
10
|
+
config = {
|
11
|
+
screen_resolution: [800,600]
|
12
|
+
}
|
13
|
+
|
14
|
+
af = ActorFactory.new input_manager: :input_manager, wrapped_screen: :wrapped_screen
|
15
|
+
af.director = FakeUpdate.new
|
16
|
+
stage = Stage.new :input_manager, af, :resource_manager, :sound_manager, config, :backstage, {}
|
17
|
+
|
18
|
+
things = []
|
19
|
+
20.times do |i|
|
20
|
+
5.times do |j|
|
21
|
+
things << stage.spawn(:thinger, x: i*40, y: j*40)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Benchmark.bm(60) do |b|
|
26
|
+
b.report("update loop") do
|
27
|
+
|
28
|
+
runs = NUM_RUNS
|
29
|
+
if PROFILE
|
30
|
+
# runs = 100
|
31
|
+
require 'perftools'
|
32
|
+
PerfTools::CpuProfiler.start("/tmp/gamebox_perf.txt")
|
33
|
+
end
|
34
|
+
|
35
|
+
runs.times do
|
36
|
+
things[0].x = things[0].x + 1
|
37
|
+
things[2].x = things[0].x + 1
|
38
|
+
things[0].x = things[2].x - 1
|
39
|
+
things[2].x = things[2].x - 1
|
40
|
+
things[0].y = things[0].y + 1
|
41
|
+
things[2].y = things[0].y + 1
|
42
|
+
things[0].y = things[2].y - 1
|
43
|
+
things[2].y = things[2].y - 1
|
44
|
+
stage.update(20)
|
45
|
+
#
|
46
|
+
# puts "\nGARBAGE COLLECTION"
|
47
|
+
# # Not even close to exact, but gives a rough idea of what's being collected
|
48
|
+
# old_objects = ObjectSpace.count_objects.dup
|
49
|
+
# ObjectSpace.garbage_collect
|
50
|
+
# new_objects = ObjectSpace.count_objects
|
51
|
+
#
|
52
|
+
# old_objects.each do |k,v|
|
53
|
+
# diff = v - new_objects[k]
|
54
|
+
# puts "#{k} #{diff} diff" if diff != 0
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
#
|
58
|
+
end
|
59
|
+
PerfTools::CpuProfiler.stop if PROFILE
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
class FakeUpdate
|
65
|
+
def update(dt);end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Thinger < Actor
|
69
|
+
has_behavior :collidable => {:shape => :circle, :radius => 34}
|
70
|
+
end
|
71
|
+
|
72
|
+
run
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
$: << File.dirname(__FILE__)+"/../lib/gamebox"
|
3
|
+
require 'gamebox'
|
4
|
+
|
5
|
+
|
6
|
+
NUM_LAYERS = 12
|
7
|
+
NUM_P_LAYERS = 3
|
8
|
+
NUM_RUNS = 200_000
|
9
|
+
PROFILE = true
|
10
|
+
|
11
|
+
def run
|
12
|
+
config = {
|
13
|
+
screen_resolution: [800,600]
|
14
|
+
}
|
15
|
+
|
16
|
+
af = Struct.new(:director).new
|
17
|
+
stage = Stage.new :input_manager, af, :resource_manager, :sound_manager, config, :backstage, {}
|
18
|
+
NUM_P_LAYERS.times do |pl|
|
19
|
+
NUM_LAYERS.times do |l|
|
20
|
+
stage.register_drawable FakeDrawable.new(l+1, pl+1)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
Benchmark.bm(60) do |b|
|
26
|
+
b.report("drawing loop") do
|
27
|
+
|
28
|
+
if PROFILE
|
29
|
+
require 'perftools'
|
30
|
+
PerfTools::CpuProfiler.start("/tmp/gamebox_perf.txt")
|
31
|
+
end
|
32
|
+
|
33
|
+
NUM_RUNS.times do
|
34
|
+
stage.draw :target
|
35
|
+
end
|
36
|
+
PerfTools::CpuProfiler.stop if PROFILE
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class FakeDrawable
|
43
|
+
def initialize(l, pl)
|
44
|
+
@layer = l
|
45
|
+
@parallax = pl
|
46
|
+
end
|
47
|
+
def draw(target,xoff,yoff,z);end
|
48
|
+
attr_accessor :layer, :parallax
|
49
|
+
end
|
50
|
+
|
51
|
+
run
|
data/spec/physical_spec.rb
CHANGED
@@ -1,134 +1,137 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__),'helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
:
|
7
|
-
|
3
|
+
# Only run these if the user has chipmunk installed
|
4
|
+
if defined? CP
|
5
|
+
class CircleActor < Actor
|
6
|
+
has_behaviors :physical => {:shape => :circle,
|
7
|
+
:mass => 500,
|
8
|
+
:radius => 10}
|
9
|
+
end
|
8
10
|
|
9
|
-
describe 'A new physical behavior' do
|
10
|
-
|
11
|
-
|
11
|
+
describe 'A new physical behavior' do
|
12
|
+
before do
|
13
|
+
@stage = stub(:load_animation_set => ['1.png_img_obj','2.png_img_obj'],:register_physical_object => true)
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
@opts = {:stage=>@stage, :input=>"input", :resources=>"rm"}
|
16
|
+
@actor = CircleActor.new @opts
|
17
|
+
@physical = @actor.physical
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
it 'should add methods to its actor' do
|
21
|
+
@actor.should.respond_to? :x
|
22
|
+
pending 'add shared example for relegates'
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
describe "#pivot" do
|
26
|
+
it 'creates a new PivotJoint and adds it to the space' do
|
27
|
+
other = CircleActor.new @opts
|
28
|
+
v1 = vec2(2,3)
|
29
|
+
v2 = vec2(4,5)
|
30
|
+
CP::Constraint::PivotJoint.expects(:new).with(@physical.body, other.body, v1, v2).returns(:joint)
|
31
|
+
@stage.expects(:register_physical_constraint).with(:joint)
|
30
32
|
|
31
|
-
|
33
|
+
@actor.pivot(v1, other, v2).should == :joint
|
34
|
+
end
|
32
35
|
end
|
33
|
-
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
describe "#pin" do
|
38
|
+
it 'creates a new PinJoint and adds it to the space' do
|
39
|
+
other = CircleActor.new @opts
|
40
|
+
v1 = vec2(2,3)
|
41
|
+
v2 = vec2(4,5)
|
42
|
+
CP::Constraint::PinJoint.expects(:new).with(@physical.body, other.body, v1, v2).returns(:joint)
|
43
|
+
@stage.expects(:register_physical_constraint).with(:joint)
|
42
44
|
|
43
|
-
|
45
|
+
@actor.pin(v1, other, v2).should == :joint
|
46
|
+
end
|
44
47
|
end
|
45
|
-
end
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
describe "#spring" do
|
50
|
+
it 'creates a new DampedSpring and adds it to the space' do
|
51
|
+
other = CircleActor.new @opts
|
52
|
+
v1 = vec2(2,3)
|
53
|
+
v2 = vec2(4,5)
|
54
|
+
CP::Constraint::DampedSpring.expects(:new).with(@physical.body, other.body, v1, v2, 1,2,3).returns(:spring)
|
55
|
+
@stage.expects(:register_physical_constraint).with(:spring)
|
54
56
|
|
55
|
-
|
57
|
+
@actor.spring(v1, other, v2, 1, 2, 3).should == :spring
|
58
|
+
end
|
56
59
|
end
|
57
|
-
end
|
58
60
|
|
59
61
|
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
63
|
+
describe "#groove" do
|
64
|
+
it 'creates a new GrooveJoint and adds it to the space' do
|
65
|
+
other = CircleActor.new @opts
|
66
|
+
v1 = vec2(2,3)
|
67
|
+
v2 = vec2(4,5)
|
68
|
+
v3 = vec2(9,7)
|
69
|
+
CP::Constraint::GrooveJoint.expects(:new).with(@physical.body, other.body, v1, v2, v3).returns(:groove)
|
70
|
+
@stage.expects(:register_physical_constraint).with(:groove)
|
69
71
|
|
70
|
-
|
72
|
+
@actor.groove(v1, v2, other, v3).should == :groove
|
73
|
+
end
|
71
74
|
end
|
72
|
-
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
describe "#rotary_spring" do
|
77
|
+
it 'creates a new DampedRotarySpring and adds it to the space' do
|
78
|
+
other = CircleActor.new @opts
|
79
|
+
CP::Constraint::DampedRotarySpring.expects(:new).with(@physical.body, other.body, 3.14, 10, 50).returns(:rotary_spring)
|
80
|
+
@stage.expects(:register_physical_constraint).with(:rotary_spring)
|
81
|
+
@actor.rotary_spring(other, 3.14, 10, 50).should == :rotary_spring
|
82
|
+
end
|
80
83
|
end
|
81
|
-
end
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
describe "#rotary_limit" do
|
86
|
+
it 'creates a new RotaryLimitJoint and adds it to the space' do
|
87
|
+
other = CircleActor.new @opts
|
88
|
+
CP::Constraint::RotaryLimitJoint.expects(:new).with(@physical.body, other.body, 0, 3).returns(:rotary_limit)
|
89
|
+
@stage.expects(:register_physical_constraint).with(:rotary_limit)
|
90
|
+
@actor.rotary_limit(other, 0, 3).should == :rotary_limit
|
91
|
+
end
|
89
92
|
end
|
90
|
-
end
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
describe "#ratchet" do
|
95
|
+
it 'creates a new RatchetJoint and adds it to the space' do
|
96
|
+
other = CircleActor.new @opts
|
97
|
+
CP::Constraint::RatchetJoint.expects(:new).with(@physical.body, other.body, 0, 0.3).returns(:ratchet)
|
98
|
+
@stage.expects(:register_physical_constraint).with(:ratchet)
|
99
|
+
@actor.ratchet(other, 0, 0.3).should == :ratchet
|
100
|
+
end
|
98
101
|
end
|
99
|
-
end
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
describe "#gear" do
|
104
|
+
it 'creates a new GearJoint and adds it to the space' do
|
105
|
+
other = CircleActor.new @opts
|
106
|
+
CP::Constraint::GearJoint.expects(:new).with(@physical.body, other.body, 0, 0.3).returns(:gear)
|
107
|
+
@stage.expects(:register_physical_constraint).with(:gear)
|
108
|
+
@actor.gear(other, 0, 0.3).should == :gear
|
109
|
+
end
|
107
110
|
end
|
108
|
-
end
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
describe "#motor" do
|
113
|
+
it 'creates a new SimpleMotor and adds it to the space' do
|
114
|
+
other = CircleActor.new @opts
|
115
|
+
CP::Constraint::SimpleMotor.expects(:new).with(@physical.body, other.body, 40).returns(:motor)
|
116
|
+
@stage.expects(:register_physical_constraint).with(:motor)
|
117
|
+
@actor.motor(other, 40).should == :motor
|
118
|
+
end
|
116
119
|
end
|
117
|
-
end
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
121
|
+
describe "#slide" do
|
122
|
+
it 'creates the slide joint and adds it to the space' do
|
123
|
+
other = CircleActor.new @opts
|
124
|
+
v1 = vec2(2,3)
|
125
|
+
v2 = vec2(4,5)
|
126
|
+
min = 2.0
|
127
|
+
max = 3.0
|
128
|
+
CP::Constraint::SlideJoint.expects(:new).with(@physical.body, other.body, v1, v2, min, max).returns(:joint)
|
127
129
|
|
128
|
-
|
130
|
+
@stage.expects(:register_physical_constraint).with(:joint)
|
129
131
|
|
130
|
-
|
132
|
+
@actor.slide(v1, other, v2, min, max).should == :joint
|
133
|
+
end
|
131
134
|
end
|
132
|
-
end
|
133
135
|
|
136
|
+
end
|
134
137
|
end
|
data/spec/spatial_hash_spec.rb
CHANGED
@@ -13,20 +13,20 @@ describe 'a new SpacialHash' do
|
|
13
13
|
it 'can add a point' do
|
14
14
|
pt = Point.new 2, 3
|
15
15
|
@hash.add pt
|
16
|
-
@hash.
|
16
|
+
@hash.buckets[0][0].first.should == pt
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'can add a neg point' do
|
20
20
|
pt = Point.new -2, 3
|
21
21
|
@hash.add pt
|
22
|
-
@hash.
|
22
|
+
@hash.buckets[-1][0].first.should == pt
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'can add a square' do
|
26
26
|
box = Item.new 2, 3, 12, 13
|
27
27
|
@hash.add box
|
28
28
|
|
29
|
-
buckets = @hash.
|
29
|
+
buckets = @hash.buckets
|
30
30
|
|
31
31
|
buckets[0][0].first.should == box
|
32
32
|
buckets[0][1].first.should == box
|
@@ -38,33 +38,38 @@ describe 'a new SpacialHash' do
|
|
38
38
|
box = Item.new 3, 3, 12, 2
|
39
39
|
@hash.add box
|
40
40
|
|
41
|
-
buckets = @hash.
|
41
|
+
buckets = @hash.buckets
|
42
42
|
buckets[0][0].first.should == box
|
43
43
|
buckets[1][0].first.should == box
|
44
44
|
|
45
|
-
buckets[1][1].should be_nil
|
46
45
|
buckets[0][1].should be_nil
|
46
|
+
buckets[1][1].should be_nil
|
47
47
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'can remove points' do
|
51
51
|
pt = Point.new -2, 3
|
52
52
|
@hash.add pt
|
53
|
+
@hash.buckets[-1][0].should_not be_empty
|
53
54
|
@hash.remove pt
|
54
55
|
|
55
|
-
@hash.
|
56
|
+
@hash.buckets[-1][0].should be_empty
|
56
57
|
end
|
57
58
|
|
58
59
|
it 'can remove boxes' do
|
59
60
|
box = Item.new 2, 3, 12, 13
|
60
61
|
@hash.add box
|
62
|
+
@hash.buckets[0][0].should_not be_empty
|
63
|
+
@hash.buckets[0][1].should_not be_empty
|
64
|
+
@hash.buckets[1][0].should_not be_empty
|
65
|
+
@hash.buckets[1][1].should_not be_empty
|
61
66
|
|
62
67
|
@hash.remove box
|
63
68
|
|
64
|
-
@hash.
|
65
|
-
@hash.
|
66
|
-
@hash.
|
67
|
-
@hash.
|
69
|
+
@hash.buckets[0][0].should be_empty
|
70
|
+
@hash.buckets[0][1].should be_empty
|
71
|
+
@hash.buckets[1][0].should be_empty
|
72
|
+
@hash.buckets[1][1].should be_empty
|
68
73
|
end
|
69
74
|
|
70
75
|
it 'can lookup objects for an x,y location' do
|
@@ -79,7 +84,7 @@ describe 'a new SpacialHash' do
|
|
79
84
|
@hash.add box
|
80
85
|
@hash.rehash
|
81
86
|
|
82
|
-
buckets = @hash.
|
87
|
+
buckets = @hash.buckets
|
83
88
|
buckets[0][0].first.should == box
|
84
89
|
buckets[0][1].first.should == box
|
85
90
|
buckets[1][0].first.should == box
|