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
@@ -2,45 +2,58 @@ require "enumerator"
2
2
 
3
3
  # SvgActor knows how to build himself based on an svg document based on the :name
4
4
  # passed in being the group name in the doc (layer).
5
- class SvgActor < Actor
6
-
7
- attr_accessor :segments, :type
8
- def setup
9
- @name = @opts[:name]
10
- @svg_doc = @opts[:svg_doc]
5
+ define_behavior :svg_built do
6
+
7
+ requires_behaviors :positioned
8
+ requires :physics_manager
9
+
10
+ setup do
11
+ name = @opts[:name]
12
+ svg_doc = @opts[:svg_doc]
11
13
 
12
- my_layer = @svg_doc.find_group_by_label(@name.to_s)
13
- build_from_vertices my_layer.path.vertices
14
+ my_layer = svg_doc.find_group_by_label(name.to_s)
15
+ segments = build_from_vertices my_layer.path.vertices
16
+
17
+ actor.has_attributes segments: segments,
18
+ name: name
14
19
  end
15
20
 
16
- def build_from_vertices(vertices)
17
-
18
- moment_of_inertia,mass = Float::INFINITY,Float::INFINITY
19
- terrain_body = CP::Body.new(mass,moment_of_inertia)
20
- elasticity = 0
21
- friction = 0.7
22
- thickness = 6
23
- @segments = []
24
- vertices.each_cons(2) do |a,b|
25
- seg = CP::Shape::Segment.new(terrain_body, a,b, thickness)
26
- seg.collision_type = @name
27
- seg.e = elasticity
28
- seg.u = friction
29
- seg.group = :terrain
30
- @segments << [a,b]
31
- @stage.space.add_static_shape(seg)
21
+ helpers do
22
+ def build_from_vertices(vertices)
23
+
24
+ moment_of_inertia,mass = Float::INFINITY,Float::INFINITY
25
+ terrain_body = CP::Body.new(mass,moment_of_inertia)
26
+ elasticity = 0
27
+ friction = 0.7
28
+ thickness = 6
29
+ segments = []
30
+ [].tap do |segments|
31
+ vertices.each_cons(2) do |a,b|
32
+ seg = CP::Shape::Segment.new(terrain_body, a,b, thickness)
33
+ seg.collision_type = @name
34
+ seg.e = elasticity
35
+ seg.u = friction
36
+ seg.group = :terrain
37
+ segments << [a,b]
38
+ physics_manager.space.add_static_shape(seg)
39
+ end
40
+ end
32
41
  end
33
42
  end
34
43
  end
35
44
 
36
- class SvgActorView < ActorView
37
- def draw(target, x_off, y_off, z)
38
- @actor.segments.each do |seg|
39
- p1 = seg[0]
40
- p2 = seg[1]
41
- # TODO pull in draw_line_s?
42
- target.draw_line p1.x+x_off, p1.y+y_off, p2.x+x_off, p2.y+y_off, [25,255,25,255], z
43
- #target.draw_line_s [p1.x+x_off,p1.y+y_off], [p2.x+x_off,p2.y+y_off], [25,255,25,255], 6
45
+ define_actor :svg_actor do
46
+ has_behavior :svg_built
47
+
48
+ view do
49
+ draw do |target, x_off, y_off, z|
50
+ actor.segments.each do |seg|
51
+ p1 = seg[0]
52
+ p2 = seg[1]
53
+ # TODO pull in draw_line_s?
54
+ target.draw_line p1.x+x_off, p1.y+y_off, p2.x+x_off, p2.y+y_off, [25,255,25,255], z
55
+ #target.draw_line_s [p1.x+x_off,p1.y+y_off], [p2.x+x_off,p2.y+y_off], [25,255,25,255], 6
56
+ end
44
57
  end
45
58
  end
46
59
  end
@@ -2,84 +2,64 @@
2
2
  # keeps track of an image for you based on the actor's class, and
3
3
  # current action, and frame num
4
4
  # by default it expects images to be:
5
- # data/graphics/classname/action/01..n.png
6
- class Animated < Behavior
7
- requires_behavior :updatable
8
-
9
- attr_accessor :frame_time, :frame_num, :animating, :frame_update_time
10
- def setup
5
+ # data/graphics/actor_type/action/01..n.png
6
+ Behavior.define :animated do
7
+ requires :resource_manager, :director
8
+ setup do
11
9
  @images = {}
12
10
  @frame_update_time = @opts[:frame_update_time]
13
11
  @frame_update_time ||= 60
14
12
  @frame_time = 0
15
-
13
+
16
14
  # all animated actors have to have an idle animation
17
15
  # data/graphics/ship/idle/1.png
18
16
  @frame_num = 0
19
- self.action = :idle
20
-
21
- relegates :image, :width, :height,
22
- :start_animating, :stop_animating, :animated,
23
- :action, :action=
24
-
25
- end
26
-
27
- def animated
28
- self
29
- end
30
17
 
31
- def width
32
- image.width
33
- end
18
+ actor.has_attributes action: :idle,
19
+ animating: true
20
+ actor.has_attributes :image, :width, :height
34
21
 
35
- def height
36
- image.height
37
- end
38
-
39
- def update(time)
40
- return unless @animating
41
- @frame_time += time
42
- if @frame_time > @frame_update_time
43
- next_frame
44
- @frame_time = @frame_time-@frame_update_time
22
+ actor.when :action_changed do |old_action, new_action|
23
+ action_changed old_action, new_action
24
+ actor.animating = @images[new_action].size > 1
45
25
  end
46
- end
47
26
 
48
- def next_frame()
49
- @frame_num = (@frame_num + 1) % @images[@action].size
50
- end
27
+ action_changed nil, actor.action
51
28
 
52
- # load all the images for this action
53
- def load_action(action)
54
- @actor.resource_manager.load_animation_set @actor, action
29
+ director.when :update do |time|
30
+ if actor.animating
31
+ @frame_time += time
32
+ if @frame_time > @frame_update_time
33
+ next_frame
34
+ @frame_time = @frame_time-@frame_update_time
35
+ end
36
+ set_image
37
+ end
38
+ end
55
39
  end
56
40
 
57
- def action
58
- @action
59
- end
41
+ helpers do
42
+ def next_frame
43
+ action_set = @images[actor.action]
44
+ @frame_num = (@frame_num + 1) % action_set.size unless action_set.nil?
45
+ end
60
46
 
61
- def action=(new_action)
62
- @images[new_action] ||= load_action(new_action)
63
- if @images[new_action].size > 1
64
- start_animating
65
- else
66
- stop_animating
47
+ def action_changed(old_action, new_action)
48
+ @images[new_action] ||= resource_manager.load_animation_set actor, new_action
49
+ @frame_num = 0
50
+ set_image
67
51
  end
68
- @frame_num = 0
69
- @action = new_action
70
- end
71
52
 
72
- # returns the current image, or nil if no action is defined
73
- def image
74
- @images[@action][@frame_num]
75
- end
53
+ def set_image
54
+ action_set = @images[actor.action]
55
+ raise "unknown action set #{actor.action} for #{actor}" if action_set.nil?
76
56
 
77
- def start_animating
78
- @animating = true
57
+ image = action_set[@frame_num]
58
+ actor.image = image
59
+ actor.width = image.width
60
+ actor.height = image.height
61
+ end
79
62
  end
80
63
 
81
- def stop_animating
82
- @animating = false
83
- end
84
64
 
85
65
  end
@@ -1,23 +1,23 @@
1
1
 
2
2
 
3
- class Audible < Behavior
3
+ Behavior.define :audible do
4
4
 
5
- def setup
6
- @sound_manager = @actor.stage.sound_manager
7
-
8
- audible_obj = self
9
- relegates :play_sound, :stop_sound
5
+ requires :sound_manager
6
+ setup do
7
+ reacts_with :play_sound, :stop_sound
10
8
  end
11
9
 
12
- # Plays a sound via the SoundManager. See SoundManager for
13
- # details on how to "define" sounds.
14
- def play_sound(*args)
15
- @sound_manager.play_sound *args
16
- end
10
+ helpers do
11
+ # Plays a sound via the SoundManager. See SoundManager for
12
+ # details on how to "define" sounds.
13
+ def play_sound(*args)
14
+ sound_manager.play_sound *args
15
+ end
17
16
 
18
- # Stops a sound via the SoundManager.
19
- def stop_sound(*args)
20
- @sound_manager.stop_sound *args
17
+ # Stops a sound via the SoundManager.
18
+ def stop_sound(*args)
19
+ sound_manager.stop_sound *args
20
+ end
21
21
  end
22
22
 
23
23
  end
@@ -1,53 +1,82 @@
1
+ # available shape_types are :circle, :polygon, :aabb
2
+ Behavior.define :collidable do
1
3
 
4
+ requires_behaviors :positioned
2
5
 
6
+ requires :stage
7
+ setup do
8
+ shape_type = opts[:shape]
3
9
 
10
+ w = actor.do_or_do_not(:width) || 1
11
+ h = actor.do_or_do_not(:height) || 1
12
+ hw = w / 2
13
+ hh = h / 2
14
+ x = (actor.do_or_do_not(:x) || 0) - hw
15
+ y = (actor.do_or_do_not(:y) || 0) - hh
4
16
 
17
+ actor.has_attributes( shape_type: shape_type,
18
+ width: w,
19
+ height: h,
20
+ x: x,
21
+ y: y )
5
22
 
6
- # available collidable_shapes are :circle, :polygon, :aabb
7
- class Collidable < Behavior
23
+ shape =
24
+ case shape_type
25
+ when :circle
26
+ CircleCollidable.new actor, opts
27
+ when :aabb
28
+ AaBbCollidable.new actor, opts
29
+ when :polygon
30
+ PolygonCollidable.new actor, opts
31
+ end
32
+ shape.setup
8
33
 
9
- attr_accessor :collidable_shape, :cw_local_points, :shape
34
+ actor.width = shape.width
35
+ actor.height = shape.height
36
+ bb = Rect.new
37
+ bb.x = actor.x
38
+ bb.y = actor.y
39
+ bb.w = actor.width
40
+ bb.h = actor.height
10
41
 
11
- def setup
12
- @shape = build_shape
13
42
 
14
- relegates :collidable_shape, :radius, :cw_world_points, :cw_world_lines, :center_x, :center_y, :cw_world_edge_normals
15
- relegates :width unless @actor.respond_to? :width
16
- relegates :height unless @actor.respond_to? :height
43
+ actor.has_attributes( shape: shape,
44
+ center_x: shape.center_x,
45
+ center_y: shape.center_y,
46
+ cw_world_points: shape.cw_world_points,
47
+ cw_world_lines: shape.cw_world_lines,
48
+ cw_world_edge_normals: shape.cw_world_edge_normals,
49
+ bb: bb,
50
+ radius: shape.radius
51
+ )
17
52
 
18
- register_actor
19
- end
53
+ stage.register_collidable actor
20
54
 
21
- def register_actor
22
- @actor.stage.register_collidable @actor
55
+ reacts_with :remove, :position_changed
23
56
  end
24
57
 
25
- def removed
26
- @actor.stage.unregister_collidable @actor
27
- super
28
- end
29
-
30
- def build_shape
31
- shape = nil
32
- @collidable_shape = opts[:shape]
33
- case @collidable_shape
34
- when :circle
35
- shape = CircleCollidable.new @actor, opts
36
- when :aabb
37
- shape = AaBbCollidable.new @actor, opts
38
- when :polygon
39
- shape = PolygonCollidable.new @actor, opts
58
+ helpers do
59
+ def remove
60
+ stage.unregister_collidable actor
40
61
  end
41
62
 
42
- shape.setup
43
- shape
44
- end
45
-
46
- def update(time)
47
- shape.update(time)
48
- end
63
+ def position_changed
64
+ shape = actor.shape
65
+ shape.recalculate_collidable_cache
66
+ actor.center_x = shape.center_x
67
+ actor.center_y = shape.center_y
68
+ actor.width = shape.width
69
+ actor.height = shape.height
70
+ actor.cw_world_points = shape.cw_world_points
71
+ actor.cw_world_lines = shape.cw_world_lines
72
+ actor.cw_world_edge_normals = shape.cw_world_edge_normals
73
+ actor.radius = shape.radius
49
74
 
50
- def method_missing(name, *args)
51
- @shape.send(name, *args)
75
+ bb = actor.bb
76
+ bb.x = actor.x
77
+ bb.y = actor.y
78
+ bb.w = actor.width
79
+ bb.h = actor.height
80
+ end
52
81
  end
53
82
  end
@@ -4,10 +4,10 @@ class AaBbCollidable < CollidableShape
4
4
  attr_accessor :cw_local_points
5
5
 
6
6
  def setup
7
- @collidable_shape = opts[:shape]
7
+ @shape_type = opts[:shape]
8
8
 
9
9
  @cw_local_points = opts[:cw_local_points]
10
- @cw_local_points ||= opts[:points]
10
+ @cw_local_points ||= opts[:points] || []
11
11
  @cw_world_points ||= build_aabb
12
12
 
13
13
  @radius = opts[:radius]
@@ -28,7 +28,6 @@ class AaBbCollidable < CollidableShape
28
28
  ]
29
29
  end
30
30
 
31
- # TODO infinite loop if actor hasn't defined width and it gets relegated to us
32
31
  def calculate_radius
33
32
  w = @actor.width
34
33
  hw = w * 0.5
@@ -1,5 +1,8 @@
1
1
  class CollidableShape
2
2
  attr_accessor :opts, :actor, :radius
3
+
4
+ attr_reader :cw_world_points, :cw_local_points, :cw_world_lines, :cw_world_edge_normals
5
+
3
6
  def initialize(actor, options)
4
7
  @opts = options
5
8
  @actor = actor
@@ -18,6 +21,7 @@ class CollidableShape
18
21
  @actor.y + @y_offset
19
22
  end
20
23
 
24
+ # TODO find out if this is called
21
25
  def setup
22
26
  end
23
27
 
@@ -26,10 +30,8 @@ class CollidableShape
26
30
  end
27
31
  alias :height :width
28
32
 
29
- def update(time)
30
- recalculate_collidable_cache
31
- end
32
-
33
33
  def recalculate_collidable_cache
34
34
  end
35
+
36
+
35
37
  end
@@ -4,7 +4,7 @@ class PolygonCollidable < CollidableShape
4
4
  attr_accessor :cw_local_points
5
5
 
6
6
  def setup
7
- @collidable_shape = opts[:shape]
7
+ @shape_type = opts[:shape]
8
8
 
9
9
  @cw_local_points = opts[:cw_local_points]
10
10
  @cw_local_points ||= opts[:points]
@@ -0,0 +1,48 @@
1
+ Behavior.define :emitting do
2
+ # options:
3
+ # delay: ms to wait between creating more particles
4
+ # particle_actor: actor to spawn as particle
5
+ # particle_opts: opts to be passed to the spawned particle
6
+ # ttl: ms to live (optional, will live forever if omitted)
7
+ # spawn_variance: dist in pixels to spawn away from emitter (default -10..10)
8
+ # location_tween: tween object that will be used to move the emitter (optional)
9
+ # follow: actor to follow (optional)
10
+ requires :stage
11
+ setup do
12
+ # TODO which opts do we want from actor and which from behavior?
13
+ opts = actor.opts
14
+ variance = opts[:spawn_variance] || (-10..10)
15
+
16
+ spawn_timer = "#{self.object_id}_spawn"
17
+ self.when :remove_me do
18
+ stage.remove_timer spawn_timer
19
+ end
20
+ stage.add_timer spawn_timer, opts[:delay] do
21
+ spawn_x = self.x + variance.sample
22
+ spawn_y = self.y + variance.sample
23
+
24
+ stage.spawn opts[:particle_actor], {x: spawn_x, y: spawn_y}.merge(opts[:particle_opts])
25
+ end
26
+ ttl = opts[:ttl]
27
+ if ttl
28
+ suicide_timer = "#{self.object_id}_ttl"
29
+ stage.add_timer suicide_timer, ttl do
30
+ stage.remove_timer suicide_timer
31
+ actor.remove
32
+ end
33
+ end
34
+
35
+ target = opts[:follow]
36
+ if target
37
+ self.x = target.x
38
+ self.y = target.y
39
+ target.when :x_changed do
40
+ self.x = target.x
41
+ end
42
+ target.when :y_changed do
43
+ self.y = target.y
44
+ end
45
+ end
46
+
47
+ end
48
+ end