gamebox 0.2.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/Gemfile +1 -8
  2. data/Rakefile +13 -37
  3. data/TODO.txt +27 -27
  4. data/docs/getting_started.rdoc +2 -2
  5. data/gamebox.gemspec +33 -191
  6. data/lib/gamebox.rb +18 -14
  7. data/lib/gamebox/actor.rb +37 -27
  8. data/lib/gamebox/actor_factory.rb +4 -5
  9. data/lib/gamebox/actor_view.rb +8 -0
  10. data/lib/gamebox/actors/collidable_debugger.rb +2 -2
  11. data/lib/gamebox/actors/curtain.rb +3 -3
  12. data/lib/gamebox/actors/emitter.rb +51 -0
  13. data/lib/gamebox/actors/label.rb +27 -7
  14. data/lib/gamebox/actors/logo.rb +1 -1
  15. data/lib/gamebox/actors/spatial_debugger.rb +25 -10
  16. data/lib/gamebox/arbiter.rb +61 -34
  17. data/lib/gamebox/behavior.rb +3 -3
  18. data/lib/gamebox/behaviors/animated.rb +1 -1
  19. data/lib/gamebox/behaviors/audible.rb +1 -1
  20. data/lib/gamebox/behaviors/collidable.rb +9 -4
  21. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +26 -1
  22. data/lib/gamebox/behaviors/collidable/circle_collidable.rb +3 -3
  23. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
  24. data/lib/gamebox/behaviors/graphical.rb +30 -4
  25. data/lib/gamebox/behaviors/layered.rb +1 -1
  26. data/lib/gamebox/behaviors/physical.rb +113 -30
  27. data/lib/gamebox/behaviors/timed.rb +33 -0
  28. data/lib/gamebox/behaviors/updatable.rb +1 -1
  29. data/lib/gamebox/class_finder.rb +1 -21
  30. data/lib/gamebox/console_app.rb +33 -31
  31. data/lib/gamebox/constants.rb +481 -0
  32. data/lib/gamebox/data/config/objects.yml +7 -0
  33. data/lib/gamebox/gamebox_application.rb +10 -33
  34. data/lib/gamebox/gamebox_generator.rb +32 -32
  35. data/lib/gamebox/input_manager.rb +73 -32
  36. data/lib/gamebox/lib/inflector.rb +1 -1
  37. data/lib/gamebox/lib/range_ext.rb +5 -0
  38. data/lib/gamebox/lib/rect.rb +548 -548
  39. data/lib/gamebox/lib/sorted_list.rb +1 -1
  40. data/lib/gamebox/lib/symbol_ext.rb +8 -0
  41. data/lib/gamebox/physical_director.rb +1 -1
  42. data/lib/gamebox/physical_stage.rb +3 -3
  43. data/lib/gamebox/physics.rb +0 -3
  44. data/lib/gamebox/resource_manager.rb +22 -17
  45. data/lib/gamebox/sound_manager.rb +3 -2
  46. data/lib/gamebox/spatial_hash.rb +60 -31
  47. data/lib/gamebox/spatial_stagehand.rb +30 -6
  48. data/lib/gamebox/spec/helper.rb +7 -7
  49. data/lib/gamebox/stage.rb +18 -19
  50. data/lib/gamebox/stage_manager.rb +33 -23
  51. data/lib/gamebox/stagehand.rb +3 -0
  52. data/lib/gamebox/svg_document.rb +1 -1
  53. data/lib/gamebox/tasks/gamebox_tasks.rake +133 -0
  54. data/lib/gamebox/templates/actor.erb +0 -2
  55. data/lib/gamebox/templates/actor_view.erb +1 -3
  56. data/lib/gamebox/templates/template_app/Gemfile +3 -2
  57. data/lib/gamebox/templates/template_app/Rakefile +3 -8
  58. data/lib/gamebox/templates/template_app/config/environment.rb +7 -39
  59. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -2
  60. data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -3
  61. data/lib/gamebox/version.rb +2 -2
  62. data/lib/gamebox/viewport.rb +44 -8
  63. data/lib/gamebox/views/graphical_actor_view.rb +22 -16
  64. data/lib/gamebox/wrapped_screen.rb +9 -1
  65. data/script/perf_spatial_hash.rb +49 -58
  66. data/script/perf_struct_vs_array.rb +32 -0
  67. data/spec/actor_factory_spec.rb +61 -0
  68. data/spec/actor_spec.rb +24 -18
  69. data/spec/actor_view_spec.rb +51 -6
  70. data/spec/animated_spec.rb +27 -6
  71. data/spec/arbiter_spec.rb +12 -24
  72. data/spec/backstage_spec.rb +1 -1
  73. data/spec/behavior_spec.rb +3 -3
  74. data/spec/class_finder_spec.rb +13 -0
  75. data/spec/collidable_spec.rb +30 -10
  76. data/spec/emitter_spec.rb +20 -0
  77. data/spec/helper.rb +5 -21
  78. data/spec/input_manager_spec.rb +134 -0
  79. data/spec/label_spec.rb +0 -1
  80. data/spec/physical_spec.rb +114 -5
  81. data/spec/resource_manager_spec.rb +1 -2
  82. data/spec/spatial_hash_spec.rb +23 -7
  83. data/spec/spatial_stagehand_spec.rb +97 -0
  84. data/spec/stage_manager_spec.rb +0 -1
  85. data/spec/stage_spec.rb +2 -2
  86. data/spec/viewport_spec.rb +92 -48
  87. metadata +223 -119
  88. data/.gitignore +0 -11
  89. data/History.txt +0 -80
  90. data/VERSION +0 -1
  91. data/lib/gamebox/event_compat.rb +0 -285
  92. data/lib/gamebox/lib/diy.rb +0 -371
  93. data/lib/gamebox/lib/numbers_ext.rb +0 -3
  94. data/lib/gamebox/tasks/gamebox_tasks.rb +0 -61
  95. data/load_paths.rb +0 -20
@@ -1,5 +1,3 @@
1
- require 'actor'
2
- require 'graphical_actor_view'
3
1
 
4
2
  # ActorFactory is responsible for loading all Actors. It passes along required params such as
5
3
  # stage, input_manager, director, resource_manager. It also creates the ActorView
@@ -16,6 +14,8 @@ class ActorFactory
16
14
  return cached_actor if cached_actor
17
15
 
18
16
  model_klass = ClassFinder.find(actor)
17
+ raise "#{actor} not found" unless model_klass
18
+
19
19
  view_klass = ClassFinder.find("#{actor}_view")
20
20
 
21
21
  actor_def = {
@@ -30,16 +30,15 @@ class ActorFactory
30
30
  def build(actor, stage, opts={})
31
31
  actor_def = cached_actor_def actor
32
32
 
33
- actor_type = actor_def[:actor_type]
34
33
  basic_opts = {
35
34
  :stage => stage,
36
35
  :input => @input_manager,
37
36
  :director => @director,
38
37
  :resources => stage.resource_manager,
39
- :actor_type => actor
38
+ :actor_type => actor,
39
+ :wrapped_screen => @wrapped_screen
40
40
  }
41
41
  merged_opts = basic_opts.merge(opts)
42
-
43
42
  model = actor_def[:model_klass].new merged_opts
44
43
 
45
44
  view_klass = opts[:view]
@@ -32,5 +32,13 @@ class ActorView
32
32
  def setup
33
33
  end
34
34
 
35
+ def screen_width
36
+ @screen_width ||= @wrapped_screen.width
37
+ end
38
+
39
+ def screen_height
40
+ @screen_height ||= @wrapped_screen.height
41
+ end
42
+
35
43
  end
36
44
 
@@ -1,5 +1,5 @@
1
- require 'actor'
2
- require 'actor_view'
1
+
2
+
3
3
 
4
4
  class CollidableDebugger < Actor
5
5
 
@@ -1,10 +1,10 @@
1
- require 'actor'
1
+
2
2
  require 'publisher'
3
- require 'actor_view'
3
+
4
4
 
5
5
  class CurtainView < ActorView
6
6
  def draw(target,x_off,y_off,z)
7
- target.fill 0,0,1024,800, [0,0,0,@actor.height]
7
+ target.fill 0,0,1024,800, [0,0,0,@actor.height], z
8
8
  end
9
9
  end
10
10
 
@@ -0,0 +1,51 @@
1
+ # class used for particle emissions
2
+ class Emitter < Actor
3
+
4
+ # options:
5
+ # delay: ms to wait between creating more particles
6
+ # particle_actor: actor to spawn as particle
7
+ # particle_opts: opts to be passed to the spawned particle
8
+ # ttl: ms to live (optional, will live forever if omitted)
9
+ # spawn_variance: dist in pixels to spawn away from emitter (default -10..10)
10
+ # location_tween: tween object that will be used to move the emitter (optional)
11
+ # follow: actor to follow (optional)
12
+ def setup
13
+ @variance = opts[:spawn_variance] || (-10..10)
14
+
15
+ spawn_timer = "#{self.object_id}_spawn"
16
+ self.when :remove_me do
17
+ stage.remove_timer spawn_timer
18
+ end
19
+ stage.add_timer spawn_timer, opts[:delay] do
20
+ spawn_particle
21
+ end
22
+ ttl = opts[:ttl]
23
+ if ttl
24
+ suicide_timer = "#{self.object_id}_ttl"
25
+ stage.add_timer suicide_timer, ttl do
26
+ stage.remove_timer suicide_timer
27
+ remove_self
28
+ end
29
+ end
30
+
31
+ target = opts[:follow]
32
+ if target
33
+ self.x = target.x
34
+ self.y = target.y
35
+ target.when :x_changed do
36
+ self.x = target.x
37
+ end
38
+ target.when :y_changed do
39
+ self.y = target.y
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ def spawn_particle
46
+ spawn_x = self.x + @variance.sample
47
+ spawn_y = self.y + @variance.sample
48
+
49
+ spawn opts[:particle_actor], {x: spawn_x, y: spawn_y}.merge(opts[:particle_opts])
50
+ end
51
+ end
@@ -1,23 +1,43 @@
1
1
  class LabelView < ActorView
2
- def draw(target,x_off,y_off)
3
- actor.text_image.blit target.screen, [actor.x, actor.y]
2
+ def draw(target,x_off,y_off,z)
3
+ @converted_color ||= target.convert_color(actor.color)
4
+ actor.font.draw actor.text, actor.x, actor.y, z,
5
+ 1,1, # x factor, y factor
6
+ @converted_color
4
7
  end
5
8
  end
9
+
6
10
  class Label < Actor
7
- attr_accessor :text, :text_image
11
+ has_behavior layered: {layer: 1}
12
+ attr_accessor :text, :font, :color
8
13
 
9
14
  def setup
10
15
  @text = @opts[:text]
11
16
  @size = @opts[:size]
12
- @font = @opts[:font]
17
+ font_name = @opts[:font]
13
18
  @color = @opts[:color]
14
19
 
15
20
  @text ||= ""
16
21
  @size ||= 30
17
- @font ||= "Asimov.ttf"
22
+ font_name ||= "Asimov.ttf"
18
23
  @color ||= [250,250,250,255]
24
+ layer = opts[:layer]
25
+ layered.layer = layer
26
+
27
+ @font = resource_manager.load_font font_name, @size
28
+ end
29
+
30
+ def width
31
+ font.text_width(text)
32
+ end
33
+
34
+ def height
35
+ [font.text_width(text),font.height]
36
+ end
19
37
 
20
- font = resource_manager.load_font @font, @size
21
- @text_image = font.render @text.to_s, true, @color
38
+ def resize(size)
39
+ @size = size
40
+ resource_manager.load_font @font, @size
22
41
  end
42
+
23
43
  end
@@ -1,4 +1,4 @@
1
- require 'actor'
1
+
2
2
  class Logo < Actor
3
3
  has_behaviors :graphical,
4
4
  :layered => {:layer => 999}
@@ -1,5 +1,5 @@
1
- require 'actor'
2
- require 'actor_view'
1
+
2
+
3
3
 
4
4
  class SpatialDebugger < Actor
5
5
 
@@ -24,24 +24,39 @@ end
24
24
 
25
25
  class SpatialDebuggerView < ActorView
26
26
  def setup
27
- size = 30
28
- font = "Asimov.ttf"
29
- @font = @actor.resource_manager.load_font font, size
27
+ # size = 30
28
+ # font = "Asimov.ttf"
29
+ # @font = @actor.resource_manager.load_font font, size
30
30
  end
31
31
 
32
- def draw(target,x_off,y_off)
32
+ def draw(target,x_off,y_off, z)
33
+ vp = stage.viewport
33
34
  cell_size = @actor.spatial.cell_size
34
35
  max = 0
35
36
  @actor.spatial.buckets.each do |x_bucket,stuff|
36
37
  stuff.each do |y_bucket,items|
37
- max = items.size if items.size > max
38
+ # max = items.size if items.size > max
38
39
  x = x_bucket * cell_size + x_off
39
40
  y = y_bucket * cell_size + y_off
40
- target.draw_box [x,y], [x+cell_size,y+cell_size], Color[:white]
41
+ target.draw_box x, y, x+cell_size, y+cell_size, [255,25,25], z
42
+
43
+ # Yes I know I may be drawing this many times for an actor
44
+ items.each do |item|
45
+ # puts "#{item.class}: [#{item.center_x}, #{item.center_y}] #{item.collidable_shape}"
46
+ parallax = 1
47
+ ix = item.center_x + x_off
48
+ iy = item.center_y + y_off
49
+
50
+ target.draw_box ix, iy, ix + 2, iy + 2, [255,255,255], 10
51
+
52
+ # TODO make work for non circles
53
+ r = item.radius
54
+ target.draw_box ix-r, iy-r, ix + r, iy + r, [255,255,255], 10
55
+ end
41
56
  end
42
57
  end
43
58
 
44
- @text_image = @font.render "#{@actor.ratio} [#{max}]", true, Color[:white]
45
- @text_image.blit target.screen, [@actor.x, @actor.y]
59
+ # @text_image = @font.render "#{@actor.ratio} [#{max}]", true, Color[:white]
60
+ # @text_image.blit target.screen, [@actor.x, @actor.y]
46
61
  end
47
62
  end
@@ -3,21 +3,11 @@ module Arbiter
3
3
  attr_reader :checks, :collisions
4
4
 
5
5
  def register_collidable(actor)
6
- @spatial_hash = stagehand(:spatial)
7
- @collidable_actors ||= []
8
- unless @collidable_actors.include? actor
9
- actor.when :remove_me do
10
- unregister_collidable actor
11
- end
12
- @collidable_actors << actor
13
- @spatial_hash.add(actor)
14
- end
6
+ stagehand(:spatial).add(actor)
15
7
  end
16
8
 
17
9
  def unregister_collidable(actor)
18
- @collidable_actors ||= []
19
- @collidable_actors.delete actor
20
- @spatial_hash.remove(actor)
10
+ stagehand(:spatial).remove(actor)
21
11
  end
22
12
 
23
13
  def on_collision_of(first_objs, second_objs, &block)
@@ -28,7 +18,7 @@ module Arbiter
28
18
 
29
19
  first_objs.each do |fobj|
30
20
  second_objs.each do |sobj|
31
- if fobj.to_i < sobj.to_i
21
+ if fobj < sobj
32
22
  @collision_handlers[fobj] ||= {}
33
23
  @collision_handlers[fobj][sobj] = [false,block]
34
24
  else
@@ -44,7 +34,7 @@ module Arbiter
44
34
  collisions.each do |collision|
45
35
  first = collision.first
46
36
  second = collision.last
47
- unless first.actor_type.to_i < second.actor_type.to_i
37
+ unless first.actor_type < second.actor_type
48
38
  tmp = first
49
39
  first = second
50
40
  second = tmp
@@ -63,29 +53,33 @@ module Arbiter
63
53
  end
64
54
 
65
55
  def find_collisions
66
- @collidable_actors ||= []
56
+ spatial_hash = stagehand(:spatial)
57
+ collidable_actors = spatial_hash.moved_items
67
58
  @checks = 0
68
59
  @collisions = 0
69
- tmp_collidable_actors = @collidable_actors.dup
70
60
  collisions = {}
71
61
 
72
- @collidable_actors.each do |first|
73
- x = first.x - @spatial_hash.cell_size
74
- y = first.y - @spatial_hash.cell_size
62
+ collidable_actors.each do |first|
63
+ x = first.x - spatial_hash.cell_size
64
+ y = first.y - spatial_hash.cell_size
75
65
  # TODO base this on size of object
76
- w = @spatial_hash.cell_size * 3
66
+ w = spatial_hash.cell_size * 3
77
67
  h = w
78
68
 
79
- tmp_collidable_actors = @spatial_hash.neighbors_of(first)
80
-
81
- tmp_collidable_actors.each do |second|
82
- @checks += 1
83
- if first != second && collide?(first, second)
84
- collisions[second] ||= []
85
- if !collisions[second].include?(first)
86
- @collisions += 1
87
- collisions[first] ||= []
88
- collisions[first] << second
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
79
+ collisions[first] ||= []
80
+ collisions[first] << second
81
+ end
82
+ end
89
83
  end
90
84
  end
91
85
  end
@@ -96,12 +90,43 @@ module Arbiter
96
90
  unique_collisions << [first,second]
97
91
  end
98
92
  end
93
+
99
94
  run_callbacks unique_collisions
100
95
  end
101
96
 
102
97
  def collide?(object, other)
103
- # TODO perf analysis of this
104
- self.send "collide_#{object.collidable_shape}_#{other.collidable_shape}?", object, other
98
+ if !other.is? :collidable
99
+ binding.pry
100
+ end
101
+ case object.collidable_shape
102
+ when :circle
103
+ case other.collidable_shape
104
+ when :circle
105
+ collide_circle_circle? object, other
106
+ when :aabb
107
+ collide_circle_aabb? object, other
108
+ when :polygon
109
+ collide_circle_polygon? object, other
110
+ end
111
+ when :aabb
112
+ case other.collidable_shape
113
+ when :circle
114
+ collide_aabb_circle? object, other
115
+ when :aabb
116
+ collide_aabb_aabb? object, other
117
+ when :polygon
118
+ collide_aabb_polygon? object, other
119
+ end
120
+ when :polygon
121
+ case other.collidable_shape
122
+ when :circle
123
+ collide_polygon_circle? object, other
124
+ when :aabb
125
+ collide_polygon_aabb? object, other
126
+ when :polygon
127
+ collide_polygon_polygon? object, other
128
+ end
129
+ end
105
130
  end
106
131
 
107
132
  def collide_circle_circle?(object, other)
@@ -110,8 +135,10 @@ module Arbiter
110
135
  x_prime = other.center_x
111
136
  y_prime = other.center_y
112
137
 
113
- x_dist = (x_prime - x) * (x_prime - x)
114
- y_dist = (y_prime - y) * (y_prime - y)
138
+ x_delta = x_prime - x
139
+ x_dist = x_delta * x_delta
140
+ y_delta = y_prime - y
141
+ y_dist = y_delta * y_delta
115
142
 
116
143
  total_radius = object.radius + other.radius
117
144
  x_dist + y_dist <= (total_radius * total_radius)
@@ -56,11 +56,11 @@ class Behavior
56
56
  @actor.instance_eval do
57
57
  (class << self; self; end).class_eval do
58
58
  methods.each do |meth|
59
- log("redefining #{meth} for #{@actor.class}") if @actor.respond_to? meth
59
+ # log("redefining #{meth} for #{@actor.class}") if @actor.respond_to? meth
60
60
  target.relegated_methods << meth
61
61
 
62
- define_method meth do |*args|
63
- target.send meth, *args
62
+ define_method meth do |*args, &block|
63
+ target.send meth, *args, &block
64
64
  end
65
65
  end
66
66
  end
@@ -1,4 +1,4 @@
1
- require 'behavior'
1
+
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:
@@ -1,4 +1,4 @@
1
- require 'behavior'
1
+
2
2
 
3
3
  class Audible < Behavior
4
4
 
@@ -1,7 +1,7 @@
1
- require 'behavior'
2
- require 'collidable/circle_collidable'
3
- require 'collidable/aabb_collidable'
4
- require 'collidable/polygon_collidable'
1
+
2
+
3
+
4
+
5
5
 
6
6
  # available collidable_shapes are :circle, :polygon, :aabb
7
7
  class Collidable < Behavior
@@ -22,6 +22,11 @@ class Collidable < Behavior
22
22
  @actor.stage.register_collidable @actor
23
23
  end
24
24
 
25
+ def removed
26
+ @actor.stage.unregister_collidable @actor
27
+ super
28
+ end
29
+
25
30
  def build_shape
26
31
  shape = nil
27
32
  @collidable_shape = opts[:shape]
@@ -1,8 +1,33 @@
1
- require 'collidable/collidable_shape'
1
+
2
2
 
3
3
  class AaBbCollidable < CollidableShape
4
4
  attr_accessor :cw_local_points
5
5
 
6
+ def setup
7
+ @collidable_shape = opts[:shape]
8
+
9
+ @cw_local_points = opts[:cw_local_points]
10
+ @cw_local_points ||= opts[:points]
11
+ @cw_world_points ||= build_aabb
12
+
13
+ @radius = opts[:radius]
14
+ @radius ||= calculate_radius
15
+
16
+ @old_x = actor_x
17
+ @old_y = actor_y
18
+ end
19
+
20
+ def build_aabb
21
+ w = @actor.width
22
+ h = @actor.height
23
+ [
24
+ [0,0],
25
+ [w,0],
26
+ [w,h],
27
+ [0,h]
28
+ ]
29
+ end
30
+
6
31
  # TODO infinite loop if actor hasn't defined width and it gets relegated to us
7
32
  def calculate_radius
8
33
  w = @actor.width