gamebox 0.3.4 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,68 +1,39 @@
1
1
  class StageManager
2
2
 
3
- constructor :resource_manager, :actor_factory, :input_manager,
4
- :sound_manager, :config_manager
3
+ construct_with :input_manager, :config_manager, :backstage,
4
+ :this_object_context
5
5
 
6
- def setup
6
+ attr_reader :stage_names, :stage_opts
7
+
8
+ def initialize
7
9
  @stages = {}
8
- @backstage = Backstage.new
9
10
 
10
- @actor_factory.stage_manager = self
11
- stages = @config_manager.load_config('stage_config')[:stages]
11
+ stages = Gamebox.configuration.stages
12
12
 
13
13
  @stage_names = []
14
14
  @stage_opts = []
15
15
  stages.each do |stage|
16
- stage_name = stage.keys.first
17
- opts = stage.values.first
18
- @stage_names << stage_name
19
- opts ||= {}
20
- @stage_opts << opts
21
- end
22
- end
23
-
24
- def lookup_stage_class(stage_name)
25
- index = @stage_names.index stage_name
26
- opts = @stage_opts[index]
27
-
28
- name = opts[:class]
29
- name ||= stage_name
30
- stage_klass_name ||= Inflector.camelize name.to_s+"Stage"
31
-
32
- begin
33
- require name.to_s+"_stage"
34
- rescue LoadError => ex
35
- STDERR.puts ex
36
- # TODO hrm.. should this get logged
37
- # hope it's defined somewhere else
16
+ if stage.is_a? Hash
17
+ stage_name = stage.keys.first
18
+ opts = stage.values.first
19
+ @stage_names << stage_name
20
+ opts ||= {}
21
+ @stage_opts << opts
22
+ else
23
+ @stage_names << stage
24
+ @stage_opts << {}
25
+ end
38
26
  end
39
- stage_klass = ObjectSpace.const_get stage_klass_name
40
27
  end
41
28
 
42
- def create_stage(name, opts)
43
- stage_instance = lookup_stage_class(name).new(@input_manager, @actor_factory, @resource_manager, @sound_manager, @config_manager, @backstage, opts)
44
-
45
- stage_instance.when :next_stage do |*args|
46
- next_stage *args
47
- end
48
- stage_instance.when :prev_stage do |*args|
49
- prev_stage *args
50
- end
51
- stage_instance.when :restart_stage do |*args|
52
- restart_stage *args
53
- end
54
- stage_instance.when :change_stage do |stage_name, *args|
55
- switch_to_stage stage_name, *args
56
- end
57
-
58
-
59
- stage_instance
29
+ def default_stage
30
+ @stage_names.first
60
31
  end
61
32
 
62
33
  def next_stage(*args)
63
34
  index = @stage_names.index @stage
64
35
  if index == @stage_names.size-1
65
- puts "last stage, exiting"
36
+ log "last stage, exiting"
66
37
  exit
67
38
  end
68
39
 
@@ -72,7 +43,7 @@ class StageManager
72
43
  def prev_stage(*args)
73
44
  index = @stage_names.index @stage
74
45
  if index == 0
75
- puts "first stage, exiting"
46
+ log "first stage, exiting"
76
47
  exit
77
48
  end
78
49
 
@@ -80,9 +51,6 @@ class StageManager
80
51
  end
81
52
 
82
53
  def restart_stage(*args)
83
- current_stage.curtain_dropping *args
84
- index = @stage_names.index @stage
85
-
86
54
  switch_to_stage @stage, *args
87
55
  end
88
56
 
@@ -117,11 +85,36 @@ class StageManager
117
85
  if @stage and @stages and @stages[@stage]
118
86
  current_stage = @stages[@stage]
119
87
  current_stage.curtain_dropping *args
120
- @input_manager.clear_hooks(current_stage)
88
+ input_manager.clear_hooks(current_stage)
121
89
  @stages.delete @stage
122
90
  @stage = nil
123
91
  @stage_args = nil
124
92
  end
125
93
  end
126
94
 
95
+ def create_stage(name, opts)
96
+ stage_instance = nil
97
+ this_object_context.in_subcontext do |stage_context|
98
+ name_or_klass = opts[:class] || name
99
+ stage_instance = stage_context["#{name_or_klass}_stage"]
100
+ stage_context[:stage] = stage_instance
101
+ end
102
+ stage_instance.configure(backstage, opts)
103
+
104
+ stage_instance.when :next_stage do |*args|
105
+ next_stage *args
106
+ end
107
+ stage_instance.when :prev_stage do |*args|
108
+ prev_stage *args
109
+ end
110
+ stage_instance.when :restart_stage do |*args|
111
+ restart_stage *args
112
+ end
113
+ stage_instance.when :change_stage do |stage_name, *args|
114
+ switch_to_stage stage_name, *args
115
+ end
116
+ stage_instance
117
+ end
118
+
119
+
127
120
  end
File without changes
@@ -0,0 +1,50 @@
1
+ class TimerManager
2
+
3
+ def initialize
4
+ @timers ||= {}
5
+ @dead_timers = []
6
+ end
7
+
8
+ # add block to be executed every interval_ms millis
9
+ def add_timer(name, interval_ms, recurring = true, &block)
10
+ raise "timer [#{name}] already exists" if @timers[name]
11
+ @timers[name] = {
12
+ count: 0, recurring: recurring,
13
+ interval_ms: interval_ms, callback: block}
14
+ end
15
+
16
+ def remove_timer(name)
17
+ @timers.delete name
18
+ end
19
+
20
+ def timer(name)
21
+ @timers[name]
22
+ end
23
+
24
+ # update each timers counts, call any blocks that are over their interval
25
+ def update(time_delta)
26
+ # TODO handle overwriting the same timer name...
27
+ @timers.each do |name, timer_hash|
28
+ timer_hash[:count] += time_delta
29
+ if timer_hash[:count] > timer_hash[:interval_ms]
30
+ timer_hash[:count] -= timer_hash[:interval_ms]
31
+ timer_hash[:callback].call
32
+ @dead_timers << name unless timer_hash[:recurring]
33
+ end
34
+ end
35
+ @dead_timers.each do |name|
36
+ remove_timer name
37
+ end
38
+ end
39
+
40
+ def pause
41
+ @paused_timers = @timers
42
+ @timers = {}
43
+ end
44
+
45
+ def unpause
46
+ @timers = @paused_timers
47
+ @paused_timers = {}
48
+ end
49
+
50
+ end
@@ -76,7 +76,6 @@ class Viewport
76
76
  scrolled = true
77
77
  end
78
78
 
79
-
80
79
  y_diff = @height/2 + @follow_offset_y - y - @y_offset
81
80
  if y_diff.abs > @buffer_y
82
81
  # move screen
@@ -120,14 +119,14 @@ class Viewport
120
119
 
121
120
  @x_offset = @width/2 - @follow_target.x + @follow_offset_x
122
121
  @y_offset = @height/2 - @follow_target.y + @follow_offset_y
123
-
122
+
124
123
  fire :scrolled
125
124
  end
126
125
 
127
126
  def bounds
128
127
  left = -@x_offset
129
128
  top = -@y_offset
130
- [left, top, left + @width, top + @height]
129
+ Rect.new left, top, left + @width, top + @height
131
130
  end
132
131
 
133
132
  end
@@ -1,11 +1,15 @@
1
1
  class WrappedScreen
2
- constructor :config_manager
2
+ construct_with :config_manager
3
3
  attr_accessor :screen
4
- def setup
5
- width, height = *@config_manager[:screen_resolution]
6
- fullscreen = @config_manager[:fullscreen]
4
+ def initialize
5
+ width, height = *config_manager[:screen_resolution]
6
+ fullscreen = config_manager[:fullscreen]
7
+ needs_cursor = config_manager[:needs_cursor]
7
8
  @screen = HookedGosuWindow.new width, height, fullscreen
8
- @screen.caption = @config_manager[:title]
9
+ @screen.tap do |screen|
10
+ screen.caption = config_manager[:title]
11
+ screen.needs_cursor = config_manager[:needs_cursor]
12
+ end
9
13
  end
10
14
 
11
15
  def method_missing(name,*args)
@@ -114,19 +118,8 @@ class WrappedScreen
114
118
  c
115
119
  end
116
120
 
117
- def size_text(text, font_file, font_size)
118
- @font_cache ||= {}
119
- @font_cache[font_file] ||= {}
120
- font = @font_cache[font_file][font_size] ||= Font.new(@screen, font_file, font_size)
121
-
122
- return [font.text_width(text),font.height]
123
- end
124
-
125
- def render_text(text, font_file, font_size, color)
126
- @font_cache ||= {}
127
- @font_cache[font_file] ||= {}
128
- font = @font_cache[font_file][font_size] ||= Font.new(@screen, font_file, font_size)
129
-
130
- DelayedText.new font, text
121
+ def print(text, x, y, z, font_style)
122
+ font_style.font.draw text, x, y, z, font_style.x_scale, font_style.y_scale, convert_color(font_style.color)
131
123
  end
132
124
  end
125
+
@@ -14,25 +14,16 @@ class GameboxApp
14
14
  end
15
15
 
16
16
  def initialize
17
- gamebox_objects = YAML.load(File.read(GAMEBOX_PATH + 'data/config/objects.yml'))
18
-
19
- game_objects_file = APP_ROOT + '/config/objects.yml'
20
- game_specific_objects = {}
21
- if File.exist? game_objects_file
22
- game_specific_objects = YAML.load(File.read(game_objects_file))
23
- end
24
- objects = gamebox_objects.merge! game_specific_objects
25
-
26
- @context = DIY::Context.from_yaml(YAML.dump(objects))
17
+ @context = Conject.default_object_context
27
18
  end
28
-
19
+
29
20
  def setup
30
21
  @game = @context[:game]
31
-
22
+ @game.configure
32
23
  @config_manager = @context[:config_manager]
33
24
  setup_debug_server if @config_manager[:debug_server] || ARGV.include?("-debug-server")
34
25
  end
35
-
26
+
36
27
  def setup_debug_server
37
28
  Thread.new do
38
29
  loop do
@@ -40,10 +31,11 @@ class GameboxApp
40
31
  end
41
32
  end
42
33
  end
43
-
34
+
44
35
  def main_loop
45
36
  @input_manager = @context[:input_manager]
46
- @input_manager.main_loop @game
37
+ @input_manager.register @game
38
+ @input_manager.show
47
39
  end
48
40
 
49
41
  def shutdown
@@ -0,0 +1,51 @@
1
+ module EventedAttributes
2
+
3
+ def has_attributes(*names)
4
+ if names.first.is_a? Hash
5
+ names.first.each do |name, default|
6
+ has_attribute name, default
7
+ end
8
+ else
9
+ names.each do |name|
10
+ has_attribute name
11
+ end
12
+ end
13
+ end
14
+
15
+ def has_attribute(name, value=nil)
16
+ @evented_attributes ||= []
17
+ unless has_attribute? name
18
+ @evented_attributes << name
19
+ self.metaclass.send :kvo_attr_accessor, name
20
+ self.define_singleton_method "#{name}?" do
21
+ self.send name
22
+ end
23
+ self.send("#{name}=", value)
24
+ end
25
+ end
26
+
27
+ def has_attribute?(name)
28
+ @evented_attributes && @evented_attributes.include?(name)
29
+ end
30
+
31
+ def attributes
32
+ {}.tap do |atts|
33
+ if @evented_attributes
34
+ @evented_attributes.each do |name|
35
+ atts[name] = self.send name
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ def self.included(klass)
42
+ klass.instance_eval do
43
+ include Kvo
44
+ def has_attribute(name)
45
+ kvo_attr_accessor name
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ module MinMaxHelpers
2
+ def min(a,b)
3
+ a < b ? a : b
4
+ end
5
+ def max(a,b)
6
+ a > b ? a : b
7
+ end
8
+
9
+ end
10
+
@@ -68,6 +68,7 @@
68
68
  # In Rubygame, Rects are used for collision detection and describing
69
69
  # the area of a Surface to operate on.
70
70
  class Rect < Array
71
+ include MinMaxHelpers
71
72
 
72
73
  #--
73
74
  # GENERAL
@@ -142,20 +143,12 @@ class Rect < Array
142
143
  def inspect; "#<Rect:#{self.object_id} [%s,%s,%s,%s]>"%self; end
143
144
 
144
145
 
145
- # Returns an SDL::Rect version of this Rect. Float values are
146
- # rounded to the nearest integer.
147
- #
148
- def to_sdl # :nodoc:
149
- SDL::Rect.new( self.collect{|n| n.round } )
150
- end
151
-
152
-
153
146
  #--
154
147
  # ATTRIBUTES
155
148
  #++
156
149
 
157
- # Returns self.at(0)
158
- def x; return self.at(0); end
150
+ # Returns self[0]
151
+ def x; return self[0]; end
159
152
  # Sets self[0] to +val+
160
153
  def x=(val); self[0] = val; end
161
154
 
@@ -164,8 +157,8 @@ class Rect < Array
164
157
  alias l x
165
158
  alias l= x=;
166
159
 
167
- # Returns self.at(1)
168
- def y; return self.at(1); end
160
+ # Returns self[1]
161
+ def y; return self[1]; end
169
162
  # Sets self[1] to +val+
170
163
  def y=(val); self[1] = val; end
171
164
 
@@ -174,16 +167,16 @@ class Rect < Array
174
167
  alias t y
175
168
  alias t= y=;
176
169
 
177
- # Returns self.at(2)
178
- def w; return self.at(2); end
170
+ # Returns self[2]
171
+ def w; return self[2]; end
179
172
  # Sets self[2] to +val+
180
173
  def w=(val); self[2] = val; end
181
174
 
182
175
  alias width w
183
176
  alias width= w=;
184
177
 
185
- # Returns self.at(3)
186
- def h; return self.at(3); end
178
+ # Returns self[3]
179
+ def h; return self[3]; end
187
180
  # Sets self[3] to +val+
188
181
  def h=(val); self[3] = val; end
189
182
 
@@ -201,21 +194,21 @@ class Rect < Array
201
194
  end
202
195
 
203
196
  # Return the x coordinate of the right side of the Rect.
204
- def right; return self.at(0)+self.at(2); end
197
+ def right; return self[0]+self[2]; end
205
198
 
206
199
  # Set the x coordinate of the right side of the Rect by translating the
207
200
  # Rect (adjusting the x offset).
208
- def right=(r); self[0] = r - self.at(2); return r; end
201
+ def right=(r); self[0] = r - self[2]; return r; end
209
202
 
210
203
  alias r right
211
204
  alias r= right=;
212
205
 
213
206
  # Return the y coordinate of the bottom side of the Rect.
214
- def bottom; return self.at(1)+self.at(3); end
207
+ def bottom; return self[1]+self[3]; end
215
208
 
216
209
  # Set the y coordinate of the bottom side of the Rect by translating the
217
210
  # Rect (adjusting the y offset).
218
- def bottom=(b); self[1] = b - self.at(3); return b; end
211
+ def bottom=(b); self[1] = b - self[3]; return b; end
219
212
 
220
213
  alias b bottom
221
214
  alias b= bottom=;
@@ -234,21 +227,21 @@ class Rect < Array
234
227
  alias c= center=;
235
228
 
236
229
  # Return the x coordinate of the center of the Rect
237
- def centerx; return self.at(0)+(self.at(2).div(2)); end
230
+ def centerx; return self[0]+(self[2].div(2)); end
238
231
 
239
232
  # Set the x coordinate of the center of the Rect by translating the
240
233
  # Rect (adjusting the x offset).
241
- def centerx=(x); self[0] = x - (self.at(2).div(2)); return x; end
234
+ def centerx=(x); self[0] = x - (self[2].div(2)); return x; end
242
235
 
243
236
  alias cx centerx
244
237
  alias cx= centerx=;
245
238
 
246
239
  # Return the y coordinate of the center of the Rect
247
- def centery; return self.at(1)+(self.at(3).div(2)); end
240
+ def centery; return self[1]+(self[3].div(2)); end
248
241
 
249
242
  # Set the y coordinate of the center of the Rect by translating the
250
243
  # Rect (adjusting the y offset).
251
- def centery=(y); self[1] = y- (self.at(3).div(2)); return y; end
244
+ def centery=(y); self[1] = y- (self[3].div(2)); return y; end
252
245
 
253
246
  alias cy centery
254
247
  alias cy= centery=;
@@ -268,7 +261,7 @@ class Rect < Array
268
261
  alias tl= topleft=;
269
262
 
270
263
  # Return the x and y coordinates of the top-right corner of the Rect
271
- def topright; return self.right, self.at(1); end
264
+ def topright; return self.right, self[1]; end
272
265
 
273
266
  # Set the x and y coordinates of the top-right corner of the Rect by
274
267
  # translating the Rect (adjusting the x and y offsets).
@@ -282,7 +275,7 @@ class Rect < Array
282
275
  alias tr= topright=;
283
276
 
284
277
  # Return the x and y coordinates of the bottom-left corner of the Rect
285
- def bottomleft; return self.at(0), self.bottom; end
278
+ def bottomleft; return self[0], self.bottom; end
286
279
 
287
280
  # Set the x and y coordinates of the bottom-left corner of the Rect by
288
281
  # translating the Rect (adjusting the x and y offsets).
@@ -311,7 +304,7 @@ class Rect < Array
311
304
 
312
305
  # Return the x and y coordinates of the midpoint on the left side of the
313
306
  # Rect.
314
- def midleft; return self.at(0), self.centery; end
307
+ def midleft; return self[0], self.centery; end
315
308
 
316
309
  # Set the x and y coordinates of the midpoint on the left side of the Rect
317
310
  # by translating the Rect (adjusting the x and y offsets).
@@ -326,7 +319,7 @@ class Rect < Array
326
319
 
327
320
  # Return the x and y coordinates of the midpoint on the left side of the
328
321
  # Rect.
329
- def midtop; return self.centerx, self.at(1); end
322
+ def midtop; return self.centerx, self[1]; end
330
323
 
331
324
  # Set the x and y coordinates of the midpoint on the top side of the Rect
332
325
  # by translating the Rect (adjusting the x and y offsets).
@@ -389,31 +382,31 @@ class Rect < Array
389
382
  unless rect.contain?(nself)
390
383
 
391
384
  #If self is too wide:
392
- if nself.at(2) >= rect.at(2)
393
- self[0] = rect.centerx - nself.at(2).div(2)
385
+ if nself[2] >= rect[2]
386
+ self[0] = rect.centerx - nself[2].div(2)
394
387
  #Else self is not too wide
395
388
  else
396
389
  #If self is to the left of arg
397
- if nself.at(0) < rect.at(0)
398
- self[0] = rect.at(0)
390
+ if nself[0] < rect[0]
391
+ self[0] = rect[0]
399
392
  #If self is to the right of arg
400
393
  elsif nself.right > rect.right
401
- self[0] = rect.right - nself.at(2)
394
+ self[0] = rect.right - nself[2]
402
395
  #Otherwise, leave x alone
403
396
  end
404
397
  end
405
398
 
406
399
  #If self is too tall:
407
- if nself.at(3) >= rect.at(3)
408
- self[1] = rect.centery - nself.at(3).div(2)
400
+ if nself[3] >= rect[3]
401
+ self[1] = rect.centery - nself[3].div(2)
409
402
  #Else self is not too tall
410
403
  else
411
404
  #If self is above arg
412
- if nself.at(1) < rect.at(1)
413
- self[1] = rect.at(1)
405
+ if nself[1] < rect[1]
406
+ self[1] = rect[1]
414
407
  #If self below arg
415
408
  elsif nself.bottom > rect.bottom
416
- self[1] = rect.bottom - nself.at(3)
409
+ self[1] = rect.bottom - nself[3]
417
410
  #Otherwise, leave y alone
418
411
  end
419
412
  end
@@ -435,10 +428,10 @@ class Rect < Array
435
428
  nself = self.normalize
436
429
  other = Rect.new_from_object(rect).normalize!
437
430
  if self.collide_rect?(other)
438
- self[0] = [nself.at(0), other.at(0)].max
439
- self[1] = [nself.at(1), other.at(1)].max
440
- self[2] = [nself.right, other.right].min - self.at(0)
441
- self[3] = [nself.bottom, other.bottom].min - self.at(1)
431
+ self[0] = [nself[0], other[0]].max
432
+ self[1] = [nself[1], other[1]].max
433
+ self[2] = [nself.right, other.right].min - self[0]
434
+ self[3] = [nself.bottom, other.bottom].min - self[1]
442
435
  else #if they do not intersect at all:
443
436
  self[0], self[1] = nself.topleft
444
437
  self[2], self[3] = 0, 0
@@ -505,8 +498,8 @@ class Rect < Array
505
498
 
506
499
  # True if the caller and the given Rect overlap (or touch) at all.
507
500
  def collide_rect?(rect)
508
- nself = self.normalize
509
- rect = Rect.new_from_object(rect).normalize!
501
+ nself = self #.normalize
502
+ rect = Rect.new_from_object(rect)#.normalize!
510
503
  return ((nself.l >= rect.l && nself.l <= rect.r) or (rect.l >= nself.l && rect.l <= nself.r)) &&
511
504
  ((nself.t >= rect.t && nself.t <= rect.b) or (rect.t >= nself.t && rect.t <= nself.b))
512
505
  end
@@ -514,18 +507,18 @@ class Rect < Array
514
507
  # True if the given Rect is totally within the caller. Borders may
515
508
  # overlap.
516
509
  def contain?(rect)
517
- nself = self.normalize
518
- rect = Rect.new_from_object(rect).normalize!
510
+ nself = self#.normalize
511
+ rect = Rect.new_from_object(rect)#.normalize!
519
512
  return (nself.left <= rect.left and rect.right <= nself.right and
520
513
  nself.top <= rect.top and rect.bottom <= nself.bottom)
521
514
  end
522
515
 
523
516
  # As #inflate!, but the original caller is not changed.
524
517
  def inflate(x,y)
525
- return self.class.new(self.at(0) - x.div(2),
526
- self.at(1) - y.div(2),
527
- self.at(2) + x,
528
- self.at(3) + y)
518
+ return self.class.new(self[0] - x.div(2),
519
+ self[1] - y.div(2),
520
+ self[2] + x,
521
+ self[3] + y)
529
522
  end
530
523
 
531
524
  # Increase the Rect's size is the x and y directions, while keeping the
@@ -561,11 +554,11 @@ class Rect < Array
561
554
  # area it represents. Has no effect on Rects with non-negative width
562
555
  # and height. Some Rect methods will automatically normalize the Rect.
563
556
  def normalize!
564
- if self.at(2) < 0
565
- self[0], self[2] = self.at(0)+self.at(2), -self.at(2)
557
+ if self[2] < 0
558
+ self[0], self[2] = self[0]+self[2], -self[2]
566
559
  end
567
- if self.at(3) < 0
568
- self[1], self[3] = self.at(1)+self.at(3), -self.at(3)
560
+ if self[3] < 0
561
+ self[1], self[3] = self[1]+self[3], -self[3]
569
562
  end
570
563
  self
571
564
  end
@@ -606,6 +599,71 @@ class Rect < Array
606
599
  return self
607
600
  end
608
601
 
602
+ # calculate the area of the Rect
603
+ def area
604
+ w * h
605
+ end
606
+
607
+ def zero_out!
608
+ self[0] = 0
609
+ self[1] = 0
610
+ self[2] = 0
611
+ self[3] = 0
612
+ end
613
+
614
+ def union_area(rect)
615
+ rleft = self.left
616
+ rtop = self.top
617
+ rright = self.right
618
+ rbottom = self.bottom
619
+ r2 = Rect.new_from_object(rect)
620
+
621
+ rleft = min(rleft, r2.left)
622
+ rtop = min(rtop, r2.top)
623
+ rright = max(rright, r2.right)
624
+ rbottom = max(rbottom, r2.bottom)
625
+
626
+ (rright - rleft) * (rbottom - rtop)
627
+ end
628
+
629
+ def union_fast(rect)
630
+ rleft = self.left
631
+ rtop = self.top
632
+ rright = self.right
633
+ rbottom = self.bottom
634
+ r2 = Rect.new_from_object(rect)
635
+
636
+ rleft = min(rleft, r2.left)
637
+ rtop = min(rtop, r2.top)
638
+ rright = max(rright, r2.right)
639
+ rbottom = max(rbottom, r2.bottom)
640
+
641
+ Rect.new(rleft, rtop, rright - rleft, rbottom - rtop)
642
+ end
643
+
644
+ def expand_to_include!(rect)
645
+ rleft = self.left
646
+ rtop = self.top
647
+ rright = self.right
648
+ rbottom = self.bottom
649
+ r2 = Rect.new_from_object(rect)
650
+
651
+ rleft = min(rleft, r2.left)
652
+ rtop = min(rtop, r2.top)
653
+ rright = max(rright, r2.right)
654
+ rbottom = max(rbottom, r2.bottom)
655
+
656
+ self.x = rleft
657
+ self.y = rtop
658
+ self.w = rright - rleft
659
+ self.h = rbottom - rtop
660
+ end
661
+
662
+ def refit_for!(rect_a, rect_b)
663
+ self.zero_out!
664
+ self.expand_to_include! rect_a
665
+ self.expand_to_include! rect_b
666
+ end
609
667
 
610
668
  end # class Rect
611
669