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.
Files changed (74) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -0
  3. data/History.txt +5 -0
  4. data/README.txt +4 -3
  5. data/Rakefile +12 -4
  6. data/TODO.txt +1 -5
  7. data/VERSION +1 -1
  8. data/docs/getting_started.rdoc +2 -2
  9. data/gamebox.gemspec +26 -10
  10. data/lib/gamebox/actor.rb +10 -3
  11. data/lib/gamebox/actor_factory.rb +2 -2
  12. data/lib/gamebox/actor_view.rb +14 -11
  13. data/lib/gamebox/actors/collidable_debugger.rb +35 -0
  14. data/lib/gamebox/actors/curtain.rb +2 -2
  15. data/lib/gamebox/actors/logo.rb +0 -6
  16. data/lib/gamebox/actors/score.rb +2 -5
  17. data/lib/gamebox/actors/spatial_debugger.rb +47 -0
  18. data/lib/gamebox/actors/svg_actor.rb +4 -6
  19. data/lib/gamebox/arbiter.rb +108 -15
  20. data/lib/gamebox/behavior.rb +29 -1
  21. data/lib/gamebox/behaviors/animated.rb +14 -23
  22. data/lib/gamebox/behaviors/audible.rb +1 -12
  23. data/lib/gamebox/behaviors/collidable.rb +29 -22
  24. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +61 -0
  25. data/lib/gamebox/behaviors/collidable/circle_collidable.rb +17 -0
  26. data/lib/gamebox/behaviors/collidable/collidable_shape.rb +35 -0
  27. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +85 -0
  28. data/lib/gamebox/behaviors/graphical.rb +13 -10
  29. data/lib/gamebox/behaviors/layered.rb +6 -20
  30. data/lib/gamebox/behaviors/physical.rb +116 -93
  31. data/lib/gamebox/class_finder.rb +6 -2
  32. data/lib/gamebox/config_manager.rb +24 -4
  33. data/lib/gamebox/data/config/objects.yml +5 -3
  34. data/lib/gamebox/ftor.rb +372 -0
  35. data/lib/gamebox/gamebox_application.rb +2 -8
  36. data/lib/gamebox/hooked_gosu_window.rb +30 -0
  37. data/lib/gamebox/input_manager.rb +78 -79
  38. data/lib/gamebox/lib/code_statistics.rb +1 -1
  39. data/lib/gamebox/lib/numbers_ext.rb +1 -1
  40. data/lib/gamebox/lib/rect.rb +612 -0
  41. data/lib/gamebox/physical_stage.rb +12 -2
  42. data/lib/gamebox/physics.rb +14 -3
  43. data/lib/gamebox/resource_manager.rb +28 -65
  44. data/lib/gamebox/sound_manager.rb +7 -13
  45. data/lib/gamebox/spatial_hash.rb +60 -14
  46. data/lib/gamebox/spatial_stagehand.rb +19 -0
  47. data/lib/gamebox/stage.rb +16 -1
  48. data/lib/gamebox/stage_manager.rb +1 -1
  49. data/lib/gamebox/svg_document.rb +1 -0
  50. data/lib/gamebox/tasks/gamebox_tasks.rb +23 -11
  51. data/lib/gamebox/templates/template_app/.gitignore +1 -0
  52. data/lib/gamebox/templates/template_app/Gemfile +1 -1
  53. data/lib/gamebox/templates/template_app/Rakefile +6 -21
  54. data/lib/gamebox/templates/template_app/config/environment.rb +14 -0
  55. data/lib/gamebox/templates/template_app/config/game.yml +2 -1
  56. data/lib/gamebox/templates/template_app/script/generate +0 -3
  57. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -11
  58. data/lib/gamebox/templates/template_app/src/game.rb +0 -1
  59. data/lib/gamebox/templates/template_app/src/my_actor.rb +2 -2
  60. data/lib/gamebox/version.rb +1 -1
  61. data/lib/gamebox/views/graphical_actor_view.rb +15 -9
  62. data/lib/gamebox/wrapped_screen.rb +114 -7
  63. data/load_paths.rb +20 -0
  64. data/script/perf_spatial_hash.rb +73 -0
  65. data/spec/actor_view_spec.rb +1 -1
  66. data/spec/arbiter_spec.rb +264 -0
  67. data/spec/behavior_spec.rb +19 -2
  68. data/spec/collidable_spec.rb +105 -5
  69. data/spec/helper.rb +1 -1
  70. data/spec/label_spec.rb +1 -1
  71. data/spec/resource_manager_spec.rb +1 -1
  72. data/spec/spatial_hash_spec.rb +1 -1
  73. metadata +52 -10
  74. 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
@@ -1,10 +1,21 @@
1
1
  require 'chipmunk'
2
2
 
3
- #require 'numbers_ext'
4
- include CP
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
- def initialize
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
- tileset = load_image "#{actor_dir}/#{action}.png"
49
+ tileset_name = "#{actor_dir}/#{action}.png"
50
+ tileset = load_image tileset_name
46
51
 
47
52
  action_imgs = []
48
- w,h = *tileset.size
49
- color = tileset.get_at 0, 0
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
- clip_from = Rubygame::Rect.new(0, 0, w, w)
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
- clip_from = Rubygame::Rect.new(0, 0, h, h)
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
- #cached_img = Rubygame::Surface.load(File.expand_path(GFX_PATH + file_name))
104
- cached_img = Rubygame::Surface.load(GFX_PATH + file_name)
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
- #check global gamebox location
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
- sound = Rubygame::Music.load(full_name)
118
- return sound
119
- rescue Rubygame::SDLError => ex
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 = Rubygame::Sound.load(full_name)
113
+ sound = Sample.new(@window, full_name)
127
114
  return sound
128
- rescue Rubygame::SDLError => ex
115
+ rescue Excpetion => ex
129
116
  puts "Cannot load sound " + full_name + " : " + ex
130
117
  end
131
118
  end
132
119
 
133
- # loads TTF fonts from the fonts dir and caches them for later
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
- begin
145
- font = TTF.new(full_name, size)
127
+ if File.exist? full_name
128
+ font = Font.new(@window, full_name, size)
146
129
  @loaded_fonts[name][size] = font
147
- rescue Exception => ex
130
+ else
148
131
  #full_name = File.expand_path(GAMEBOX_FONTS_PATH + name)
149
132
  full_name = GAMEBOX_FONTS_PATH + name
150
- font = TTF.new(full_name, size)
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
- (@enabled = (Rubygame::VERSIONS[:sdl_mixer] != nil))
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
- volume = opts.delete :volume
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
- opts[:repeats] = -1 unless opts[:repeat]
68
- @music_thread = Thread.new do
69
- @music[what].volume = volume if volume
70
- @music[what].play opts
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
 
@@ -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
- @buckets = {}
8
- @items = []
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
- @items = []
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
- unless target_bucket.include? item
33
- target_bucket << item
34
- @items << item
35
- end
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 << [min_x+i,min_y+j]
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 @buckets[bucket_x].nil? || @buckets[bucket_x][bucket_y].nil?
109
- items << @buckets[bucket_x][bucket_y]
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
@@ -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
- drawable.draw target, trans_x, trans_y
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={})