gamebox 0.2.1 → 0.3.2
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 -8
- data/Rakefile +13 -37
- data/TODO.txt +27 -27
- data/docs/getting_started.rdoc +2 -2
- data/gamebox.gemspec +33 -191
- data/lib/gamebox.rb +18 -14
- data/lib/gamebox/actor.rb +37 -27
- data/lib/gamebox/actor_factory.rb +4 -5
- data/lib/gamebox/actor_view.rb +8 -0
- data/lib/gamebox/actors/collidable_debugger.rb +2 -2
- data/lib/gamebox/actors/curtain.rb +3 -3
- data/lib/gamebox/actors/emitter.rb +51 -0
- data/lib/gamebox/actors/label.rb +27 -7
- data/lib/gamebox/actors/logo.rb +1 -1
- data/lib/gamebox/actors/spatial_debugger.rb +25 -10
- data/lib/gamebox/arbiter.rb +61 -34
- data/lib/gamebox/behavior.rb +3 -3
- data/lib/gamebox/behaviors/animated.rb +1 -1
- data/lib/gamebox/behaviors/audible.rb +1 -1
- data/lib/gamebox/behaviors/collidable.rb +9 -4
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +26 -1
- data/lib/gamebox/behaviors/collidable/circle_collidable.rb +3 -3
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
- data/lib/gamebox/behaviors/graphical.rb +30 -4
- data/lib/gamebox/behaviors/layered.rb +1 -1
- data/lib/gamebox/behaviors/physical.rb +113 -30
- data/lib/gamebox/behaviors/timed.rb +33 -0
- data/lib/gamebox/behaviors/updatable.rb +1 -1
- data/lib/gamebox/class_finder.rb +1 -21
- data/lib/gamebox/console_app.rb +33 -31
- data/lib/gamebox/constants.rb +481 -0
- data/lib/gamebox/data/config/objects.yml +7 -0
- data/lib/gamebox/gamebox_application.rb +10 -33
- data/lib/gamebox/gamebox_generator.rb +32 -32
- data/lib/gamebox/input_manager.rb +73 -32
- data/lib/gamebox/lib/inflector.rb +1 -1
- data/lib/gamebox/lib/range_ext.rb +5 -0
- data/lib/gamebox/lib/rect.rb +548 -548
- data/lib/gamebox/lib/sorted_list.rb +1 -1
- data/lib/gamebox/lib/symbol_ext.rb +8 -0
- data/lib/gamebox/physical_director.rb +1 -1
- data/lib/gamebox/physical_stage.rb +3 -3
- data/lib/gamebox/physics.rb +0 -3
- data/lib/gamebox/resource_manager.rb +22 -17
- data/lib/gamebox/sound_manager.rb +3 -2
- data/lib/gamebox/spatial_hash.rb +60 -31
- data/lib/gamebox/spatial_stagehand.rb +30 -6
- data/lib/gamebox/spec/helper.rb +7 -7
- data/lib/gamebox/stage.rb +18 -19
- data/lib/gamebox/stage_manager.rb +33 -23
- data/lib/gamebox/stagehand.rb +3 -0
- data/lib/gamebox/svg_document.rb +1 -1
- data/lib/gamebox/tasks/gamebox_tasks.rake +133 -0
- data/lib/gamebox/templates/actor.erb +0 -2
- data/lib/gamebox/templates/actor_view.erb +1 -3
- data/lib/gamebox/templates/template_app/Gemfile +3 -2
- data/lib/gamebox/templates/template_app/Rakefile +3 -8
- data/lib/gamebox/templates/template_app/config/environment.rb +7 -39
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -2
- data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -3
- data/lib/gamebox/version.rb +2 -2
- data/lib/gamebox/viewport.rb +44 -8
- data/lib/gamebox/views/graphical_actor_view.rb +22 -16
- data/lib/gamebox/wrapped_screen.rb +9 -1
- data/script/perf_spatial_hash.rb +49 -58
- data/script/perf_struct_vs_array.rb +32 -0
- data/spec/actor_factory_spec.rb +61 -0
- data/spec/actor_spec.rb +24 -18
- data/spec/actor_view_spec.rb +51 -6
- data/spec/animated_spec.rb +27 -6
- data/spec/arbiter_spec.rb +12 -24
- data/spec/backstage_spec.rb +1 -1
- data/spec/behavior_spec.rb +3 -3
- data/spec/class_finder_spec.rb +13 -0
- data/spec/collidable_spec.rb +30 -10
- data/spec/emitter_spec.rb +20 -0
- data/spec/helper.rb +5 -21
- data/spec/input_manager_spec.rb +134 -0
- data/spec/label_spec.rb +0 -1
- data/spec/physical_spec.rb +114 -5
- data/spec/resource_manager_spec.rb +1 -2
- data/spec/spatial_hash_spec.rb +23 -7
- data/spec/spatial_stagehand_spec.rb +97 -0
- data/spec/stage_manager_spec.rb +0 -1
- data/spec/stage_spec.rb +2 -2
- data/spec/viewport_spec.rb +92 -48
- metadata +223 -119
- data/.gitignore +0 -11
- data/History.txt +0 -80
- data/VERSION +0 -1
- data/lib/gamebox/event_compat.rb +0 -285
- data/lib/gamebox/lib/diy.rb +0 -371
- data/lib/gamebox/lib/numbers_ext.rb +0 -3
- data/lib/gamebox/tasks/gamebox_tasks.rb +0 -61
- data/load_paths.rb +0 -20
@@ -1,9 +1,9 @@
|
|
1
1
|
# Stage represent on level of game play. Some games will likely have only one
|
2
2
|
# stage. Stage is responsible for loading its background, props, and directors.
|
3
3
|
# PhysicalStage adds a physics space to the Stage
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
|
5
|
+
|
6
|
+
|
7
7
|
class PhysicalStage < Stage
|
8
8
|
|
9
9
|
attr_accessor :space
|
data/lib/gamebox/physics.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
$: << "#{File.dirname(__FILE__)}/../config"
|
3
2
|
require "fileutils"
|
4
|
-
require 'inflector'
|
5
|
-
require 'svg_document'
|
6
3
|
|
7
4
|
class ResourceManager
|
8
5
|
|
@@ -92,7 +89,7 @@ class ResourceManager
|
|
92
89
|
end
|
93
90
|
cached_img = Image.new(@window, full_name)
|
94
91
|
rescue Exception => ex
|
95
|
-
|
92
|
+
log "Cannot load image #{file_name}", :warn
|
96
93
|
end
|
97
94
|
@loaded_images[file_name] = cached_img
|
98
95
|
end
|
@@ -103,8 +100,8 @@ class ResourceManager
|
|
103
100
|
begin
|
104
101
|
music = Song.new(@window, full_name)
|
105
102
|
return music
|
106
|
-
rescue
|
107
|
-
|
103
|
+
rescue Exception => ex
|
104
|
+
log "Cannot load music " + full_name + " : " + ex, :warn
|
108
105
|
end
|
109
106
|
end
|
110
107
|
|
@@ -112,8 +109,8 @@ class ResourceManager
|
|
112
109
|
begin
|
113
110
|
sound = Sample.new(@window, full_name)
|
114
111
|
return sound
|
115
|
-
rescue
|
116
|
-
|
112
|
+
rescue Exception => ex
|
113
|
+
log "Cannot load sound " + full_name + " : " + ex.inspect, :warn
|
117
114
|
end
|
118
115
|
end
|
119
116
|
|
@@ -122,20 +119,23 @@ class ResourceManager
|
|
122
119
|
@loaded_fonts[name] ||= {}
|
123
120
|
return @loaded_fonts[name][size] if @loaded_fonts[name][size]
|
124
121
|
begin
|
125
|
-
|
126
|
-
|
127
|
-
if File.exist? full_name
|
128
|
-
font = Font.new(@window, full_name, size)
|
122
|
+
if name =~ /^\// and File.exists?(name)
|
123
|
+
font = Font.new(@window, name, size)
|
129
124
|
@loaded_fonts[name][size] = font
|
130
125
|
else
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
126
|
+
full_name = FONTS_PATH + name
|
127
|
+
if File.exist? full_name
|
128
|
+
font = Font.new(@window, full_name, size)
|
129
|
+
@loaded_fonts[name][size] = font
|
130
|
+
else
|
131
|
+
full_name = GAMEBOX_FONTS_PATH + name
|
132
|
+
font = Font.new(@window, full_name, size)
|
133
|
+
@loaded_fonts[name][size] = font
|
134
|
+
end
|
135
135
|
end
|
136
136
|
return font
|
137
137
|
rescue Exception => ex
|
138
|
-
|
138
|
+
debug "Cannot load font #{full_name}:#{ex}"
|
139
139
|
end
|
140
140
|
return nil
|
141
141
|
end
|
@@ -151,4 +151,9 @@ class ResourceManager
|
|
151
151
|
cached_svg
|
152
152
|
end
|
153
153
|
|
154
|
+
def load_tiles(filename, tile_width, tile_height)
|
155
|
+
Image.load_tiles @window, GFX_PATH+filename, tile_width, tile_height, true
|
156
|
+
end
|
157
|
+
|
158
|
+
|
154
159
|
end
|
@@ -5,6 +5,7 @@ class SoundManager
|
|
5
5
|
attr_accessor :sounds, :music
|
6
6
|
|
7
7
|
constructor :resource_manager, :config_manager
|
8
|
+
SUPPORTED_AUDIO_EXTS = %w(wav ogg mp3 au aiff caf)
|
8
9
|
|
9
10
|
# checks to see if sdl_mixer is availalbe and preloads the sounds and music directories.
|
10
11
|
def setup
|
@@ -14,7 +15,7 @@ class SoundManager
|
|
14
15
|
|
15
16
|
if @enabled
|
16
17
|
@music = {}
|
17
|
-
files = Dir.glob "#{MUSIC_PATH}
|
18
|
+
files = Dir.glob "#{MUSIC_PATH}**.{#{SUPPORTED_AUDIO_EXTS.join(',')}}"
|
18
19
|
for f in files
|
19
20
|
name = File.basename(f)
|
20
21
|
begin
|
@@ -27,7 +28,7 @@ class SoundManager
|
|
27
28
|
end if files
|
28
29
|
|
29
30
|
@sounds = {}
|
30
|
-
files = Dir.glob "#{SOUND_PATH}
|
31
|
+
files = Dir.glob "#{SOUND_PATH}**.{#{SUPPORTED_AUDIO_EXTS.join(',')}}"
|
31
32
|
for f in files
|
32
33
|
name = File.basename(f)
|
33
34
|
begin
|
data/lib/gamebox/spatial_hash.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
class SpatialHash
|
2
2
|
|
3
|
-
attr_reader :cell_size, :buckets
|
3
|
+
attr_reader :cell_size, :buckets, :items, :moved_items
|
4
4
|
attr_accessor :auto_resize
|
5
5
|
|
6
6
|
def initialize(cell_size, resize = false)
|
7
7
|
@cell_size = cell_size.to_f
|
8
8
|
@items = {}
|
9
|
-
@total_w = 0
|
10
|
-
@total_h = 0
|
11
9
|
@auto_resize = resize
|
10
|
+
|
11
|
+
if @auto_resize
|
12
|
+
@total_w = 0
|
13
|
+
@total_h = 0
|
14
|
+
end
|
15
|
+
@items = {}
|
16
|
+
@buckets = {}
|
12
17
|
rehash
|
13
18
|
end
|
14
19
|
|
@@ -18,6 +23,8 @@ class SpatialHash
|
|
18
23
|
end
|
19
24
|
|
20
25
|
def rehash
|
26
|
+
@moved_items = {}
|
27
|
+
return
|
21
28
|
items = @items
|
22
29
|
|
23
30
|
if @auto_resize
|
@@ -28,10 +35,11 @@ class SpatialHash
|
|
28
35
|
|
29
36
|
@cell_size = (avg_w+avg_h)
|
30
37
|
end
|
38
|
+
|
39
|
+
@total_w = 0
|
40
|
+
@total_h = 0
|
31
41
|
end
|
32
42
|
|
33
|
-
@total_w = 0
|
34
|
-
@total_h = 0
|
35
43
|
@items = {}
|
36
44
|
@buckets = {}
|
37
45
|
items.values.each do |item|
|
@@ -39,24 +47,53 @@ class SpatialHash
|
|
39
47
|
end
|
40
48
|
end
|
41
49
|
|
50
|
+
# does not remove or add event handlers
|
51
|
+
def move(item)
|
52
|
+
@moved_items[item] = item
|
53
|
+
_remove item
|
54
|
+
_add item
|
55
|
+
end
|
56
|
+
|
42
57
|
def add(item)
|
58
|
+
_add item
|
59
|
+
end
|
60
|
+
|
61
|
+
def _add(item)
|
43
62
|
buckets = lookup item
|
63
|
+
@items[item] = buckets
|
44
64
|
buckets.each do |bucket|
|
45
65
|
x,y = *bucket
|
46
66
|
@buckets[x] ||= {}
|
47
67
|
@buckets[x][y] ||= []
|
48
68
|
target_bucket = @buckets[x][y]
|
49
69
|
target_bucket << item
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
70
|
+
|
71
|
+
if @auto_resize
|
72
|
+
w = item.width if item.respond_to? :width
|
73
|
+
h = item.height if item.respond_to? :height
|
74
|
+
w ||= 1
|
75
|
+
h ||= 1
|
76
|
+
@total_w += w
|
77
|
+
@total_h += h
|
78
|
+
end
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
82
|
+
def remove(item)
|
83
|
+
@moved_items.delete item
|
84
|
+
_remove item
|
85
|
+
end
|
86
|
+
|
87
|
+
def _remove(item)
|
88
|
+
buckets = @items[item]
|
89
|
+
(buckets || []).each do |bucket|
|
90
|
+
x,y = *bucket
|
91
|
+
return if @buckets[x].nil? || @buckets[x][y].nil?
|
92
|
+
@buckets[x][y].delete item
|
93
|
+
end
|
94
|
+
@items.delete item
|
95
|
+
end
|
96
|
+
|
60
97
|
def lookup(item)
|
61
98
|
w = item.width if item.respond_to? :width
|
62
99
|
h = item.height if item.respond_to? :height
|
@@ -90,16 +127,6 @@ class SpatialHash
|
|
90
127
|
bucket_y = (y/cell_size).floor
|
91
128
|
return [bucket_x, bucket_y]
|
92
129
|
end
|
93
|
-
|
94
|
-
def remove(item)
|
95
|
-
buckets = lookup item
|
96
|
-
buckets.each do |bucket|
|
97
|
-
x,y = *bucket
|
98
|
-
return if @buckets[x].nil? || @buckets[x][y].nil?
|
99
|
-
@buckets[x][y].delete item
|
100
|
-
end
|
101
|
-
@items.delete item
|
102
|
-
end
|
103
130
|
|
104
131
|
def items_at(x,y)
|
105
132
|
bucket_x = (x/@cell_size).floor
|
@@ -126,20 +153,22 @@ class SpatialHash
|
|
126
153
|
end
|
127
154
|
|
128
155
|
def items_in_bucket_range(min_x,min_y,max_x,max_y)
|
129
|
-
items =
|
130
|
-
(
|
131
|
-
bucket_x = min_x + i
|
156
|
+
items = {}
|
157
|
+
(min_x+1..(max_x+1)).each do |bucket_x|
|
132
158
|
x_bucket = @buckets[bucket_x]
|
133
|
-
have_bucket_x = x_bucket.nil?
|
134
159
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
160
|
+
if x_bucket
|
161
|
+
(min_y+1..(max_y+1)).each do |bucket_y|
|
162
|
+
objects = x_bucket[bucket_y]
|
163
|
+
if objects
|
164
|
+
objects.each do |item|
|
165
|
+
items[item] = item
|
166
|
+
end
|
167
|
+
end
|
139
168
|
end
|
140
169
|
end
|
141
170
|
end
|
142
|
-
items.
|
171
|
+
items.values
|
143
172
|
end
|
144
173
|
|
145
174
|
# will look dist number of cells around all the cells
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
|
3
3
|
class SpatialStagehand < Stagehand
|
4
4
|
|
@@ -8,6 +8,8 @@ class SpatialStagehand < Stagehand
|
|
8
8
|
def setup
|
9
9
|
merged_opts = DEFAULT_PARAMS.merge opts
|
10
10
|
@spatial_actors = SpatialHash.new merged_opts[:cell_size]
|
11
|
+
# TODO
|
12
|
+
# delegate :items, :cell_size, :to => @spatial_actors
|
11
13
|
end
|
12
14
|
|
13
15
|
def cell_size
|
@@ -22,23 +24,45 @@ class SpatialStagehand < Stagehand
|
|
22
24
|
@spatial_actors.auto_resize = val
|
23
25
|
end
|
24
26
|
|
27
|
+
def auto_resize
|
28
|
+
@spatial_actors.auto_resize
|
29
|
+
end
|
30
|
+
|
31
|
+
def moved_items
|
32
|
+
@spatial_actors.moved_items.values
|
33
|
+
end
|
34
|
+
|
35
|
+
def items
|
36
|
+
@spatial_actors.items.values
|
37
|
+
end
|
38
|
+
|
25
39
|
def buckets
|
26
40
|
@spatial_actors.buckets
|
27
41
|
end
|
28
42
|
|
29
43
|
def add(actor)
|
30
|
-
|
31
|
-
|
32
|
-
|
44
|
+
# TODO change these to one event? position_changed?
|
45
|
+
# item.when :width_changed do |old_w, new_w|
|
46
|
+
# item.when :height_changed do |old_h, new_h|
|
47
|
+
|
48
|
+
actor.when :x_changed do |old_x, new_x|
|
49
|
+
move actor
|
50
|
+
end
|
51
|
+
actor.when :y_changed do |old_y, new_y|
|
52
|
+
move actor
|
33
53
|
end
|
54
|
+
actor.when :remove_me do
|
55
|
+
remove actor
|
56
|
+
end
|
57
|
+
@spatial_actors.add actor
|
34
58
|
end
|
35
59
|
|
36
60
|
def remove(actor)
|
37
61
|
@spatial_actors.remove actor
|
38
62
|
end
|
39
63
|
|
40
|
-
def
|
41
|
-
@spatial_actors.
|
64
|
+
def move(actor)
|
65
|
+
@spatial_actors.move actor
|
42
66
|
end
|
43
67
|
|
44
68
|
def items_at(x,y)
|
data/lib/gamebox/spec/helper.rb
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
module GameboxSpecHelpers
|
3
3
|
|
4
4
|
def create_actor(type, args = {})
|
5
|
-
InputManager.
|
5
|
+
InputManager.any_instance.stubs :setup
|
6
6
|
basic_opts = {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
7
|
+
stage: @stage = stub_everything,
|
8
|
+
input: @input_manager = InputManager.new(wrapped_screen: 'wrapped_screen', config_manager: 'config_manager'),
|
9
|
+
sound: @sound_manager = stub_everything,
|
10
|
+
director: @director = stub_everything,
|
11
|
+
resources: @resource_manager = stub_everything,
|
12
12
|
}.merge(args)
|
13
13
|
|
14
14
|
klass = ClassFinder.find(type)
|
@@ -20,6 +20,6 @@ module GameboxSpecHelpers
|
|
20
20
|
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
RSpec.configure do |configuration|
|
24
24
|
configuration.include GameboxSpecHelpers
|
25
25
|
end
|
data/lib/gamebox/stage.rb
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
require 'inflector'
|
2
|
-
require 'publisher'
|
3
|
-
require 'director'
|
4
|
-
require 'viewport'
|
5
|
-
require 'backstage'
|
6
|
-
require 'arbiter'
|
7
|
-
|
8
1
|
# Stage is a state that the game is in. (ie intro stage, multiplayer stage,
|
9
2
|
# single player stage).
|
10
3
|
class Stage
|
@@ -79,10 +72,9 @@ class Stage
|
|
79
72
|
@director.update time
|
80
73
|
@viewport.update time
|
81
74
|
@stagehands.each do |name, stagehand|
|
82
|
-
stagehand.update time
|
75
|
+
stagehand.update time
|
83
76
|
end
|
84
|
-
|
85
|
-
find_collisions unless @collidable_actors.nil?
|
77
|
+
find_collisions
|
86
78
|
update_timers time
|
87
79
|
end
|
88
80
|
|
@@ -119,6 +111,7 @@ class Stage
|
|
119
111
|
rescue Exception => ex
|
120
112
|
p drawable.class
|
121
113
|
p ex
|
114
|
+
p ex.backtrace
|
122
115
|
end
|
123
116
|
end
|
124
117
|
end
|
@@ -170,21 +163,27 @@ class Stage
|
|
170
163
|
end
|
171
164
|
|
172
165
|
# add block to be executed every interval_ms millis
|
166
|
+
# TODO make this hash based on object => name => block
|
167
|
+
# to clean up the timed behavior
|
173
168
|
def add_timer(name, interval_ms, &block)
|
174
|
-
@
|
175
|
-
@
|
169
|
+
@new_timers ||= {}
|
170
|
+
@new_timers[name] = {:count => 0,
|
176
171
|
:interval_ms => interval_ms, :callback => block}
|
177
172
|
end
|
178
173
|
|
179
174
|
# update each timers counts, call any blocks that are over their interval
|
180
175
|
def update_timers(time_delta)
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
176
|
+
# TODO handle overwriting the same timer name...
|
177
|
+
@timers ||= {}
|
178
|
+
if @new_timers
|
179
|
+
@timers.merge!(@new_timers)
|
180
|
+
@new_timers = nil
|
181
|
+
end
|
182
|
+
@timers.each do |name, timer_hash|
|
183
|
+
timer_hash[:count] += time_delta
|
184
|
+
if timer_hash[:count] > timer_hash[:interval_ms]
|
185
|
+
timer_hash[:count] -= timer_hash[:interval_ms]
|
186
|
+
timer_hash[:callback].call
|
188
187
|
end
|
189
188
|
end
|
190
189
|
end
|