gamebox 0.1.1 → 0.2.1
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/.gitignore +4 -0
- data/Gemfile +9 -0
- data/History.txt +5 -0
- data/README.txt +4 -3
- data/Rakefile +12 -4
- data/TODO.txt +1 -5
- data/VERSION +1 -1
- data/docs/getting_started.rdoc +2 -2
- data/gamebox.gemspec +26 -10
- data/lib/gamebox/actor.rb +10 -3
- data/lib/gamebox/actor_factory.rb +2 -2
- data/lib/gamebox/actor_view.rb +14 -11
- data/lib/gamebox/actors/collidable_debugger.rb +35 -0
- data/lib/gamebox/actors/curtain.rb +2 -2
- data/lib/gamebox/actors/logo.rb +0 -6
- data/lib/gamebox/actors/score.rb +2 -5
- data/lib/gamebox/actors/spatial_debugger.rb +47 -0
- data/lib/gamebox/actors/svg_actor.rb +4 -6
- data/lib/gamebox/arbiter.rb +108 -15
- data/lib/gamebox/behavior.rb +29 -1
- data/lib/gamebox/behaviors/animated.rb +14 -23
- data/lib/gamebox/behaviors/audible.rb +1 -12
- data/lib/gamebox/behaviors/collidable.rb +29 -22
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +61 -0
- data/lib/gamebox/behaviors/collidable/circle_collidable.rb +17 -0
- data/lib/gamebox/behaviors/collidable/collidable_shape.rb +35 -0
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +85 -0
- data/lib/gamebox/behaviors/graphical.rb +13 -10
- data/lib/gamebox/behaviors/layered.rb +6 -20
- data/lib/gamebox/behaviors/physical.rb +116 -93
- data/lib/gamebox/class_finder.rb +6 -2
- data/lib/gamebox/config_manager.rb +24 -4
- data/lib/gamebox/data/config/objects.yml +5 -3
- data/lib/gamebox/ftor.rb +372 -0
- data/lib/gamebox/gamebox_application.rb +2 -8
- data/lib/gamebox/hooked_gosu_window.rb +30 -0
- data/lib/gamebox/input_manager.rb +78 -79
- data/lib/gamebox/lib/code_statistics.rb +1 -1
- data/lib/gamebox/lib/numbers_ext.rb +1 -1
- data/lib/gamebox/lib/rect.rb +612 -0
- data/lib/gamebox/physical_stage.rb +12 -2
- data/lib/gamebox/physics.rb +14 -3
- data/lib/gamebox/resource_manager.rb +28 -65
- data/lib/gamebox/sound_manager.rb +7 -13
- data/lib/gamebox/spatial_hash.rb +60 -14
- data/lib/gamebox/spatial_stagehand.rb +19 -0
- data/lib/gamebox/stage.rb +16 -1
- data/lib/gamebox/stage_manager.rb +1 -1
- data/lib/gamebox/svg_document.rb +1 -0
- data/lib/gamebox/tasks/gamebox_tasks.rb +23 -11
- data/lib/gamebox/templates/template_app/.gitignore +1 -0
- data/lib/gamebox/templates/template_app/Gemfile +1 -1
- data/lib/gamebox/templates/template_app/Rakefile +6 -21
- data/lib/gamebox/templates/template_app/config/environment.rb +14 -0
- data/lib/gamebox/templates/template_app/config/game.yml +2 -1
- data/lib/gamebox/templates/template_app/script/generate +0 -3
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -11
- data/lib/gamebox/templates/template_app/src/game.rb +0 -1
- data/lib/gamebox/templates/template_app/src/my_actor.rb +2 -2
- data/lib/gamebox/version.rb +1 -1
- data/lib/gamebox/views/graphical_actor_view.rb +15 -9
- data/lib/gamebox/wrapped_screen.rb +114 -7
- data/load_paths.rb +20 -0
- data/script/perf_spatial_hash.rb +73 -0
- data/spec/actor_view_spec.rb +1 -1
- data/spec/arbiter_spec.rb +264 -0
- data/spec/behavior_spec.rb +19 -2
- data/spec/collidable_spec.rb +105 -5
- data/spec/helper.rb +1 -1
- data/spec/label_spec.rb +1 -1
- data/spec/resource_manager_spec.rb +1 -1
- data/spec/spatial_hash_spec.rb +1 -1
- metadata +52 -10
- data/lib/gamebox/lib/surface_ext.rb +0 -76
@@ -14,7 +14,7 @@ class PhysicalStage < Stage
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def setup_space
|
17
|
-
@space = Space.new
|
17
|
+
@space = CP::Space.new
|
18
18
|
@space.iterations = 20
|
19
19
|
@space.elastic_iterations = 5
|
20
20
|
end
|
@@ -44,7 +44,7 @@ class PhysicalStage < Stage
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def update(time)
|
47
|
-
update_physics time
|
47
|
+
update_physics time
|
48
48
|
super
|
49
49
|
end
|
50
50
|
|
@@ -97,4 +97,14 @@ class PhysicalStage < Stage
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
+
def pause
|
101
|
+
pause_physics
|
102
|
+
super
|
103
|
+
end
|
104
|
+
|
105
|
+
def unpause
|
106
|
+
super
|
107
|
+
restart_physics
|
108
|
+
end
|
109
|
+
|
100
110
|
end
|
data/lib/gamebox/physics.rb
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
require 'chipmunk'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
def vec2(*args)
|
5
|
+
CP::Vec2.new *args
|
6
|
+
end
|
7
|
+
|
8
|
+
def moment_for_circle(*args)
|
9
|
+
CP.moment_for_circle(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def moment_for_poly(*args)
|
13
|
+
CP.moment_for_poly(*args)
|
14
|
+
end
|
15
|
+
|
5
16
|
ZERO_VEC_2 = vec2(0,0)
|
6
17
|
|
7
|
-
class Space
|
18
|
+
class CP::Space
|
8
19
|
alias :add_collision_func_old :add_collision_func
|
9
20
|
|
10
21
|
# allows for passing arrays of collision types not just single ones
|
@@ -5,10 +5,14 @@ require 'inflector'
|
|
5
5
|
require 'svg_document'
|
6
6
|
|
7
7
|
class ResourceManager
|
8
|
-
|
8
|
+
|
9
|
+
constructor :wrapped_screen
|
10
|
+
|
11
|
+
def setup
|
9
12
|
@loaded_images = {}
|
10
13
|
@loaded_fonts = {}
|
11
14
|
@loaded_svgs = {}
|
15
|
+
@window = @wrapped_screen.screen
|
12
16
|
end
|
13
17
|
|
14
18
|
def load_actor_image(actor)
|
@@ -42,40 +46,21 @@ class ResourceManager
|
|
42
46
|
#
|
43
47
|
def load_tile_set(actor, action)
|
44
48
|
actor_dir = Inflector.underscore(actor.class)
|
45
|
-
|
49
|
+
tileset_name = "#{actor_dir}/#{action}.png"
|
50
|
+
tileset = load_image tileset_name
|
46
51
|
|
47
52
|
action_imgs = []
|
48
|
-
w
|
49
|
-
|
53
|
+
w = tileset.width
|
54
|
+
h = tileset.height
|
50
55
|
|
51
56
|
if h > w
|
52
57
|
# down
|
53
58
|
num_frames = h/w
|
54
|
-
|
55
|
-
clip_to = Rubygame::Rect.new(0, 0, w, w)
|
56
|
-
num_frames.times do
|
57
|
-
surface = Rubygame::Surface.new(clip_to.size)
|
58
|
-
surface.fill color
|
59
|
-
tileset.blit surface, clip_to, clip_from
|
60
|
-
surface.set_colorkey color
|
61
|
-
surface = surface.to_display_alpha
|
62
|
-
action_imgs << surface
|
63
|
-
clip_from.y += w
|
64
|
-
end
|
59
|
+
action_imgs = Image.load_tiles @window, GFX_PATH+tileset_name, -1, -num_frames, true
|
65
60
|
else
|
66
61
|
# right
|
67
62
|
num_frames = w/h
|
68
|
-
|
69
|
-
clip_to = Rubygame::Rect.new(0, 0, h, h)
|
70
|
-
num_frames.times do
|
71
|
-
surface = Rubygame::Surface.new(clip_to.size)
|
72
|
-
surface.fill color
|
73
|
-
tileset.blit surface, clip_to, clip_from
|
74
|
-
surface.set_colorkey color
|
75
|
-
surface = surface.to_display_alpha
|
76
|
-
action_imgs << surface
|
77
|
-
clip_from.x += h
|
78
|
-
end
|
63
|
+
action_imgs = Image.load_tiles @window, GFX_PATH+tileset_name, -num_frames, -1, true
|
79
64
|
end
|
80
65
|
|
81
66
|
action_imgs
|
@@ -100,12 +85,14 @@ class ResourceManager
|
|
100
85
|
cached_img = @loaded_images[file_name]
|
101
86
|
if cached_img.nil?
|
102
87
|
begin
|
103
|
-
|
104
|
-
|
88
|
+
full_name = GFX_PATH + file_name
|
89
|
+
if ! File.exist? full_name
|
90
|
+
#check global gamebox location
|
91
|
+
full_name = GAMEBOX_GFX_PATH + file_name
|
92
|
+
end
|
93
|
+
cached_img = Image.new(@window, full_name)
|
105
94
|
rescue Exception => ex
|
106
|
-
|
107
|
-
#cached_img = Rubygame::Surface.load(File.expand_path(GAMEBOX_GFX_PATH + file_name))
|
108
|
-
cached_img = Rubygame::Surface.load(GAMEBOX_GFX_PATH + file_name)
|
95
|
+
puts "Cannot load image #{file_name}"
|
109
96
|
end
|
110
97
|
@loaded_images[file_name] = cached_img
|
111
98
|
end
|
@@ -114,40 +101,36 @@ class ResourceManager
|
|
114
101
|
|
115
102
|
def load_music(full_name)
|
116
103
|
begin
|
117
|
-
|
118
|
-
return
|
119
|
-
rescue
|
104
|
+
music = Song.new(@window, full_name)
|
105
|
+
return music
|
106
|
+
rescue Excpetion => ex
|
120
107
|
puts "Cannot load music " + full_name + " : " + ex
|
121
108
|
end
|
122
109
|
end
|
123
110
|
|
124
111
|
def load_sound(full_name)
|
125
112
|
begin
|
126
|
-
sound =
|
113
|
+
sound = Sample.new(@window, full_name)
|
127
114
|
return sound
|
128
|
-
rescue
|
115
|
+
rescue Excpetion => ex
|
129
116
|
puts "Cannot load sound " + full_name + " : " + ex
|
130
117
|
end
|
131
118
|
end
|
132
119
|
|
133
|
-
# loads
|
120
|
+
# loads fonts from the fonts dir and caches them for later
|
134
121
|
def load_font(name, size)
|
135
122
|
@loaded_fonts[name] ||= {}
|
136
123
|
return @loaded_fonts[name][size] if @loaded_fonts[name][size]
|
137
124
|
begin
|
138
|
-
unless @ttf_loaded
|
139
|
-
TTF.setup
|
140
|
-
@ttf_loaded = true
|
141
|
-
end
|
142
125
|
#full_name = File.expand_path(FONTS_PATH + name)
|
143
126
|
full_name = FONTS_PATH + name
|
144
|
-
|
145
|
-
font =
|
127
|
+
if File.exist? full_name
|
128
|
+
font = Font.new(@window, full_name, size)
|
146
129
|
@loaded_fonts[name][size] = font
|
147
|
-
|
130
|
+
else
|
148
131
|
#full_name = File.expand_path(GAMEBOX_FONTS_PATH + name)
|
149
132
|
full_name = GAMEBOX_FONTS_PATH + name
|
150
|
-
font =
|
133
|
+
font = Font.new(@window, full_name, size)
|
151
134
|
@loaded_fonts[name][size] = font
|
152
135
|
end
|
153
136
|
return font
|
@@ -157,26 +140,6 @@ class ResourceManager
|
|
157
140
|
return nil
|
158
141
|
end
|
159
142
|
|
160
|
-
# TODO make this path include that app name?
|
161
|
-
def load_config(name)
|
162
|
-
conf = YAML::load_file(CONFIG_PATH + name + ".yml")
|
163
|
-
user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
|
164
|
-
if File.exist? user_file
|
165
|
-
user_conf = YAML::load_file user_file
|
166
|
-
conf = conf.merge user_conf
|
167
|
-
end
|
168
|
-
conf
|
169
|
-
end
|
170
|
-
|
171
|
-
def save_settings(name, settings)
|
172
|
-
user_gamebox_dir = "#{ENV['HOME']}/.gamebox"
|
173
|
-
FileUtils.mkdir_p user_gamebox_dir
|
174
|
-
user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
|
175
|
-
File.open user_file, "w" do |f|
|
176
|
-
f.write settings.to_yaml
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
143
|
def load_svg(file_name)
|
181
144
|
# TODO create LEVEL_PATH in environment
|
182
145
|
cached_svg = @loaded_svgs[file_name]
|
@@ -9,9 +9,8 @@ class SoundManager
|
|
9
9
|
# checks to see if sdl_mixer is availalbe and preloads the sounds and music directories.
|
10
10
|
def setup
|
11
11
|
|
12
|
-
puts 'Warning, sound disabled' unless
|
13
|
-
|
14
|
-
@enabled = (@enabled and (@config_manager.settings[:sound].nil? or @config_manager.settings[:sound] == true))
|
12
|
+
puts 'CHANGE TO LOG:Warning, sound disabled' unless
|
13
|
+
@enabled = (@config_manager.settings[:sound].nil? or @config_manager.settings[:sound] == true)
|
15
14
|
|
16
15
|
if @enabled
|
17
16
|
@music = {}
|
@@ -50,11 +49,7 @@ class SoundManager
|
|
50
49
|
# play_sound :foo # play sound at 100% volume
|
51
50
|
def play_sound(what, opts={})
|
52
51
|
if @enabled && @sounds[what]
|
53
|
-
|
54
|
-
@sound_thread = Thread.new do
|
55
|
-
@sounds[what].volume = volume if volume
|
56
|
-
@sounds[what].play opts
|
57
|
-
end
|
52
|
+
@sounds[what].play #opts
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
@@ -64,11 +59,10 @@ class SoundManager
|
|
64
59
|
def play_music(what, opts={})
|
65
60
|
if @enabled && @music[what]
|
66
61
|
volume = opts.delete :volume
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
62
|
+
repeat = opts[:repeat]
|
63
|
+
repeat ||= false
|
64
|
+
@music[what].volume = volume if volume
|
65
|
+
@music[what].play repeat
|
72
66
|
end
|
73
67
|
end
|
74
68
|
|
data/lib/gamebox/spatial_hash.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
class SpatialHash
|
2
2
|
|
3
|
-
attr_reader :cell_size
|
3
|
+
attr_reader :cell_size, :buckets
|
4
|
+
attr_accessor :auto_resize
|
4
5
|
|
5
|
-
def initialize(cell_size)
|
6
|
+
def initialize(cell_size, resize = false)
|
6
7
|
@cell_size = cell_size.to_f
|
7
|
-
@
|
8
|
-
@
|
8
|
+
@items = {}
|
9
|
+
@total_w = 0
|
10
|
+
@total_h = 0
|
11
|
+
@auto_resize = resize
|
12
|
+
rehash
|
9
13
|
end
|
10
14
|
|
11
15
|
def cell_size=(new_size)
|
@@ -15,9 +19,22 @@ class SpatialHash
|
|
15
19
|
|
16
20
|
def rehash
|
17
21
|
items = @items
|
18
|
-
|
22
|
+
|
23
|
+
if @auto_resize
|
24
|
+
# recommeded cell size == 2 x avg obj size
|
25
|
+
if @total_w > 0 && items.size > 0
|
26
|
+
avg_w = @total_w / items.size
|
27
|
+
avg_h = @total_h / items.size
|
28
|
+
|
29
|
+
@cell_size = (avg_w+avg_h)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
@total_w = 0
|
34
|
+
@total_h = 0
|
35
|
+
@items = {}
|
19
36
|
@buckets = {}
|
20
|
-
items.each do |item|
|
37
|
+
items.values.each do |item|
|
21
38
|
add item
|
22
39
|
end
|
23
40
|
end
|
@@ -29,10 +46,14 @@ class SpatialHash
|
|
29
46
|
@buckets[x] ||= {}
|
30
47
|
@buckets[x][y] ||= []
|
31
48
|
target_bucket = @buckets[x][y]
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
target_bucket << item
|
50
|
+
@items[item] = item
|
51
|
+
w = item.width if item.respond_to? :width
|
52
|
+
h = item.height if item.respond_to? :height
|
53
|
+
w ||= 1
|
54
|
+
h ||= 1
|
55
|
+
@total_w += w
|
56
|
+
@total_h += h
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
@@ -55,8 +76,9 @@ class SpatialHash
|
|
55
76
|
|
56
77
|
buckets = []
|
57
78
|
(max_x-min_x+1).times do |i|
|
79
|
+
bucket_x = min_x + i
|
58
80
|
(max_y-min_y+1).times do |j|
|
59
|
-
buckets << [
|
81
|
+
buckets << [bucket_x,min_y+j]
|
60
82
|
end
|
61
83
|
end
|
62
84
|
|
@@ -100,18 +122,42 @@ class SpatialHash
|
|
100
122
|
max_x, max_y = bucket_for x+w-1, y+h-1
|
101
123
|
end
|
102
124
|
|
125
|
+
items_in_bucket_range min_x, min_y, max_x, max_y
|
126
|
+
end
|
127
|
+
|
128
|
+
def items_in_bucket_range(min_x,min_y,max_x,max_y)
|
103
129
|
items = []
|
104
130
|
(max_x-min_x+1).times do |i|
|
131
|
+
bucket_x = min_x + i
|
132
|
+
x_bucket = @buckets[bucket_x]
|
133
|
+
have_bucket_x = x_bucket.nil?
|
134
|
+
|
105
135
|
(max_y-min_y+1).times do |j|
|
106
|
-
bucket_x = min_x + i
|
107
136
|
bucket_y = min_y + j
|
108
|
-
unless
|
109
|
-
items <<
|
137
|
+
unless have_bucket_x || x_bucket[bucket_y].nil?
|
138
|
+
items << x_bucket[bucket_y]
|
110
139
|
end
|
111
140
|
end
|
112
141
|
end
|
113
142
|
items.flatten.uniq
|
114
143
|
end
|
115
144
|
|
145
|
+
# will look dist number of cells around all the cells
|
146
|
+
# occupied by the item
|
147
|
+
def neighbors_of(item, dist=1)
|
148
|
+
buckets = lookup(item)
|
149
|
+
min_bucket_x, min_bucket_y = *buckets.first
|
150
|
+
max_bucket_x, max_bucket_y = *buckets.last
|
151
|
+
|
152
|
+
min_bucket_x = min_bucket_x-1
|
153
|
+
min_bucket_y = min_bucket_y-1
|
154
|
+
|
155
|
+
max_bucket_x = max_bucket_x+1
|
156
|
+
max_bucket_y = max_bucket_y+1
|
157
|
+
|
158
|
+
items = items_in_bucket_range min_bucket_x, min_bucket_y, max_bucket_x, max_bucket_y
|
159
|
+
items-[item]
|
160
|
+
end
|
161
|
+
|
116
162
|
end
|
117
163
|
|
@@ -14,8 +14,23 @@ class SpatialStagehand < Stagehand
|
|
14
14
|
@spatial_actors.cell_size
|
15
15
|
end
|
16
16
|
|
17
|
+
def cell_size=(new_size)
|
18
|
+
@spatial_actors.cell_size = new_size
|
19
|
+
end
|
20
|
+
|
21
|
+
def auto_resize=(val)
|
22
|
+
@spatial_actors.auto_resize = val
|
23
|
+
end
|
24
|
+
|
25
|
+
def buckets
|
26
|
+
@spatial_actors.buckets
|
27
|
+
end
|
28
|
+
|
17
29
|
def add(actor)
|
18
30
|
@spatial_actors.add actor
|
31
|
+
actor.when :remove_me do
|
32
|
+
@spatial_actors.remove actor
|
33
|
+
end
|
19
34
|
end
|
20
35
|
|
21
36
|
def remove(actor)
|
@@ -34,4 +49,8 @@ class SpatialStagehand < Stagehand
|
|
34
49
|
@spatial_actors.items_in x, y, w, h
|
35
50
|
end
|
36
51
|
|
52
|
+
def neighbors_of(item, dist=1)
|
53
|
+
@spatial_actors.neighbors_of item, dist
|
54
|
+
end
|
55
|
+
|
37
56
|
end
|
data/lib/gamebox/stage.rb
CHANGED
@@ -101,6 +101,7 @@ class Stage
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def draw(target)
|
104
|
+
z = 0
|
104
105
|
@drawables.keys.sort.reverse.each do |parallax_layer|
|
105
106
|
|
106
107
|
drawables_on_parallax_layer = @drawables[parallax_layer]
|
@@ -111,8 +112,14 @@ class Stage
|
|
111
112
|
trans_x = @viewport.x_offset parallax_layer
|
112
113
|
trans_y = @viewport.y_offset parallax_layer
|
113
114
|
|
115
|
+
z += 1
|
114
116
|
drawables_on_parallax_layer[layer].each do |drawable|
|
115
|
-
|
117
|
+
begin
|
118
|
+
drawable.draw target, trans_x, trans_y, z
|
119
|
+
rescue Exception => ex
|
120
|
+
p drawable.class
|
121
|
+
p ex
|
122
|
+
end
|
116
123
|
end
|
117
124
|
end
|
118
125
|
end
|
@@ -192,7 +199,13 @@ class Stage
|
|
192
199
|
@unpause_listeners << block if block_given?
|
193
200
|
end
|
194
201
|
|
202
|
+
def paused?
|
203
|
+
@pause
|
204
|
+
end
|
205
|
+
|
195
206
|
def pause
|
207
|
+
@pause_listeners ||= []
|
208
|
+
@paused = true
|
196
209
|
@director.pause
|
197
210
|
@input_manager.pause
|
198
211
|
@paused_timers = @timers
|
@@ -203,6 +216,7 @@ class Stage
|
|
203
216
|
end
|
204
217
|
|
205
218
|
def unpause
|
219
|
+
@unpause_listeners ||= []
|
206
220
|
@director.unpause
|
207
221
|
@input_manager.unpause
|
208
222
|
@timers = @paused_timers
|
@@ -210,6 +224,7 @@ class Stage
|
|
210
224
|
@unpause_listeners.each do |listener|
|
211
225
|
listener.call
|
212
226
|
end
|
227
|
+
@paused = true
|
213
228
|
end
|
214
229
|
|
215
230
|
def stagehand(stagehand_sym, opts={})
|