gamebox 0.3.2 → 0.3.3
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/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
|