gamebox 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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)