gamebox 0.0.7 → 0.0.8

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 (53) hide show
  1. data/.gitignore +6 -0
  2. data/History.txt +6 -0
  3. data/Rakefile +25 -23
  4. data/TODO.txt +5 -3
  5. data/VERSION +1 -0
  6. data/bin/gamebox +2 -2
  7. data/docs/CODE_REVIEW +48 -0
  8. data/docs/getting_started.rdoc +30 -14
  9. data/gamebox.gemspec +184 -0
  10. data/lib/gamebox/actor.rb +29 -37
  11. data/lib/gamebox/actor_factory.rb +7 -24
  12. data/lib/gamebox/actors/curtain.rb +57 -0
  13. data/lib/gamebox/actors/label.rb +23 -0
  14. data/lib/gamebox/actors/score.rb +9 -5
  15. data/lib/gamebox/arbiter.rb +75 -0
  16. data/lib/gamebox/backstage.rb +17 -0
  17. data/lib/gamebox/behavior.rb +24 -1
  18. data/lib/gamebox/behaviors/animated.rb +2 -0
  19. data/lib/gamebox/behaviors/audible.rb +34 -0
  20. data/lib/gamebox/behaviors/collidable.rb +41 -0
  21. data/lib/gamebox/class_finder.rb +29 -0
  22. data/lib/gamebox/data/config/objects.yml +0 -1
  23. data/lib/gamebox/director.rb +13 -0
  24. data/lib/gamebox/gamebox_application.rb +2 -0
  25. data/lib/gamebox/input_manager.rb +58 -36
  26. data/lib/gamebox/{templates/template_app/lib → lib}/code_statistics.rb +0 -0
  27. data/lib/gamebox/lib/platform.rb +1 -0
  28. data/lib/gamebox/lib/surface_ext.rb +1 -1
  29. data/lib/gamebox/sound_manager.rb +11 -5
  30. data/lib/gamebox/spec/helper.rb +25 -0
  31. data/lib/gamebox/stage.rb +69 -2
  32. data/lib/gamebox/stage_manager.rb +6 -5
  33. data/lib/gamebox/tasks/gamebox_tasks.rb +18 -0
  34. data/lib/gamebox/templates/template_app/.gitignore +6 -0
  35. data/lib/gamebox/templates/template_app/README +3 -9
  36. data/lib/gamebox/templates/template_app/Rakefile +0 -13
  37. data/lib/gamebox/templates/template_app/spec/helper.rb +1 -1
  38. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -1
  39. data/lib/gamebox/version.rb +1 -1
  40. data/lib/gamebox/views/graphical_actor_view.rb +13 -21
  41. data/spec/actor_spec.rb +12 -4
  42. data/spec/actor_view_spec.rb +16 -0
  43. data/spec/animated_spec.rb +1 -0
  44. data/spec/backstage_spec.rb +45 -0
  45. data/spec/behavior_spec.rb +11 -0
  46. data/spec/collidable_spec.rb +15 -0
  47. data/spec/label_spec.rb +11 -0
  48. data/spec/resource_manager_spec.rb +14 -0
  49. data/spec/stage_spec.rb +65 -0
  50. metadata +66 -34
  51. data/Manifest.txt +0 -97
  52. data/lib/gamebox/ftor.rb +0 -2
  53. data/lib/gamebox/templates/template_app/lib/platform.rb +0 -16
@@ -0,0 +1,41 @@
1
+ require 'behavior'
2
+
3
+ class Collidable < Behavior
4
+
5
+ attr_accessor :shape, :radius, :width
6
+
7
+ def setup
8
+ @shape = opts[:shape]
9
+ @radius = opts[:radius]
10
+ @width = opts[:width]
11
+
12
+ collidable_obj = self
13
+
14
+ @actor.instance_eval do
15
+ (class << self; self; end).class_eval do
16
+ define_method :shape do |*args|
17
+ collidable_obj.shape *args
18
+ end
19
+ define_method :radius do |*args|
20
+ collidable_obj.radius *args
21
+ end
22
+ end
23
+ end
24
+
25
+ register_actor
26
+ end
27
+
28
+ def register_actor
29
+ @actor.stage.register_collidable @actor
30
+ end
31
+
32
+ def bounding_box
33
+ [ @actor.x-@width,@actor.y-@width,
34
+ @actor.x+@width,@actor.y+@width ]
35
+ end
36
+
37
+ def bounding_circle
38
+ [ @actor.x+@radius, @actor.y+@radius, @radius]
39
+ end
40
+
41
+ end
@@ -0,0 +1,29 @@
1
+ module ClassFinder
2
+
3
+ # Name is an underscore name string or symbol
4
+ def find(name)
5
+ klass = nil
6
+ klass_name = Inflector.camelize(name)
7
+
8
+ begin
9
+ klass = Object.const_get(klass_name)
10
+ rescue NameError
11
+ # not there yet
12
+ begin
13
+ require "#{name}"
14
+ rescue LoadError => ex
15
+ # maybe its included somewhere else
16
+ ensure
17
+ begin
18
+ klass = Object.const_get(klass_name)
19
+ rescue
20
+ # leave this alone.. maybe there isnt a NameView
21
+ end
22
+ end
23
+ end
24
+
25
+ klass
26
+ end
27
+ module_function :find
28
+
29
+ end
@@ -25,7 +25,6 @@ wrapped_screen:
25
25
  actor_factory:
26
26
  compose:
27
27
  - input_manager
28
- - sound_manager
29
28
  config_manager:
30
29
  compose:
31
30
  - resource_manager
@@ -34,6 +34,19 @@ class Director
34
34
  @actors.empty?
35
35
  end
36
36
 
37
+ def pause
38
+ @paused_actors = @actors
39
+ @actors = []
40
+ end
41
+
42
+ def unpause
43
+ unless @paused_actors.nil?
44
+ @actors.each{|actor| actor.remove_self }
45
+ @actors = @paused_actors
46
+ @paused_actors = nil
47
+ end
48
+ end
49
+
37
50
  def update(time)
38
51
  for act in @dead_actors
39
52
  @actors.delete act
@@ -16,7 +16,9 @@ require 'publisher_ext'
16
16
  require 'inflector'
17
17
  require 'constructor'
18
18
  require 'diy'
19
+ require 'class_finder'
19
20
  require 'actor_factory'
21
+ require 'input_manager'
20
22
 
21
23
  class GameboxApp
22
24
  attr_reader :context, :game
@@ -80,46 +80,54 @@ class InputManager
80
80
  loop do
81
81
  # add magic hooks
82
82
  @queue.each do |event|
83
- case event
84
- when KeyPressed
85
- case event.key
86
- when :f
87
- puts "Framerate:#{@clock.framerate}"
88
- when @auto_quit
89
- throw :rubygame_quit
90
- end
91
- when QuitRequested
92
- throw :rubygame_quit
93
- end
94
- fire :event_received, event
83
+ _handle_event(event)
84
+ end
95
85
 
96
- event_hooks = @hooks[event.class]
97
- id = event.key if event.respond_to? :key
86
+ game.update @clock.tick
87
+ end
88
+ end
89
+ end
98
90
 
99
- if event.respond_to? :button
100
- id ||= (MOUSE_BUTTON_LOOKUP[event.button] or event.button)
101
- end
91
+ def _handle_event(event) #:nodoc:
92
+ case event
93
+ when KeyPressed
94
+ case event.key
95
+ when :f
96
+ puts "Framerate:#{@clock.framerate}"
97
+ when @auto_quit
98
+ throw :rubygame_quit
99
+ end
100
+ when QuitRequested
101
+ throw :rubygame_quit
102
+ end
103
+ fire :event_received, event
102
104
 
103
- unless id.nil?
104
- event_action_hooks = event_hooks[id] if event_hooks
105
- if event_action_hooks
106
- for callback in event_action_hooks
107
- callback.call event
108
- end
109
- end
110
- end
111
-
112
- non_id_event_hooks = @non_id_hooks[event.class]
113
- if non_id_event_hooks
114
- for callback in non_id_event_hooks
115
- callback.call event
116
- end
117
- end
118
- end
105
+ # fix for pause bug?
106
+ @hooks ||= {}
107
+ @non_id_hooks ||= {}
119
108
 
120
- game.update @clock.tick
109
+ event_hooks = @hooks[event.class]
110
+ id = event.key if event.respond_to? :key
111
+
112
+ if event.respond_to? :button
113
+ id ||= (MOUSE_BUTTON_LOOKUP[event.button] or event.button)
114
+ end
115
+
116
+ unless id.nil?
117
+ event_action_hooks = event_hooks[id] if event_hooks
118
+ if event_action_hooks
119
+ for callback in event_action_hooks
120
+ callback.call event
121
+ end
121
122
  end
122
123
  end
124
+
125
+ non_id_event_hooks = @non_id_hooks[event.class]
126
+ if non_id_event_hooks
127
+ for callback in non_id_event_hooks
128
+ callback.call event
129
+ end
130
+ end
123
131
  end
124
132
 
125
133
  # registers a block to be called when matching events are pulled from the SDL queue.
@@ -197,11 +205,25 @@ class InputManager
197
205
  # autohook a boolean to be set to true while a key is pressed
198
206
  def while_key_pressed(key, target, accessor)
199
207
  _register_hook target, KeyPressed, key do
200
- target.send accessor.to_s+"=", true
208
+ target.send "#{accessor}=", true
201
209
  end
202
210
  _register_hook target, KeyReleased, key do
203
- target.send accessor.to_s+"=", false
211
+ target.send "#{accessor}=", false
204
212
  end
205
213
  end
206
214
 
215
+ def pause
216
+ @paused_hooks = @hooks
217
+ @paused_non_id_hooks = @non_id_hooks
218
+ @hooks = {}
219
+ @non_id_hooks = {}
220
+ end
221
+
222
+ def unpause
223
+ @hooks = @paused_hooks
224
+ @non_id_hooks = @paused_non_id_hooks
225
+ @paused_hooks = nil
226
+ @paused_non_id_hooks = nil
227
+ end
228
+
207
229
  end
@@ -1,4 +1,5 @@
1
1
  # Helper functions for determining platform
2
+
2
3
  class Platform
3
4
  def self.mac?
4
5
  return RUBY_PLATFORM =~ /darwin/
@@ -1,4 +1,4 @@
1
- require 'ftor'
1
+ require 'rubygame/ftor'
2
2
  include Rubygame::Color
3
3
  module Rubygame
4
4
  class Surface
@@ -48,23 +48,26 @@ class SoundManager
48
48
 
49
49
  # plays the sound based on the name with the specified volume level.
50
50
  # play_sound :foo # play sound at 100% volume
51
- def play_sound(what, volume=nil)
51
+ def play_sound(what, opts={})
52
52
  if @enabled && @sounds[what]
53
+ volume = opts.delete :volume
53
54
  @sound_thread = Thread.new do
54
55
  @sounds[what].volume = volume if volume
55
- @sounds[what].play
56
+ @sounds[what].play opts
56
57
  end
57
58
  end
58
59
  end
59
60
 
60
61
  # plays the music based on the name with the specified volume level.
61
62
  # will loop until SoundManager#stop_music is called.
62
- # play_music :foo, 0.8 # play music at 80% volumne
63
- def play_music(what, volume=nil)
63
+ # play_music :foo, :volume => 0.8 # play music at 80% volumne
64
+ def play_music(what, opts={})
64
65
  if @enabled && @music[what]
66
+ volume = opts.delete :volume
67
+ opts[:repeats] = -1 unless opts[:repeat]
65
68
  @music_thread = Thread.new do
66
69
  @music[what].volume = volume if volume
67
- @music[what].play :repeats => -1
70
+ @music[what].play opts
68
71
  end
69
72
  end
70
73
  end
@@ -85,4 +88,7 @@ class SoundManager
85
88
  end
86
89
  end
87
90
 
91
+ # TODO
92
+ # def pause_all_sounds;end
93
+
88
94
  end
@@ -0,0 +1,25 @@
1
+ # Helper methods and classes for writing specs for your gamebox application
2
+ module GameboxSpecHelpers
3
+
4
+ def create_actor(type, args = {})
5
+ InputManager.stub :setup
6
+ basic_opts = {
7
+ :stage => @stage = stub.as_null_object,
8
+ :input => @input_manager = InputManager.new(:config_manager => "config_manager"),
9
+ :sound => @sound_manager = stub.as_null_object,
10
+ :director => @director = stub.as_null_object,
11
+ :resources => @resource_manager = stub.as_null_object
12
+ }.merge(args)
13
+
14
+ klass = ClassFinder.find(type)
15
+
16
+ raise "Could not find actor class #{type}" unless klass
17
+
18
+ klass.new(basic_opts)
19
+ end
20
+
21
+ end
22
+
23
+ Spec::Runner.configure do |configuration|
24
+ configuration.include GameboxSpecHelpers
25
+ end
data/lib/gamebox/stage.rb CHANGED
@@ -2,16 +2,20 @@ require 'inflector'
2
2
  require 'publisher'
3
3
  require 'director'
4
4
  require 'viewport'
5
+ require 'backstage'
6
+ require 'arbiter'
7
+
5
8
  # Stage is a state that the game is in. (ie intro stage, multiplayer stage,
6
9
  # single player stage).
7
10
  class Stage
11
+ include Arbiter
8
12
  extend Publisher
9
13
  can_fire_anything
10
14
 
11
15
  attr_accessor :drawables, :resource_manager, :sound_manager,
12
- :director, :opts, :viewport, :input_manager
16
+ :director, :opts, :viewport, :input_manager, :backstage
13
17
 
14
- def initialize(input_manager, actor_factory, resource_manager, sound_manager, config_manager, opts)
18
+ def initialize(input_manager, actor_factory, resource_manager, sound_manager, config_manager, backstage, opts)
15
19
  @input_manager = input_manager
16
20
 
17
21
  @resource_manager = resource_manager
@@ -24,6 +28,7 @@ class Stage
24
28
  @actor_factory = actor_factory
25
29
  @director = create_director
26
30
  @actor_factory.director = @director
31
+ @backstage = backstage
27
32
 
28
33
  @opts = opts
29
34
 
@@ -72,6 +77,8 @@ class Stage
72
77
  def update(time)
73
78
  @director.update time
74
79
  @viewport.update time
80
+ find_collisions unless @collidable_actors.nil?
81
+ update_timers time
75
82
  end
76
83
 
77
84
  def curtain_raising(*args)
@@ -139,5 +146,65 @@ class Stage
139
146
  prev_drawable_list
140
147
 
141
148
  end
149
+
150
+ def remove_timer(name)
151
+ @timers ||= {}
152
+ @timers.delete name
153
+ end
154
+
155
+ def timer(name)
156
+ @timers ||= {}
157
+ @timers[name]
158
+ end
159
+
160
+ # add block to be executed every interval_ms millis
161
+ def add_timer(name, interval_ms, &block)
162
+ @timers ||= {}
163
+ @timers[name] = {:count => 0,
164
+ :interval_ms => interval_ms, :callback => block}
165
+ end
166
+
167
+ # update each timers counts, call any blocks that are over their interval
168
+ def update_timers(time_delta)
169
+ unless @timers.nil?
170
+ @timers.each do |name, timer_hash|
171
+ timer_hash[:count] += time_delta
172
+ if timer_hash[:count] > timer_hash[:interval_ms]
173
+ timer_hash[:count] -= timer_hash[:interval_ms]
174
+ timer_hash[:callback].call
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ def on_pause(&block)
181
+ @pause_listeners ||= []
182
+ @pause_listeners << block if block_given?
183
+ end
184
+
185
+ def on_unpause(&block)
186
+ @unpause_listeners ||= []
187
+ @unpause_listeners << block if block_given?
188
+ end
189
+
190
+ def pause
191
+ @director.pause
192
+ @input_manager.pause
193
+ @paused_timers = @timers
194
+ @timers = nil
195
+ @pause_listeners.each do |listener|
196
+ listener.call
197
+ end
198
+ end
199
+
200
+ def unpause
201
+ @director.unpause
202
+ @input_manager.unpause
203
+ @timers = @paused_timers
204
+ @paused_timers = nil
205
+ @unpause_listeners.each do |listener|
206
+ listener.call
207
+ end
208
+ end
142
209
  end
143
210
 
@@ -7,6 +7,7 @@ class StageManager
7
7
 
8
8
  def setup
9
9
  @stages = {}
10
+ @backstage = Backstage.new
10
11
 
11
12
  @actor_factory.stage_manager = self
12
13
  stages = @resource_manager.load_config('stage_config')[:stages]
@@ -41,7 +42,7 @@ class StageManager
41
42
  end
42
43
 
43
44
  def create_stage(name, opts)
44
- stage_instance = lookup_stage_class(name).new(@input_manager, @actor_factory, @resource_manager, @sound_manager, @config_manager, opts)
45
+ stage_instance = lookup_stage_class(name).new(@input_manager, @actor_factory, @resource_manager, @sound_manager, @config_manager, @backstage, opts)
45
46
 
46
47
  stage_instance.when :next_stage do |*args|
47
48
  next_stage *args
@@ -56,24 +57,24 @@ class StageManager
56
57
  stage_instance
57
58
  end
58
59
 
59
- def next_stage
60
+ def next_stage(*args)
60
61
  index = @stage_names.index @stage
61
62
  if index == @stage_names.size-1
62
63
  puts "last stage, exiting"
63
64
  exit
64
65
  end
65
66
  @stages.delete @stage_names[index+1]
66
- change_stage_to @stage_names[index+1]
67
+ change_stage_to @stage_names[index+1], *args
67
68
  end
68
69
 
69
- def prev_stage
70
+ def prev_stage(*args)
70
71
  index = @stage_names.index @stage
71
72
  if index == 0
72
73
  puts "first stage, exiting"
73
74
  exit
74
75
  end
75
76
  @stages.delete @stage_names[index-1]
76
- change_stage_to @stage_names[index-1]
77
+ change_stage_to @stage_names[index-1], *args
77
78
  end
78
79
 
79
80
  def restart_stage(*args)