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/Gemfile
CHANGED
data/gamebox.gemspec
CHANGED
@@ -25,12 +25,9 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency "tween"
|
26
26
|
s.add_dependency "require_all"
|
27
27
|
s.add_dependency "kvo"
|
28
|
-
s.add_dependency "pry", '0.9.6'
|
29
|
-
s.add_dependency "pry-remote"
|
30
|
-
|
31
|
-
# TODO make this optional
|
32
|
-
s.add_dependency "chipmunk"
|
33
28
|
|
29
|
+
s.add_development_dependency "pry", '~>0.9.7'
|
30
|
+
s.add_development_dependency "pry-remote"
|
34
31
|
s.add_development_dependency "rspec-core"
|
35
32
|
s.add_development_dependency "rspec-mocks"
|
36
33
|
s.add_development_dependency "rspec-expectations"
|
@@ -38,7 +35,6 @@ Gem::Specification.new do |s|
|
|
38
35
|
s.add_development_dependency "rspec"
|
39
36
|
s.add_development_dependency "rake"
|
40
37
|
s.add_development_dependency "polaris"
|
41
|
-
s.add_development_dependency 'rcov'
|
42
38
|
|
43
39
|
end
|
44
40
|
|
data/lib/gamebox.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
GAMEBOX_PATH = File.join(File.dirname(__FILE__),"gamebox/")
|
2
|
-
require 'chipmunk'
|
3
2
|
require 'diy'
|
4
3
|
require 'constructor'
|
5
4
|
require 'kvo'
|
@@ -16,5 +15,10 @@ def log(output, level = :debug)
|
|
16
15
|
puts "[#{t.min}:#{t.sec}:#{t.usec}] [#{level}] #{output}"
|
17
16
|
end
|
18
17
|
|
18
|
+
begin
|
19
|
+
require 'chipmunk'
|
20
|
+
rescue LoadError
|
21
|
+
end
|
22
|
+
|
19
23
|
require 'require_all'
|
20
24
|
require_all Dir.glob("#{GAMEBOX_PATH}/**/*.rb").reject { |f| f.match("template_app") || f.match("spec") || f.match("gamebox_application.rb")}
|
@@ -16,19 +16,19 @@ end
|
|
16
16
|
class CollidableDebuggerView < ActorView
|
17
17
|
|
18
18
|
def setup
|
19
|
-
@color = Color
|
19
|
+
@color = Color::WHITE
|
20
20
|
end
|
21
21
|
|
22
|
-
def draw(target,x_off,y_off)
|
22
|
+
def draw(target,x_off,y_off,z)
|
23
23
|
collider = @actor.actor
|
24
24
|
case collider.collidable_shape
|
25
25
|
when :circle
|
26
|
-
target.draw_circle
|
26
|
+
target.draw_circle x_off+collider.center_x, y_off+collider.center_y, collider.radius, @color, z
|
27
27
|
else
|
28
28
|
collider.cw_world_lines.each do |line|
|
29
29
|
f = line.first
|
30
30
|
l = line.last
|
31
|
-
target.draw_line
|
31
|
+
target.draw_line x_off+f[0],y_off+f[1],x_off+l[0],y_off+l[1], @color, z
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
data/lib/gamebox/actors/fps.rb
CHANGED
@@ -1,23 +1,8 @@
|
|
1
|
-
class FpsView <
|
2
|
-
|
3
|
-
text = @actor.fps.to_s
|
4
|
-
text = '0'*(6-text.size)+text if text.size < 6
|
1
|
+
class FpsView < LabelView; end
|
2
|
+
class Fps < Label
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
x = @actor.x
|
10
|
-
y = @actor.y
|
11
|
-
|
12
|
-
text_image.blit target.screen, [x,y]
|
13
|
-
end
|
14
|
-
end
|
15
|
-
class Fps < Actor
|
16
|
-
|
17
|
-
has_behavior :layered => {:layer => 999}
|
18
|
-
|
19
|
-
def fps
|
20
|
-
input_manager.current_framerate.round
|
4
|
+
def text
|
5
|
+
fps
|
21
6
|
end
|
22
7
|
|
23
8
|
end
|
data/lib/gamebox/arbiter.rb
CHANGED
@@ -130,18 +130,13 @@ module Arbiter
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def collide_circle_circle?(object, other)
|
133
|
-
|
134
|
-
y = object.center_y
|
135
|
-
x_prime = other.center_x
|
136
|
-
y_prime = other.center_y
|
137
|
-
|
138
|
-
x_delta = x_prime - x
|
133
|
+
x_delta = other.center_x - object.center_x
|
139
134
|
x_dist = x_delta * x_delta
|
140
|
-
y_delta =
|
135
|
+
y_delta = other.center_y - object.center_y
|
141
136
|
y_dist = y_delta * y_delta
|
142
137
|
|
143
138
|
total_radius = object.radius + other.radius
|
144
|
-
x_dist + y_dist <= (total_radius * total_radius)
|
139
|
+
(x_dist + y_dist) <= (total_radius * total_radius)
|
145
140
|
end
|
146
141
|
|
147
142
|
# Idea from:
|
@@ -86,14 +86,14 @@ class Physical < Behavior
|
|
86
86
|
when :circle
|
87
87
|
@radius = @opts[:radius]
|
88
88
|
|
89
|
-
@moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_circle(@mass, @radius, 0, ZERO_VEC_2)
|
89
|
+
@moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : CP::moment_for_circle(@mass, @radius, 0, ZERO_VEC_2)
|
90
90
|
@body = CP::Body.new(@mass, @moment_of_inertia)
|
91
91
|
@shape = CP::Shape::Circle.new(@body, @radius, ZERO_VEC_2)
|
92
92
|
|
93
93
|
when :poly
|
94
94
|
shape_array = @opts[:verts].collect{|v| vec2(v[0],v[1])}
|
95
95
|
|
96
|
-
@moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_poly(@mass, shape_array, ZERO_VEC_2)
|
96
|
+
@moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : CP::moment_for_poly(@mass, shape_array, ZERO_VEC_2)
|
97
97
|
@body = CP::Body.new(@mass, @moment_of_inertia)
|
98
98
|
@shape = CP::Shape::Poly.new(@body, shape_array, ZERO_VEC_2)
|
99
99
|
verts = @opts[:verts].dup
|
@@ -51,19 +51,22 @@ class InputManager
|
|
51
51
|
@window.when :button_down do |button_id|
|
52
52
|
_handle_event button_id, :down
|
53
53
|
end
|
54
|
+
|
54
55
|
@window.when :update do |millis|
|
55
56
|
|
56
|
-
@
|
57
|
-
|
57
|
+
if @uses_mouse
|
58
|
+
@last_mouse_x ||= mouse_x
|
59
|
+
@last_mouse_y ||= mouse_y
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
+
x_diff = @last_mouse_x - mouse_x
|
62
|
+
y_diff = @last_mouse_y - mouse_y
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
+
unless x_diff < 0.1 && x_diff > -0.1 && y_diff < 0.1 && y_diff > -0.1
|
65
|
+
_handle_event nil, :motion
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
+
@last_mouse_x = mouse_x
|
68
|
+
@last_mouse_y = mouse_y
|
69
|
+
end
|
67
70
|
end
|
68
71
|
|
69
72
|
game.update millis
|
@@ -112,21 +115,21 @@ class InputManager
|
|
112
115
|
event_type = :game_pad
|
113
116
|
end
|
114
117
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
118
|
+
# single threaded.. keep same event
|
119
|
+
@event ||= {}
|
120
|
+
@event[:type] = event_type
|
121
|
+
@event[:id] = gosu_id
|
122
|
+
@event[:action] = action
|
123
|
+
@event[:callback_key] = callback_key
|
124
|
+
@event[:data] = event_data
|
122
125
|
|
123
|
-
fire_event(event)
|
126
|
+
fire_event(@event)
|
124
127
|
|
125
128
|
if mouse_dragged
|
126
129
|
drag_data = {:to => [mouse_x, mouse_y], :from => [@last_click_x, @last_click_y]}
|
127
|
-
event[:data] = drag_data
|
128
|
-
event[:callback_key] = :mouse_drag
|
129
|
-
fire_event(event)
|
130
|
+
@event[:data] = drag_data
|
131
|
+
@event[:callback_key] = :mouse_drag
|
132
|
+
fire_event(@event)
|
130
133
|
end
|
131
134
|
end
|
132
135
|
|
@@ -178,11 +181,13 @@ class InputManager
|
|
178
181
|
return unless block_given?
|
179
182
|
@hooks[event_class] ||= {}
|
180
183
|
for event_id in event_ids
|
184
|
+
@uses_mouse = true if event_id >= MsRangeBegin && event_id <= MsRangeEnd
|
181
185
|
@hooks[event_class][event_id] ||= []
|
182
186
|
@hooks[event_class][event_id] << block
|
183
187
|
end
|
184
188
|
@non_id_hooks[event_class] ||= []
|
185
189
|
if event_ids.empty?
|
190
|
+
@uses_mouse = true
|
186
191
|
@non_id_hooks[event_class] << block
|
187
192
|
end
|
188
193
|
if listener.respond_to?(:can_fire?) && listener.can_fire?(:remove_me)
|
data/lib/gamebox/physics.rb
CHANGED
@@ -1,35 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
CP.moment_for_circle(*args)
|
7
|
-
end
|
8
|
-
|
9
|
-
def moment_for_poly(*args)
|
10
|
-
CP.moment_for_poly(*args)
|
11
|
-
end
|
12
|
-
|
13
|
-
ZERO_VEC_2 = vec2(0,0)
|
1
|
+
if defined? CP
|
2
|
+
ZERO_VEC_2 = vec2(0,0)
|
3
|
+
def vec2(*args)
|
4
|
+
CP::Vec2.new *args
|
5
|
+
end
|
14
6
|
|
15
|
-
class CP::Space
|
16
|
-
|
17
|
-
|
18
|
-
# allows for passing arrays of collision types not just single ones
|
19
|
-
# add_collision_func([:foo,:bar], [:baz,:yar]) becomes:
|
20
|
-
# add_collision_func(:foo, :baz)
|
21
|
-
# add_collision_func(:foo, :yar)
|
22
|
-
# add_collision_func(:bar, :baz)
|
23
|
-
# add_collision_func(:bar, :yar)
|
24
|
-
def add_collision_func(first_objs, second_objs, &block)
|
25
|
-
firsts = [first_objs].flatten
|
26
|
-
seconds = [second_objs].flatten
|
7
|
+
class CP::Space
|
8
|
+
alias :add_collision_func_old :add_collision_func
|
27
9
|
|
28
|
-
|
29
|
-
|
30
|
-
|
10
|
+
# allows for passing arrays of collision types not just single ones
|
11
|
+
# add_collision_func([:foo,:bar], [:baz,:yar]) becomes:
|
12
|
+
# add_collision_func(:foo, :baz)
|
13
|
+
# add_collision_func(:foo, :yar)
|
14
|
+
# add_collision_func(:bar, :baz)
|
15
|
+
# add_collision_func(:bar, :yar)
|
16
|
+
def add_collision_func(first_objs, second_objs, &block)
|
17
|
+
firsts = [first_objs].flatten
|
18
|
+
seconds = [second_objs].flatten
|
19
|
+
|
20
|
+
firsts.each do |f|
|
21
|
+
seconds.each do |s|
|
22
|
+
add_collision_func_old(f,s,&block)
|
23
|
+
end
|
31
24
|
end
|
32
25
|
end
|
33
26
|
end
|
34
|
-
|
27
|
+
else
|
28
|
+
ZERO_VEC_2 = Ftor.new(0,0)
|
29
|
+
def vec2(*args)
|
30
|
+
Ftor.new *args
|
31
|
+
end
|
35
32
|
end
|
@@ -28,6 +28,7 @@ class SoundManager
|
|
28
28
|
end if files
|
29
29
|
|
30
30
|
@sounds = {}
|
31
|
+
@playing_sounds = {}
|
31
32
|
files = Dir.glob "#{SOUND_PATH}**.{#{SUPPORTED_AUDIO_EXTS.join(',')}}"
|
32
33
|
for f in files
|
33
34
|
name = File.basename(f)
|
@@ -50,7 +51,8 @@ class SoundManager
|
|
50
51
|
# play_sound :foo # play sound at 100% volume
|
51
52
|
def play_sound(what, opts={})
|
52
53
|
if @enabled && @sounds[what]
|
53
|
-
|
54
|
+
merged_opts = {volume:1, speed:1, looping:false}.merge opts
|
55
|
+
@playing_sounds[what] = @sounds[what].play merged_opts[:volume], merged_opts[:speed], merged_opts[:looping]
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
@@ -79,7 +81,7 @@ class SoundManager
|
|
79
81
|
# stop_sound :foo
|
80
82
|
def stop_sound(what)
|
81
83
|
if @enabled
|
82
|
-
@
|
84
|
+
@playing_sounds[what].stop if @playing_sounds[what]
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
data/lib/gamebox/spatial_hash.rb
CHANGED
@@ -4,10 +4,11 @@ class SpatialHash
|
|
4
4
|
attr_accessor :auto_resize
|
5
5
|
|
6
6
|
def initialize(cell_size, resize = false)
|
7
|
-
@cell_size = cell_size.
|
7
|
+
@cell_size = cell_size.to_i
|
8
8
|
@items = {}
|
9
9
|
@auto_resize = resize
|
10
10
|
|
11
|
+
# TODO auto resize is broken atm
|
11
12
|
if @auto_resize
|
12
13
|
@total_w = 0
|
13
14
|
@total_h = 0
|
@@ -18,12 +19,13 @@ class SpatialHash
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def cell_size=(new_size)
|
21
|
-
@cell_size = new_size
|
22
|
+
@cell_size = new_size.to_i
|
22
23
|
rehash
|
23
24
|
end
|
24
25
|
|
25
26
|
def rehash
|
26
27
|
@moved_items = {}
|
28
|
+
# TODO WTF?
|
27
29
|
return
|
28
30
|
items = @items
|
29
31
|
|
@@ -33,7 +35,7 @@ class SpatialHash
|
|
33
35
|
avg_w = @total_w / items.size
|
34
36
|
avg_h = @total_h / items.size
|
35
37
|
|
36
|
-
@cell_size = (avg_w+avg_h)
|
38
|
+
@cell_size = (avg_w+avg_h).to_i
|
37
39
|
end
|
38
40
|
|
39
41
|
@total_w = 0
|
@@ -61,12 +63,9 @@ class SpatialHash
|
|
61
63
|
def _add(item)
|
62
64
|
buckets = lookup item
|
63
65
|
@items[item] = buckets
|
66
|
+
|
64
67
|
buckets.each do |bucket|
|
65
|
-
|
66
|
-
@buckets[x] ||= {}
|
67
|
-
@buckets[x][y] ||= []
|
68
|
-
target_bucket = @buckets[x][y]
|
69
|
-
target_bucket << item
|
68
|
+
bucket << item
|
70
69
|
|
71
70
|
if @auto_resize
|
72
71
|
w = item.width if item.respond_to? :width
|
@@ -85,13 +84,12 @@ class SpatialHash
|
|
85
84
|
end
|
86
85
|
|
87
86
|
def _remove(item)
|
88
|
-
buckets = @items
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
87
|
+
buckets = @items.delete item
|
88
|
+
if buckets
|
89
|
+
buckets.each do |bucket|
|
90
|
+
bucket.delete item
|
91
|
+
end
|
93
92
|
end
|
94
|
-
@items.delete item
|
95
93
|
end
|
96
94
|
|
97
95
|
def lookup(item)
|
@@ -103,34 +101,39 @@ class SpatialHash
|
|
103
101
|
|
104
102
|
x = item.x
|
105
103
|
y = item.y
|
106
|
-
min_x
|
104
|
+
min_x = bucket_cell_for x
|
105
|
+
min_y = bucket_cell_for y
|
107
106
|
if w == 1 && h == 1
|
108
107
|
max_x = min_x
|
109
108
|
max_y = min_y
|
110
109
|
else
|
111
|
-
max_x
|
110
|
+
max_x = bucket_cell_for x+w-1
|
111
|
+
max_y = bucket_cell_for y+h-1
|
112
112
|
end
|
113
113
|
|
114
114
|
buckets = []
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
115
|
+
bucket_x = min_x
|
116
|
+
while bucket_x < max_x + 1 do
|
117
|
+
bucket_y = min_y
|
118
|
+
while bucket_y < max_y + 1 do
|
119
|
+
@buckets[bucket_x] ||= {}
|
120
|
+
@buckets[bucket_x][bucket_y] ||= SpatialBucket.new(bucket_x, bucket_y)
|
121
|
+
buckets << @buckets[bucket_x][bucket_y]
|
122
|
+
bucket_y += 1
|
119
123
|
end
|
124
|
+
bucket_x += 1
|
120
125
|
end
|
121
126
|
|
122
127
|
buckets
|
123
128
|
end
|
124
129
|
|
125
|
-
def
|
126
|
-
|
127
|
-
bucket_y = (y/cell_size).floor
|
128
|
-
return [bucket_x, bucket_y]
|
130
|
+
def bucket_cell_for(location)
|
131
|
+
(location.to_i / cell_size).to_i
|
129
132
|
end
|
130
|
-
|
133
|
+
|
131
134
|
def items_at(x,y)
|
132
|
-
bucket_x =
|
133
|
-
bucket_y =
|
135
|
+
bucket_x = bucket_cell_for x
|
136
|
+
bucket_y = bucket_cell_for y
|
134
137
|
if @buckets[bucket_x].nil? || @buckets[bucket_x][bucket_y].nil?
|
135
138
|
return []
|
136
139
|
else
|
@@ -141,12 +144,14 @@ class SpatialHash
|
|
141
144
|
def items_in(x,y,w,h)
|
142
145
|
return items_at x, y if ((w.nil? || w == 1) && (h.nil? || w == 1))
|
143
146
|
|
144
|
-
min_x
|
147
|
+
min_x = bucket_cell_for x
|
148
|
+
min_y = bucket_cell_for y
|
145
149
|
if w == 1 && h == 1
|
146
150
|
max_x = min_x
|
147
151
|
max_y = min_y
|
148
152
|
else
|
149
|
-
max_x
|
153
|
+
max_x = bucket_cell_for x+w-1
|
154
|
+
max_y = bucket_cell_for y+w-1
|
150
155
|
end
|
151
156
|
|
152
157
|
items_in_bucket_range min_x, min_y, max_x, max_y
|
@@ -175,14 +180,11 @@ class SpatialHash
|
|
175
180
|
# occupied by the item
|
176
181
|
def neighbors_of(item, dist=1)
|
177
182
|
buckets = lookup(item)
|
178
|
-
min_bucket_x, min_bucket_y = *buckets.first
|
179
|
-
max_bucket_x, max_bucket_y = *buckets.last
|
180
|
-
|
181
|
-
min_bucket_x = min_bucket_x-1
|
182
|
-
min_bucket_y = min_bucket_y-1
|
183
183
|
|
184
|
-
|
185
|
-
|
184
|
+
min_bucket_x = buckets.min_by{ |bucket| bucket.x }.x - dist
|
185
|
+
min_bucket_y = buckets.min_by{ |bucket| bucket.y }.y - dist
|
186
|
+
max_bucket_x = buckets.max_by{ |bucket| bucket.x }.x + dist
|
187
|
+
max_bucket_y = buckets.max_by{ |bucket| bucket.y }.y + dist
|
186
188
|
|
187
189
|
items = items_in_bucket_range min_bucket_x, min_bucket_y, max_bucket_x, max_bucket_y
|
188
190
|
items-[item]
|