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.
- data/README.rdoc +38 -0
- data/Rakefile +1 -10
- data/TODO.txt +6 -6
- data/app_generators/gamebox_generator.rb +95 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/.gitignore +0 -0
- data/app_generators/templates/Gemfile +7 -0
- data/app_generators/templates/NEXT_STEPS.txt +1 -0
- data/{lib/gamebox/templates/template_app/README → app_generators/templates/README.rdoc} +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/Rakefile +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/config/boot.rb +0 -0
- data/app_generators/templates/config/environment.rb +30 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/config/game.yml +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/fonts/FONTS_GO_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/graphics/GRAPHICS_GO_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/music/MUSIC_GOES_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/sounds/SOUND_FX_GO_HERE +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_spec.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_view.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_view_spec.erb +0 -0
- data/app_generators/templates/script/generate +12 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/spec/helper.rb +0 -0
- data/app_generators/templates/src/actors/player.rb +8 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/src/app.rb +0 -0
- data/app_generators/templates/src/demo_stage.rb +7 -0
- data/bin/gamebox +8 -70
- data/component_generators/actor_generator.rb +17 -0
- data/docs/CODE_REVIEW +1 -1
- data/docs/REFACTOR_NOTES.txt +25 -0
- data/docs/getting_started.rdoc +1 -1
- data/gamebox.gemspec +7 -4
- data/lib/gamebox.rb +6 -3
- data/lib/gamebox/actors/collidable_debugger.rb +13 -15
- data/lib/gamebox/actors/curtain.rb +44 -43
- data/lib/gamebox/actors/emitter.rb +3 -42
- data/lib/gamebox/actors/fps.rb +13 -6
- data/lib/gamebox/actors/label.rb +42 -34
- data/lib/gamebox/actors/logo.rb +2 -4
- data/lib/gamebox/actors/score.rb +37 -27
- data/lib/gamebox/actors/svg_actor.rb +45 -32
- data/lib/gamebox/behaviors/animated.rb +39 -59
- data/lib/gamebox/behaviors/audible.rb +14 -14
- data/lib/gamebox/behaviors/collidable.rb +65 -36
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +2 -3
- data/lib/gamebox/behaviors/collidable/collidable_shape.rb +6 -4
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
- data/lib/gamebox/behaviors/emitting.rb +48 -0
- data/lib/gamebox/behaviors/graphical.rb +22 -56
- data/lib/gamebox/behaviors/layered.rb +8 -21
- data/lib/gamebox/behaviors/physical.rb +202 -213
- data/lib/gamebox/behaviors/positioned.rb +16 -0
- data/lib/gamebox/behaviors/projectile.rb +15 -0
- data/lib/gamebox/behaviors/visible.rb +16 -0
- data/lib/gamebox/core/aabb_helpers.rb +61 -0
- data/lib/gamebox/core/aabb_node.rb +118 -0
- data/lib/gamebox/core/aabb_tree.rb +137 -0
- data/lib/gamebox/core/actor.rb +102 -0
- data/lib/gamebox/core/actor_factory.rb +56 -0
- data/lib/gamebox/core/actor_view.rb +63 -0
- data/lib/gamebox/core/actor_view_factory.rb +40 -0
- data/lib/gamebox/{arbiter.rb → core/arbiter.rb} +31 -34
- data/lib/gamebox/{backstage.rb → core/backstage.rb} +0 -0
- data/lib/gamebox/core/behavior.rb +64 -0
- data/lib/gamebox/core/behavior_factory.rb +56 -0
- data/lib/gamebox/{class_finder.rb → core/class_finder.rb} +0 -0
- data/lib/gamebox/{config_manager.rb → core/config_manager.rb} +1 -1
- data/lib/gamebox/core/configuration.rb +39 -0
- data/lib/gamebox/core/core.rb +30 -0
- data/lib/gamebox/core/deprecated.rb +15 -0
- data/lib/gamebox/{director.rb → core/director.rb} +6 -11
- data/lib/gamebox/core/font_style.rb +26 -0
- data/lib/gamebox/core/font_style_factory.rb +11 -0
- data/lib/gamebox/core/game.rb +19 -0
- data/lib/gamebox/{hooked_gosu_window.rb → core/hooked_gosu_window.rb} +12 -6
- data/lib/gamebox/{input_manager.rb → core/input_manager.rb} +106 -99
- data/lib/gamebox/core/physics.rb +22 -0
- data/lib/gamebox/{physical_stage.rb → core/physics_manager.rb} +36 -30
- data/lib/gamebox/{resource_manager.rb → core/resource_manager.rb} +19 -18
- data/lib/gamebox/{sound_manager.rb → core/sound_manager.rb} +9 -7
- data/lib/gamebox/{stage.rb → core/stage.rb} +42 -80
- data/lib/gamebox/{stage_manager.rb → core/stage_manager.rb} +46 -53
- data/lib/gamebox/{stagehand.rb → core/stagehand.rb} +0 -0
- data/lib/gamebox/{svg_document.rb → core/svg_document.rb} +0 -0
- data/lib/gamebox/core/timer_manager.rb +50 -0
- data/lib/gamebox/{viewport.rb → core/viewport.rb} +2 -3
- data/lib/gamebox/{wrapped_screen.rb → core/wrapped_screen.rb} +12 -19
- data/lib/gamebox/gamebox_application.rb +7 -15
- data/lib/gamebox/lib/evented_attributes.rb +51 -0
- data/lib/gamebox/{ftor.rb → lib/ftor.rb} +0 -0
- data/lib/gamebox/lib/min_max_helpers.rb +10 -0
- data/lib/gamebox/lib/rect.rb +112 -54
- data/lib/gamebox/lib/yoda.rb +46 -0
- data/lib/gamebox/spec/helper.rb +317 -12
- data/lib/gamebox/stagehands/spatial_tree_stagehand.rb +61 -0
- data/lib/gamebox/version.rb +8 -3
- data/lib/gamebox/views/graphical_actor_view.rb +22 -29
- data/script/perf_aabb.rb +56 -0
- data/script/perf_array_access.rb +16 -0
- data/script/perf_collisions.rb +37 -18
- data/script/perf_struct_vs_array.rb +7 -7
- data/spec/acceptance/animation_spec.rb +65 -0
- data/spec/acceptance/basic_actor_lifecycle_spec.rb +92 -0
- data/spec/acceptance/built_in_collision_handling_spec.rb +55 -0
- data/spec/acceptance/chipmunk_collision_handling_spec.rb +83 -0
- data/spec/acceptance/fps_actor_spec.rb +40 -0
- data/spec/acceptance/pausing_spec.rb +61 -0
- data/spec/acceptance/timer_usage_spec.rb +53 -0
- data/spec/actors/emitter_spec.rb +5 -0
- data/spec/{label_spec.rb → actors/label_spec.rb} +1 -1
- data/spec/behaviors/animated_spec.rb +85 -0
- data/spec/behaviors/collidable_spec.rb +134 -0
- data/spec/{physical_spec.rb → behaviors/physical_spec.rb} +2 -1
- data/spec/behaviors/positioned_spec.rb +6 -0
- data/spec/behaviors/projectile_spec.rb +6 -0
- data/spec/core/aabb_tree_spec.rb +109 -0
- data/spec/core/actor_factory_spec.rb +44 -0
- data/spec/core/actor_spec.rb +78 -0
- data/spec/core/actor_view_spec.rb +53 -0
- data/spec/{arbiter_spec.rb → core/arbiter_spec.rb} +29 -30
- data/spec/core/backstage_spec.rb +37 -0
- data/spec/core/behavior_factory_spec.rb +50 -0
- data/spec/core/behavior_spec.rb +8 -0
- data/spec/core/configuration_spec.rb +8 -0
- data/spec/core/core_spec.rb +13 -0
- data/spec/core/font_style_factory_spec.rb +17 -0
- data/spec/core/font_style_spec.rb +41 -0
- data/spec/core/hooked_gosu_window_spec.rb +75 -0
- data/spec/core/input_manager_spec.rb +285 -0
- data/spec/core/physics_manager_spec.rb +11 -0
- data/spec/core/resource_manager_spec.rb +12 -0
- data/spec/core/stage_manager_spec.rb +140 -0
- data/spec/core/stage_spec.rb +73 -0
- data/spec/core/timer_manager_spec.rb +89 -0
- data/spec/{viewport_spec.rb → core/viewport_spec.rb} +6 -3
- data/spec/core/wrapped_screen_spec.rb +26 -0
- data/spec/fixtures/game.yml +7 -0
- data/spec/fixtures/snelpling/idle/1.png +0 -0
- data/spec/fixtures/snelpling/jump/1.png +0 -0
- data/spec/fixtures/snelpling/jump/2.png +0 -0
- data/spec/fixtures/snelpling/jump/3.png +0 -0
- data/spec/helper.rb +8 -0
- data/spec/{class_finder_spec.rb → lib/class_finder_spec.rb} +2 -1
- data/spec/stagehands/spatial_tree_stagehand_spec.rb +19 -0
- data/spec/views/graphical_actor_view_spec.rb +116 -0
- metadata +343 -144
- data/README.txt +0 -34
- data/lib/gamebox/actor.rb +0 -179
- data/lib/gamebox/actor_factory.rb +0 -57
- data/lib/gamebox/actor_view.rb +0 -44
- data/lib/gamebox/actors/spatial_debugger.rb +0 -62
- data/lib/gamebox/behavior.rb +0 -70
- data/lib/gamebox/behaviors/timed.rb +0 -33
- data/lib/gamebox/behaviors/updatable.rb +0 -12
- data/lib/gamebox/console_app.rb +0 -41
- data/lib/gamebox/gamebox_generator.rb +0 -32
- data/lib/gamebox/generators/actor_generator.rb +0 -43
- data/lib/gamebox/generators/view_generator.rb +0 -42
- data/lib/gamebox/physical_director.rb +0 -17
- data/lib/gamebox/physics.rb +0 -32
- data/lib/gamebox/spatial_bucket.rb +0 -9
- data/lib/gamebox/spatial_hash.rb +0 -194
- data/lib/gamebox/spatial_stagehand.rb +0 -80
- data/lib/gamebox/templates/template_app/Gemfile +0 -6
- data/lib/gamebox/templates/template_app/config/environment.rb +0 -23
- data/lib/gamebox/templates/template_app/config/stage_config.yml +0 -2
- data/lib/gamebox/templates/template_app/script/generate +0 -7
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +0 -11
- data/lib/gamebox/templates/template_app/src/game.rb +0 -19
- data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -14
- data/script/perf_spatial_hash.rb +0 -64
- data/spec/actor_factory_spec.rb +0 -61
- data/spec/actor_spec.rb +0 -71
- data/spec/actor_view_spec.rb +0 -61
- data/spec/animated_spec.rb +0 -83
- data/spec/backstage_spec.rb +0 -45
- data/spec/behavior_spec.rb +0 -28
- data/spec/collidable_spec.rb +0 -135
- data/spec/emitter_spec.rb +0 -20
- data/spec/input_manager_spec.rb +0 -134
- data/spec/resource_manager_spec.rb +0 -13
- data/spec/spatial_hash_spec.rb +0 -119
- data/spec/spatial_stagehand_spec.rb +0 -93
- data/spec/stage_manager_spec.rb +0 -25
- 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(:
|
6
|
+
stagehand(:spatial_tree).add(actor)
|
7
7
|
end
|
8
8
|
|
9
9
|
def unregister_collidable(actor)
|
10
|
-
stagehand(:
|
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
|
-
|
57
|
-
collidable_actors =
|
58
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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
|
-
|
99
|
-
binding.pry
|
100
|
-
end
|
101
|
-
case object.collidable_shape
|
98
|
+
case object.shape_type
|
102
99
|
when :circle
|
103
|
-
case other.
|
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.
|
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.
|
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.
|
163
|
-
b_min, b_max = send("#{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
|
File without changes
|
@@ -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(
|
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
|