gamebox 0.3.4 → 0.4.0.rc1

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 (184) hide show
  1. data/README.rdoc +38 -0
  2. data/Rakefile +1 -10
  3. data/TODO.txt +6 -6
  4. data/app_generators/gamebox_generator.rb +95 -0
  5. data/{lib/gamebox/templates/template_app → app_generators/templates}/.gitignore +0 -0
  6. data/app_generators/templates/Gemfile +7 -0
  7. data/app_generators/templates/NEXT_STEPS.txt +1 -0
  8. data/{lib/gamebox/templates/template_app/README → app_generators/templates/README.rdoc} +0 -0
  9. data/{lib/gamebox/templates/template_app → app_generators/templates}/Rakefile +0 -0
  10. data/{lib/gamebox/templates/template_app → app_generators/templates}/config/boot.rb +0 -0
  11. data/app_generators/templates/config/environment.rb +30 -0
  12. data/{lib/gamebox/templates/template_app → app_generators/templates}/config/game.yml +0 -0
  13. data/{lib/gamebox/templates/template_app → app_generators/templates}/data/fonts/FONTS_GO_HERE +0 -0
  14. data/{lib/gamebox/templates/template_app → app_generators/templates}/data/graphics/GRAPHICS_GO_HERE +0 -0
  15. data/{lib/gamebox/templates/template_app → app_generators/templates}/data/music/MUSIC_GOES_HERE +0 -0
  16. data/{lib/gamebox/templates/template_app → app_generators/templates}/data/sounds/SOUND_FX_GO_HERE +0 -0
  17. data/{lib/gamebox/templates → app_generators/templates/script}/actor.erb +0 -0
  18. data/{lib/gamebox/templates → app_generators/templates/script}/actor_spec.erb +0 -0
  19. data/{lib/gamebox/templates → app_generators/templates/script}/actor_view.erb +0 -0
  20. data/{lib/gamebox/templates → app_generators/templates/script}/actor_view_spec.erb +0 -0
  21. data/app_generators/templates/script/generate +12 -0
  22. data/{lib/gamebox/templates/template_app → app_generators/templates}/spec/helper.rb +0 -0
  23. data/app_generators/templates/src/actors/player.rb +8 -0
  24. data/{lib/gamebox/templates/template_app → app_generators/templates}/src/app.rb +0 -0
  25. data/app_generators/templates/src/demo_stage.rb +7 -0
  26. data/bin/gamebox +8 -70
  27. data/component_generators/actor_generator.rb +17 -0
  28. data/docs/CODE_REVIEW +1 -1
  29. data/docs/REFACTOR_NOTES.txt +25 -0
  30. data/docs/getting_started.rdoc +1 -1
  31. data/gamebox.gemspec +7 -4
  32. data/lib/gamebox.rb +6 -3
  33. data/lib/gamebox/actors/collidable_debugger.rb +13 -15
  34. data/lib/gamebox/actors/curtain.rb +44 -43
  35. data/lib/gamebox/actors/emitter.rb +3 -42
  36. data/lib/gamebox/actors/fps.rb +13 -6
  37. data/lib/gamebox/actors/label.rb +42 -34
  38. data/lib/gamebox/actors/logo.rb +2 -4
  39. data/lib/gamebox/actors/score.rb +37 -27
  40. data/lib/gamebox/actors/svg_actor.rb +45 -32
  41. data/lib/gamebox/behaviors/animated.rb +39 -59
  42. data/lib/gamebox/behaviors/audible.rb +14 -14
  43. data/lib/gamebox/behaviors/collidable.rb +65 -36
  44. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +2 -3
  45. data/lib/gamebox/behaviors/collidable/collidable_shape.rb +6 -4
  46. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
  47. data/lib/gamebox/behaviors/emitting.rb +48 -0
  48. data/lib/gamebox/behaviors/graphical.rb +22 -56
  49. data/lib/gamebox/behaviors/layered.rb +8 -21
  50. data/lib/gamebox/behaviors/physical.rb +202 -213
  51. data/lib/gamebox/behaviors/positioned.rb +16 -0
  52. data/lib/gamebox/behaviors/projectile.rb +15 -0
  53. data/lib/gamebox/behaviors/visible.rb +16 -0
  54. data/lib/gamebox/core/aabb_helpers.rb +61 -0
  55. data/lib/gamebox/core/aabb_node.rb +118 -0
  56. data/lib/gamebox/core/aabb_tree.rb +137 -0
  57. data/lib/gamebox/core/actor.rb +102 -0
  58. data/lib/gamebox/core/actor_factory.rb +56 -0
  59. data/lib/gamebox/core/actor_view.rb +63 -0
  60. data/lib/gamebox/core/actor_view_factory.rb +40 -0
  61. data/lib/gamebox/{arbiter.rb → core/arbiter.rb} +31 -34
  62. data/lib/gamebox/{backstage.rb → core/backstage.rb} +0 -0
  63. data/lib/gamebox/core/behavior.rb +64 -0
  64. data/lib/gamebox/core/behavior_factory.rb +56 -0
  65. data/lib/gamebox/{class_finder.rb → core/class_finder.rb} +0 -0
  66. data/lib/gamebox/{config_manager.rb → core/config_manager.rb} +1 -1
  67. data/lib/gamebox/core/configuration.rb +39 -0
  68. data/lib/gamebox/core/core.rb +30 -0
  69. data/lib/gamebox/core/deprecated.rb +15 -0
  70. data/lib/gamebox/{director.rb → core/director.rb} +6 -11
  71. data/lib/gamebox/core/font_style.rb +26 -0
  72. data/lib/gamebox/core/font_style_factory.rb +11 -0
  73. data/lib/gamebox/core/game.rb +19 -0
  74. data/lib/gamebox/{hooked_gosu_window.rb → core/hooked_gosu_window.rb} +12 -6
  75. data/lib/gamebox/{input_manager.rb → core/input_manager.rb} +106 -99
  76. data/lib/gamebox/core/physics.rb +22 -0
  77. data/lib/gamebox/{physical_stage.rb → core/physics_manager.rb} +36 -30
  78. data/lib/gamebox/{resource_manager.rb → core/resource_manager.rb} +19 -18
  79. data/lib/gamebox/{sound_manager.rb → core/sound_manager.rb} +9 -7
  80. data/lib/gamebox/{stage.rb → core/stage.rb} +42 -80
  81. data/lib/gamebox/{stage_manager.rb → core/stage_manager.rb} +46 -53
  82. data/lib/gamebox/{stagehand.rb → core/stagehand.rb} +0 -0
  83. data/lib/gamebox/{svg_document.rb → core/svg_document.rb} +0 -0
  84. data/lib/gamebox/core/timer_manager.rb +50 -0
  85. data/lib/gamebox/{viewport.rb → core/viewport.rb} +2 -3
  86. data/lib/gamebox/{wrapped_screen.rb → core/wrapped_screen.rb} +12 -19
  87. data/lib/gamebox/gamebox_application.rb +7 -15
  88. data/lib/gamebox/lib/evented_attributes.rb +51 -0
  89. data/lib/gamebox/{ftor.rb → lib/ftor.rb} +0 -0
  90. data/lib/gamebox/lib/min_max_helpers.rb +10 -0
  91. data/lib/gamebox/lib/rect.rb +112 -54
  92. data/lib/gamebox/lib/yoda.rb +46 -0
  93. data/lib/gamebox/spec/helper.rb +317 -12
  94. data/lib/gamebox/stagehands/spatial_tree_stagehand.rb +61 -0
  95. data/lib/gamebox/version.rb +8 -3
  96. data/lib/gamebox/views/graphical_actor_view.rb +22 -29
  97. data/script/perf_aabb.rb +56 -0
  98. data/script/perf_array_access.rb +16 -0
  99. data/script/perf_collisions.rb +37 -18
  100. data/script/perf_struct_vs_array.rb +7 -7
  101. data/spec/acceptance/animation_spec.rb +65 -0
  102. data/spec/acceptance/basic_actor_lifecycle_spec.rb +92 -0
  103. data/spec/acceptance/built_in_collision_handling_spec.rb +55 -0
  104. data/spec/acceptance/chipmunk_collision_handling_spec.rb +83 -0
  105. data/spec/acceptance/fps_actor_spec.rb +40 -0
  106. data/spec/acceptance/pausing_spec.rb +61 -0
  107. data/spec/acceptance/timer_usage_spec.rb +53 -0
  108. data/spec/actors/emitter_spec.rb +5 -0
  109. data/spec/{label_spec.rb → actors/label_spec.rb} +1 -1
  110. data/spec/behaviors/animated_spec.rb +85 -0
  111. data/spec/behaviors/collidable_spec.rb +134 -0
  112. data/spec/{physical_spec.rb → behaviors/physical_spec.rb} +2 -1
  113. data/spec/behaviors/positioned_spec.rb +6 -0
  114. data/spec/behaviors/projectile_spec.rb +6 -0
  115. data/spec/core/aabb_tree_spec.rb +109 -0
  116. data/spec/core/actor_factory_spec.rb +44 -0
  117. data/spec/core/actor_spec.rb +78 -0
  118. data/spec/core/actor_view_spec.rb +53 -0
  119. data/spec/{arbiter_spec.rb → core/arbiter_spec.rb} +29 -30
  120. data/spec/core/backstage_spec.rb +37 -0
  121. data/spec/core/behavior_factory_spec.rb +50 -0
  122. data/spec/core/behavior_spec.rb +8 -0
  123. data/spec/core/configuration_spec.rb +8 -0
  124. data/spec/core/core_spec.rb +13 -0
  125. data/spec/core/font_style_factory_spec.rb +17 -0
  126. data/spec/core/font_style_spec.rb +41 -0
  127. data/spec/core/hooked_gosu_window_spec.rb +75 -0
  128. data/spec/core/input_manager_spec.rb +285 -0
  129. data/spec/core/physics_manager_spec.rb +11 -0
  130. data/spec/core/resource_manager_spec.rb +12 -0
  131. data/spec/core/stage_manager_spec.rb +140 -0
  132. data/spec/core/stage_spec.rb +73 -0
  133. data/spec/core/timer_manager_spec.rb +89 -0
  134. data/spec/{viewport_spec.rb → core/viewport_spec.rb} +6 -3
  135. data/spec/core/wrapped_screen_spec.rb +26 -0
  136. data/spec/fixtures/game.yml +7 -0
  137. data/spec/fixtures/snelpling/idle/1.png +0 -0
  138. data/spec/fixtures/snelpling/jump/1.png +0 -0
  139. data/spec/fixtures/snelpling/jump/2.png +0 -0
  140. data/spec/fixtures/snelpling/jump/3.png +0 -0
  141. data/spec/helper.rb +8 -0
  142. data/spec/{class_finder_spec.rb → lib/class_finder_spec.rb} +2 -1
  143. data/spec/stagehands/spatial_tree_stagehand_spec.rb +19 -0
  144. data/spec/views/graphical_actor_view_spec.rb +116 -0
  145. metadata +343 -144
  146. data/README.txt +0 -34
  147. data/lib/gamebox/actor.rb +0 -179
  148. data/lib/gamebox/actor_factory.rb +0 -57
  149. data/lib/gamebox/actor_view.rb +0 -44
  150. data/lib/gamebox/actors/spatial_debugger.rb +0 -62
  151. data/lib/gamebox/behavior.rb +0 -70
  152. data/lib/gamebox/behaviors/timed.rb +0 -33
  153. data/lib/gamebox/behaviors/updatable.rb +0 -12
  154. data/lib/gamebox/console_app.rb +0 -41
  155. data/lib/gamebox/gamebox_generator.rb +0 -32
  156. data/lib/gamebox/generators/actor_generator.rb +0 -43
  157. data/lib/gamebox/generators/view_generator.rb +0 -42
  158. data/lib/gamebox/physical_director.rb +0 -17
  159. data/lib/gamebox/physics.rb +0 -32
  160. data/lib/gamebox/spatial_bucket.rb +0 -9
  161. data/lib/gamebox/spatial_hash.rb +0 -194
  162. data/lib/gamebox/spatial_stagehand.rb +0 -80
  163. data/lib/gamebox/templates/template_app/Gemfile +0 -6
  164. data/lib/gamebox/templates/template_app/config/environment.rb +0 -23
  165. data/lib/gamebox/templates/template_app/config/stage_config.yml +0 -2
  166. data/lib/gamebox/templates/template_app/script/generate +0 -7
  167. data/lib/gamebox/templates/template_app/src/demo_stage.rb +0 -11
  168. data/lib/gamebox/templates/template_app/src/game.rb +0 -19
  169. data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -14
  170. data/script/perf_spatial_hash.rb +0 -64
  171. data/spec/actor_factory_spec.rb +0 -61
  172. data/spec/actor_spec.rb +0 -71
  173. data/spec/actor_view_spec.rb +0 -61
  174. data/spec/animated_spec.rb +0 -83
  175. data/spec/backstage_spec.rb +0 -45
  176. data/spec/behavior_spec.rb +0 -28
  177. data/spec/collidable_spec.rb +0 -135
  178. data/spec/emitter_spec.rb +0 -20
  179. data/spec/input_manager_spec.rb +0 -134
  180. data/spec/resource_manager_spec.rb +0 -13
  181. data/spec/spatial_hash_spec.rb +0 -119
  182. data/spec/spatial_stagehand_spec.rb +0 -93
  183. data/spec/stage_manager_spec.rb +0 -25
  184. data/spec/stage_spec.rb +0 -65
@@ -0,0 +1,56 @@
1
+
2
+ # ActorFactory is responsible for loading all Actors. It also creates the ActorView
3
+ # associated with the Actor and registers it to the Stage be drawn.
4
+ class ActorFactory
5
+ construct_with :input_manager, :wrapped_screen, :resource_manager,
6
+ :behavior_factory, :actor_view_factory, :this_object_context
7
+
8
+ # returns the newly created Actor after it and its ActorView has been created.
9
+ def build(actor, opts={})
10
+ merged_opts = opts.merge(actor_type: actor)
11
+
12
+ model = nil
13
+ this_object_context.in_subcontext do |actor_context|
14
+ begin
15
+ model = actor_context[:actor]
16
+
17
+ actor_definition = Actor.definitions[actor]
18
+ raise "#{actor} not found in Actor.definitions" if actor_definition.nil?
19
+ model.configure(merged_opts)
20
+
21
+ actor_definition.behaviors.each do |behavior|
22
+ beh_opts = {}
23
+ beh_key = behavior
24
+
25
+ if behavior.is_a?(Hash)
26
+ beh_opts = behavior.values.first
27
+ beh_key = behavior.keys.first
28
+ end
29
+
30
+ behavior_factory.add_behavior(model, beh_key, beh_opts)
31
+ end
32
+
33
+ actor_view_factory.build model, opts
34
+ rescue Exception => e
35
+ # binding.pry
36
+ raise """
37
+ #{actor} not found:
38
+ #{e.inspect}
39
+ #{e.backtrace[0..6].join("\n")}
40
+ """
41
+ end
42
+ end
43
+ model
44
+ end
45
+
46
+ def class_ancestors(actor)
47
+ klass = actor.class
48
+ [].tap { |actor_klasses|
49
+ while klass != Actor
50
+ actor_klasses << klass
51
+ klass = klass.superclass
52
+ end
53
+ }
54
+ end
55
+
56
+ end
@@ -0,0 +1,63 @@
1
+ class ActorView
2
+ construct_with :stage, :wrapped_screen, :resource_manager, :actor
3
+ public :stage, :wrapped_screen, :resource_manager, :actor
4
+
5
+ attr_accessor :layer, :parallax
6
+ def initialize
7
+ @layer = actor.do_or_do_not(:layer) || 0
8
+ @parallax = actor.do_or_do_not(:parallax) || 1
9
+
10
+ # TODO clean up the show/hide here make nice with visible behavior?
11
+ actor.when :remove_me do unregister end
12
+ actor.when :hide_me do unregister end
13
+ actor.when :show_me do register end
14
+
15
+ end
16
+
17
+ def register
18
+ stage.register_drawable self
19
+ end
20
+
21
+ def unregister
22
+ stage.unregister_drawable self
23
+ end
24
+
25
+ def screen_width
26
+ @screen_width ||= wrapped_screen.width
27
+ end
28
+
29
+ def screen_height
30
+ @screen_height ||= wrapped_screen.height
31
+ end
32
+
33
+ class << self
34
+ def define(actor_view_type, &blk)
35
+ @definitions ||= {}
36
+ definition = ActorViewDefinition.new
37
+ definition.instance_eval &blk if block_given?
38
+ @definitions[actor_view_type] = definition
39
+ end
40
+
41
+ def definitions
42
+ @definitions ||= {}
43
+ end
44
+ end
45
+
46
+ # TODO can these defs be unified?
47
+ class ActorViewDefinition
48
+ attr_accessor :draw_block, :configure_block, :required_injections
49
+ def requires(*injections_needed)
50
+ @required_injections = injections_needed
51
+ end
52
+
53
+ def configure(&configure_block)
54
+ @configure_block = configure_block
55
+ end
56
+
57
+ def draw(&draw_block)
58
+ @draw_block = draw_block
59
+ end
60
+ end
61
+
62
+
63
+ end
@@ -0,0 +1,40 @@
1
+
2
+ # ActorViewFactory is responsible for loading all ActorViews. It creates the ActorView
3
+ # associated with the Actor and registers it to the Stage be drawn.
4
+ class ActorViewFactory
5
+ construct_with :behavior_factory
6
+
7
+ # builds a new ActorView and configures it per its definition that is setup via ActorView.define
8
+ def build(actor, opts={})
9
+ # TODO have animated, graphical, physical set a view attr on actor
10
+ view_klass = opts[:view] || actor.do_or_do_not(:view) || "#{actor.actor_type}_view"
11
+ view_definition = ActorView.definitions[view_klass.to_sym]
12
+ view = nil
13
+ if view_definition
14
+ actor_context = actor.this_object_context
15
+ view = actor_context[:actor_view]
16
+ reqs = view_definition.required_injections
17
+ if reqs
18
+ reqs.each do |req|
19
+ object = actor_context[req]
20
+ view.define_singleton_method req do
21
+ components[req]
22
+ end
23
+ components = view.send :components
24
+ components[req] = object
25
+ end
26
+ end
27
+
28
+ view.define_singleton_method :draw, &view_definition.draw_block if view_definition.draw_block
29
+ if view_definition.configure_block
30
+ view.define_singleton_method :configure, &view_definition.configure_block
31
+ view.configure
32
+ end
33
+
34
+ behavior_factory.add_behavior(actor, :visible, view: view)
35
+ actor.react_to :show unless opts[:hide]
36
+ end
37
+ view
38
+ end
39
+
40
+ end
@@ -3,11 +3,11 @@ module Arbiter
3
3
  attr_reader :checks, :collisions
4
4
 
5
5
  def register_collidable(actor)
6
- stagehand(:spatial).add(actor)
6
+ stagehand(:spatial_tree).add(actor)
7
7
  end
8
8
 
9
9
  def unregister_collidable(actor)
10
- stagehand(:spatial).remove(actor)
10
+ stagehand(:spatial_tree).remove(actor)
11
11
  end
12
12
 
13
13
  def on_collision_of(first_objs, second_objs, &block)
@@ -52,35 +52,33 @@ module Arbiter
52
52
  end
53
53
  end
54
54
 
55
+ def interested_in_collision_of?(type1, type2)
56
+ @collision_handlers ||= {}
57
+ (@collision_handlers[type1] && @collision_handlers[type1][type2]) ||
58
+ (@collision_handlers[type2] && @collision_handlers[type2][type1])
59
+ end
60
+
55
61
  def find_collisions
56
- spatial_hash = stagehand(:spatial)
57
- collidable_actors = spatial_hash.moved_items
58
- @checks = 0
59
- @collisions = 0
62
+ aabb_tree = stagehand(:spatial_tree)
63
+ collidable_actors = aabb_tree.moved_items.values
64
+
60
65
  collisions = {}
61
66
 
62
67
  collidable_actors.each do |first|
63
- x = first.x - spatial_hash.cell_size
64
- y = first.y - spatial_hash.cell_size
65
- # TODO base this on size of object
66
- w = spatial_hash.cell_size * 3
67
- h = w
68
-
69
- tmp_collidable_actors = spatial_hash.neighbors_of(first)
70
-
71
- if first.is? :collidable
72
- tmp_collidable_actors.each do |second|
73
- @checks += 1
74
- if second.is? :collidable
75
- if first != second && collide?(first, second)
76
- collisions[second] ||= []
77
- if !collisions[second].include?(first)
78
- @collisions += 1
68
+ # if first.is? :collidable
69
+ # HUH? it appears that querying modifies the tree somehow?
70
+ aabb_tree.collisions(first) do |second|
71
+
72
+ # if second.is? :collidable
73
+ if first != second &&
74
+ interested_in_collision_of?(first.actor_type, second.actor_type) &&
75
+ collide?(first, second)
76
+ if !collisions[second] || (collisions[second] && !collisions[second].include?(first))
79
77
  collisions[first] ||= []
80
78
  collisions[first] << second
81
79
  end
82
- end
83
- end
80
+ # end
81
+ # end
84
82
  end
85
83
  end
86
84
  end
@@ -90,17 +88,16 @@ module Arbiter
90
88
  unique_collisions << [first,second]
91
89
  end
92
90
  end
93
-
94
91
  run_callbacks unique_collisions
92
+ aabb_tree.reset
95
93
  end
96
94
 
95
+
96
+
97
97
  def collide?(object, other)
98
- if !other.is? :collidable
99
- binding.pry
100
- end
101
- case object.collidable_shape
98
+ case object.shape_type
102
99
  when :circle
103
- case other.collidable_shape
100
+ case other.shape_type
104
101
  when :circle
105
102
  collide_circle_circle? object, other
106
103
  when :aabb
@@ -109,7 +106,7 @@ module Arbiter
109
106
  collide_circle_polygon? object, other
110
107
  end
111
108
  when :aabb
112
- case other.collidable_shape
109
+ case other.shape_type
113
110
  when :circle
114
111
  collide_aabb_circle? object, other
115
112
  when :aabb
@@ -118,7 +115,7 @@ module Arbiter
118
115
  collide_aabb_polygon? object, other
119
116
  end
120
117
  when :polygon
121
- case other.collidable_shape
118
+ case other.shape_type
122
119
  when :circle
123
120
  collide_polygon_circle? object, other
124
121
  when :aabb
@@ -159,8 +156,8 @@ module Arbiter
159
156
 
160
157
  # returns true if the projections overlap
161
158
  def project_and_detect(axis, a, b)
162
- a_min, a_max = send("#{a.collidable_shape}_interval", axis, a)
163
- b_min, b_max = send("#{b.collidable_shape}_interval", axis, b)
159
+ a_min, a_max = send("#{a.shape_type}_interval", axis, a)
160
+ b_min, b_max = send("#{b.shape_type}_interval", axis, b)
164
161
 
165
162
  a_min <= b_max && b_min <= a_max
166
163
  end
File without changes
@@ -0,0 +1,64 @@
1
+ # Behavior is any type of behavior an actor can exibit.
2
+ class Behavior
3
+ construct_with :actor
4
+
5
+ attr_accessor :opts
6
+
7
+ def configure(opts={})
8
+ @opts = opts
9
+ setup
10
+ end
11
+
12
+ def setup
13
+ end
14
+
15
+ def reacts_with(*messages_with_methods)
16
+ @message_handlers = messages_with_methods
17
+ end
18
+
19
+ def react_to(message_type, *opts)
20
+ # TODO perf analysis, should I use a hash here?
21
+ if @message_handlers && @message_handlers.include?(message_type)
22
+ send message_type, *opts
23
+ end
24
+ end
25
+
26
+ class << self
27
+
28
+ def define(behavior_type, &blk)
29
+ @definitions ||= {}
30
+ definition = BehaviorDefinition.new
31
+ definition.instance_eval &blk if block_given?
32
+ @definitions[behavior_type] = definition
33
+ end
34
+
35
+ def definitions
36
+ @definitions ||= {}
37
+ end
38
+ end
39
+
40
+ class BehaviorDefinition
41
+ attr_accessor :setup_block, :required_injections, :react_to_block, :required_behaviors,
42
+ :helpers_block
43
+
44
+ def requires(*injections_needed)
45
+ @required_injections = injections_needed
46
+ end
47
+
48
+ def requires_behaviors(*behaviors_needed)
49
+ @required_behaviors = behaviors_needed
50
+ end
51
+
52
+ def setup(&setup_block)
53
+ @setup_block = setup_block
54
+ end
55
+
56
+ def react_to(&react_to_block)
57
+ @react_to_block = react_to_block
58
+ end
59
+
60
+ def helpers(&helpers_block)
61
+ @helpers_block = helpers_block
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,56 @@
1
+ # BehaviorFactory is in charge of creating all behaviors and placing them in an Actor.
2
+ # Everything you want an Actor to _do_ is part of a Behavior. Actors are stupid buckets of data.
3
+ # Behaviors can be created by:
4
+ # has_behavior in an Actor's class definition
5
+ # or by dynamically creating one at runtime via another behavior.
6
+ class BehaviorFactory
7
+
8
+ # Build a behavior. Takes a symbol or a Hash.
9
+ # add_behavior(:shootable) or add_behavior(:shootable => {:range=>3})
10
+ # this will create a new instance of Shootable and pass
11
+ # :range=>3 to it
12
+ def add_behavior(actor, behavior_name, opts = {})
13
+ raise "nil actor" if actor.nil?
14
+ raise "nil behavior definition" if behavior_name.nil?
15
+
16
+ behavior_definition = Behavior.definitions[behavior_name]
17
+
18
+ raise "unknown behavior #{behavior_name}" unless behavior_definition
19
+ context = actor.this_object_context
20
+ context.in_subcontext do |behavioral_context|
21
+ behavioral_context[:behavior].tap do |behavior|
22
+ reqs = behavior_definition.required_injections
23
+ if reqs
24
+ reqs.each do |req|
25
+ object = context[req]
26
+ behavior.define_singleton_method req do
27
+ components[req]
28
+ end
29
+ components = behavior.send :components
30
+ components[req] = object
31
+ end
32
+ end
33
+
34
+ helpers = behavior_definition.helpers_block
35
+ if helpers
36
+ helpers_module = Module.new &helpers
37
+ behavior.extend helpers_module
38
+ end
39
+
40
+ behavior.define_singleton_method :react_to, behavior_definition.react_to_block if behavior_definition.react_to_block
41
+
42
+ deps = behavior_definition.required_behaviors
43
+ if deps
44
+ deps.each do |beh|
45
+ add_behavior actor, beh unless actor.has_behavior?(beh)
46
+ end
47
+ end
48
+ behavior.configure(opts)
49
+ behavior.instance_eval &behavior_definition.setup_block if behavior_definition.setup_block
50
+ actor.add_behavior behavior_name, behavior
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ end
@@ -21,7 +21,7 @@ class ConfigManager
21
21
 
22
22
  # TODO make this path include that app name?
23
23
  def load_config(name)
24
- conf = YAML::load_file(CONFIG_PATH + name + ".yml")
24
+ conf = YAML::load_file("#{Gamebox.configuration.config_path}#{name}.yml")
25
25
  user_file = "#{ENV['HOME']}/.gamebox/#{name}.yml"
26
26
  if File.exist? user_file
27
27
  user_conf = YAML::load_file user_file
@@ -0,0 +1,39 @@
1
+ module Gamebox
2
+ # Pattern stolen from rspec for configuration
3
+ class Configuration
4
+ def self.add_setting(name, opts={})
5
+ if opts[:alias]
6
+ alias_method name, opts[:alias]
7
+ alias_method "#{name}=", "#{opts[:alias]}="
8
+ alias_method "#{name}?", "#{opts[:alias]}?"
9
+ else
10
+ define_method("#{name}=") {|val| settings[name] = val}
11
+ define_method(name) { settings.has_key?(name) ? settings[name] : opts[:default] }
12
+ define_method("#{name}?") { send name }
13
+ end
14
+ end
15
+
16
+ # add_setting :output, :alias => :output_stream
17
+ add_setting :config_path
18
+ add_setting :data_path
19
+ add_setting :music_path
20
+ add_setting :sound_path
21
+ add_setting :gfx_path
22
+ add_setting :fonts_path
23
+
24
+ add_setting :gb_config_path
25
+ add_setting :gb_data_path
26
+ add_setting :gb_music_path
27
+ add_setting :gb_sound_path
28
+ add_setting :gb_gfx_path
29
+ add_setting :gb_fonts_path
30
+
31
+ add_setting :game_name, default: "Untitled Game"
32
+
33
+ add_setting :stages, default: [:demo]
34
+
35
+ def settings
36
+ @settings ||= {}
37
+ end
38
+ end
39
+ end