gamebox 0.1.1 → 0.2.1

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 (74) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +9 -0
  3. data/History.txt +5 -0
  4. data/README.txt +4 -3
  5. data/Rakefile +12 -4
  6. data/TODO.txt +1 -5
  7. data/VERSION +1 -1
  8. data/docs/getting_started.rdoc +2 -2
  9. data/gamebox.gemspec +26 -10
  10. data/lib/gamebox/actor.rb +10 -3
  11. data/lib/gamebox/actor_factory.rb +2 -2
  12. data/lib/gamebox/actor_view.rb +14 -11
  13. data/lib/gamebox/actors/collidable_debugger.rb +35 -0
  14. data/lib/gamebox/actors/curtain.rb +2 -2
  15. data/lib/gamebox/actors/logo.rb +0 -6
  16. data/lib/gamebox/actors/score.rb +2 -5
  17. data/lib/gamebox/actors/spatial_debugger.rb +47 -0
  18. data/lib/gamebox/actors/svg_actor.rb +4 -6
  19. data/lib/gamebox/arbiter.rb +108 -15
  20. data/lib/gamebox/behavior.rb +29 -1
  21. data/lib/gamebox/behaviors/animated.rb +14 -23
  22. data/lib/gamebox/behaviors/audible.rb +1 -12
  23. data/lib/gamebox/behaviors/collidable.rb +29 -22
  24. data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +61 -0
  25. data/lib/gamebox/behaviors/collidable/circle_collidable.rb +17 -0
  26. data/lib/gamebox/behaviors/collidable/collidable_shape.rb +35 -0
  27. data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +85 -0
  28. data/lib/gamebox/behaviors/graphical.rb +13 -10
  29. data/lib/gamebox/behaviors/layered.rb +6 -20
  30. data/lib/gamebox/behaviors/physical.rb +116 -93
  31. data/lib/gamebox/class_finder.rb +6 -2
  32. data/lib/gamebox/config_manager.rb +24 -4
  33. data/lib/gamebox/data/config/objects.yml +5 -3
  34. data/lib/gamebox/ftor.rb +372 -0
  35. data/lib/gamebox/gamebox_application.rb +2 -8
  36. data/lib/gamebox/hooked_gosu_window.rb +30 -0
  37. data/lib/gamebox/input_manager.rb +78 -79
  38. data/lib/gamebox/lib/code_statistics.rb +1 -1
  39. data/lib/gamebox/lib/numbers_ext.rb +1 -1
  40. data/lib/gamebox/lib/rect.rb +612 -0
  41. data/lib/gamebox/physical_stage.rb +12 -2
  42. data/lib/gamebox/physics.rb +14 -3
  43. data/lib/gamebox/resource_manager.rb +28 -65
  44. data/lib/gamebox/sound_manager.rb +7 -13
  45. data/lib/gamebox/spatial_hash.rb +60 -14
  46. data/lib/gamebox/spatial_stagehand.rb +19 -0
  47. data/lib/gamebox/stage.rb +16 -1
  48. data/lib/gamebox/stage_manager.rb +1 -1
  49. data/lib/gamebox/svg_document.rb +1 -0
  50. data/lib/gamebox/tasks/gamebox_tasks.rb +23 -11
  51. data/lib/gamebox/templates/template_app/.gitignore +1 -0
  52. data/lib/gamebox/templates/template_app/Gemfile +1 -1
  53. data/lib/gamebox/templates/template_app/Rakefile +6 -21
  54. data/lib/gamebox/templates/template_app/config/environment.rb +14 -0
  55. data/lib/gamebox/templates/template_app/config/game.yml +2 -1
  56. data/lib/gamebox/templates/template_app/script/generate +0 -3
  57. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -11
  58. data/lib/gamebox/templates/template_app/src/game.rb +0 -1
  59. data/lib/gamebox/templates/template_app/src/my_actor.rb +2 -2
  60. data/lib/gamebox/version.rb +1 -1
  61. data/lib/gamebox/views/graphical_actor_view.rb +15 -9
  62. data/lib/gamebox/wrapped_screen.rb +114 -7
  63. data/load_paths.rb +20 -0
  64. data/script/perf_spatial_hash.rb +73 -0
  65. data/spec/actor_view_spec.rb +1 -1
  66. data/spec/arbiter_spec.rb +264 -0
  67. data/spec/behavior_spec.rb +19 -2
  68. data/spec/collidable_spec.rb +105 -5
  69. data/spec/helper.rb +1 -1
  70. data/spec/label_spec.rb +1 -1
  71. data/spec/resource_manager_spec.rb +1 -1
  72. data/spec/spatial_hash_spec.rb +1 -1
  73. metadata +52 -10
  74. data/lib/gamebox/lib/surface_ext.rb +0 -76
@@ -0,0 +1,17 @@
1
+ require 'collidable/collidable_shape'
2
+
3
+ class CircleCollidable < CollidableShape
4
+
5
+ def setup
6
+ @radius ||= opts[:radius]
7
+ end
8
+
9
+ def center_x
10
+ actor_x + radius
11
+ end
12
+
13
+ def center_y
14
+ actor_y + radius
15
+ end
16
+
17
+ end
@@ -0,0 +1,35 @@
1
+ class CollidableShape
2
+ attr_accessor :opts, :actor, :radius
3
+ def initialize(actor, options)
4
+ @opts = options
5
+ @actor = actor
6
+
7
+ @x_offset = opts[:x_offset]
8
+ @y_offset = opts[:y_offset]
9
+ @x_offset ||= 0
10
+ @y_offset ||= 0
11
+ end
12
+
13
+ def actor_x
14
+ @actor.x + @x_offset
15
+ end
16
+
17
+ def actor_y
18
+ @actor.y + @y_offset
19
+ end
20
+
21
+ def setup
22
+ end
23
+
24
+ def width
25
+ @radius * 2
26
+ end
27
+ alias :height :width
28
+
29
+ def update(time)
30
+ recalculate_collidable_cache
31
+ end
32
+
33
+ def recalculate_collidable_cache
34
+ end
35
+ end
@@ -0,0 +1,85 @@
1
+ require 'collidable/collidable_shape'
2
+
3
+ class PolygonCollidable < CollidableShape
4
+ attr_accessor :cw_local_points
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
+
12
+ @radius = opts[:radius]
13
+ @radius ||= calculate_radius
14
+
15
+ @old_x = actor_x
16
+ @old_y = actor_y
17
+ end
18
+
19
+ def calculate_radius
20
+ local_avg = cw_local_points.inject([0,0]) {|s, (x,y)| s[0] += x; s[1]+=y; s}.map {|x| x / cw_local_points.size}
21
+ max_dist = 0
22
+ cw_local_points.each do |lp|
23
+ x_dist = local_avg[0]-lp[0]
24
+ y_dist = local_avg[1]-lp[1]
25
+ dist = Math.sqrt(x_dist*x_dist + y_dist*y_dist)
26
+ max_dist = dist if dist > max_dist
27
+ end
28
+ max_dist
29
+ end
30
+
31
+ def center_x
32
+ poly_center[0]
33
+ end
34
+
35
+ def center_y
36
+ poly_center[1]
37
+ end
38
+
39
+ def poly_center
40
+ @cached_poly_center ||= cw_world_points.inject([0,0]) {|s, (x,y)| s[0] += x; s[1]+=y; s}.map {|x| x / cw_world_points.size}
41
+ end
42
+
43
+ def cw_world_points
44
+ @cached_points ||= @cw_local_points.map{|lp| [lp[0]+actor_x,lp[1]+actor_y]}
45
+ end
46
+
47
+ def cw_world_lines
48
+ return @cached_lines if @cached_lines
49
+ lines = []
50
+
51
+ cw_world_points.each_cons(2) do |a,b|
52
+ lines << [a,b]
53
+ end
54
+ lines << [cw_world_points[-1],cw_world_points[0]]
55
+
56
+ @cached_lines = lines
57
+ end
58
+
59
+ def cw_world_edge_normals
60
+ return @cached_normals if @cached_normals
61
+
62
+ @cached_normals = cw_world_lines.map do |edge|
63
+ # vector subtraction
64
+ v = edge[1][0]-edge[0][0], edge[1][1]-edge[0][1]
65
+ [-v[1],v[0]]
66
+ end
67
+
68
+ @cached_normals
69
+ end
70
+
71
+ def recalculate_collidable_cache
72
+ unless @old_x == actor_x && @old_y == actor_y
73
+ clear_collidable_cache
74
+ @old_x = actor_x
75
+ @old_y = actor_y
76
+ end
77
+ end
78
+
79
+ def clear_collidable_cache
80
+ @cached_points = nil
81
+ @cached_lines = nil
82
+ @cached_poly_center = nil
83
+ end
84
+
85
+ end
@@ -15,16 +15,19 @@ class Graphical < Behavior
15
15
  @num_y_tiles ||= 1
16
16
 
17
17
  graphical_obj = self
18
- @actor.instance_eval do
19
- (class << self; self; end).class_eval do
20
- define_method :image do
21
- graphical_obj.image
22
- end
23
- define_method :graphical do
24
- graphical_obj
25
- end
26
- end
27
- end
18
+ relegates :image, :graphical, :width, :height
19
+ end
20
+
21
+ def graphical
22
+ self
23
+ end
24
+
25
+ def width
26
+ image.width
27
+ end
28
+
29
+ def height
30
+ image.height
28
31
  end
29
32
 
30
33
  def tiled?
@@ -16,26 +16,12 @@ class Layered < Behavior
16
16
  @layer ||= 0
17
17
  @parallax ||= 1
18
18
 
19
- layered_obj = self
20
- @actor.instance_eval do
21
- (class << self; self; end).class_eval do
22
- define_method :layer= do |new_layer|
23
- layered_obj.layer = new_layer
24
- end
25
- define_method :parallax= do |new_parallax|
26
- layered_obj.parallax = new_parallax
27
- end
28
- define_method :layer do
29
- layered_obj.layer
30
- end
31
- define_method :parallax do
32
- layered_obj.parallax
33
- end
34
- define_method :layered do
35
- layered_obj
36
- end
37
- end
38
- end
19
+ relegates :layer=, :layer, :parallax=, :parallax,
20
+ :layered
21
+ end
22
+
23
+ def layered
24
+ self
39
25
  end
40
26
 
41
27
  def parallax=(new_parallax)
@@ -19,70 +19,101 @@ class Physical < Behavior
19
19
  attr_accessor :shapes, :body, :opts, :parts, :segments_groups
20
20
 
21
21
  def shape
22
- @shapes.first if @shapes
22
+ if @shapes
23
+ @shapes.first
24
+ else
25
+ @shape
26
+ end
23
27
  end
24
28
 
25
29
  def setup
26
- # TODO add defaults?
27
- @mass = @opts[:mass]
28
- @mass ||= Float::INFINITY
29
30
  @parts = {}
30
31
  @shapes = []
31
32
  @segments_groups = []
32
33
 
33
- moment_of_inertia = @opts[:moment]
34
+ @moment_of_inertia = @opts[:moment]
34
35
 
35
- case @opts[:shape]
36
- when :circle
37
- @radius = @opts[:radius]
36
+ build_main_shape
37
+ setup_main_collisions
38
+ setup_position
39
+ setup_elasticity
40
+ setup_friction
38
41
 
39
- moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_circle(@mass, @radius, 0, ZERO_VEC_2)
40
- @body = Body.new(@mass, moment_of_inertia)
41
- @shape = Shape::Circle.new(@body, @radius, ZERO_VEC_2)
42
+ build_secondary_shapes
42
43
 
43
- when :poly
44
- shape_array = @opts[:verts].collect{|v| vec2(v[0],v[1])}
44
+ register
45
45
 
46
- moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_poly(@mass, shape_array, ZERO_VEC_2)
47
- @body = Body.new(@mass, moment_of_inertia)
48
- @shape = Shape::Poly.new(@body, shape_array, ZERO_VEC_2)
49
- verts = @opts[:verts].dup
50
- verts << @opts[:verts][0]
51
- @segments_groups << verts
52
- end
46
+ # write code here to keep physics and x,y of actor in sync
47
+ relegates :x, :y, :x=, :y=, :shape, :body, :parts,
48
+ :rotation, :warp, :segment_groups, :physical
49
+ end
50
+
51
+ def setup_friction
52
+ @friction = @opts[:friction]
53
+ @friction ||= 0.4
54
+ @shape.u = @friction
55
+ end
56
+
57
+ def setup_elasticity
58
+ @elasticity = @opts[:elasticity]
59
+ @elasticity ||= 0.1
60
+ @shape.e = @elasticity
61
+ end
53
62
 
54
- collision_type = @opts[:collision_group]
55
- collision_type ||=
63
+ def setup_main_collisions
64
+ @collision_type = @opts[:collision_group]
65
+ @collision_type ||=
56
66
  Inflector.underscore(@actor.class).to_sym
57
-
58
- @body.a = @opts[:angle] if @opts[:angle]
67
+ @shape.collision_type = @collision_type
68
+ end
59
69
 
60
- @shape.collision_type = collision_type
70
+ def setup_position
71
+ @body.a = @opts[:angle] if @opts[:angle]
61
72
  start_x = @opts[:x]
62
73
  start_y = @opts[:y]
63
74
  start_x ||= @actor.x
64
75
  start_y ||= @actor.y
65
76
  @shape.body.p = vec2(start_x,start_y)
66
77
 
67
- elasticity = @opts[:elasticity]
68
- elasticity ||= 0.1
69
- @shape.e = elasticity
78
+ end
79
+
80
+ def build_main_shape
81
+ @mass = @opts[:mass]
82
+ @mass ||= Float::INFINITY
83
+
84
+ case @opts[:shape]
85
+ when :circle
86
+ @radius = @opts[:radius]
87
+
88
+ @moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_circle(@mass, @radius, 0, ZERO_VEC_2)
89
+ @body = CP::Body.new(@mass, @moment_of_inertia)
90
+ @shape = CP::Shape::Circle.new(@body, @radius, ZERO_VEC_2)
91
+
92
+ when :poly
93
+ shape_array = @opts[:verts].collect{|v| vec2(v[0],v[1])}
94
+
95
+ @moment_of_inertia ||= @opts[:fixed] ? Float::INFINITY : moment_for_poly(@mass, shape_array, ZERO_VEC_2)
96
+ @body = CP::Body.new(@mass, @moment_of_inertia)
97
+ @shape = CP::Shape::Poly.new(@body, shape_array, ZERO_VEC_2)
98
+ verts = @opts[:verts].dup
99
+ verts << @opts[:verts][0]
100
+ @segments_groups << verts
101
+ end
70
102
 
71
- friction = @opts[:friction]
72
- friction ||= 0.4
73
- @shape.u = friction
74
-
75
103
  @shapes << @shape
104
+ end
105
+
106
+ def build_secondary_shapes
76
107
 
77
108
  if @opts[:shapes]
78
109
  for obj in @opts[:shapes]
79
110
  for part_name, part_def in obj
80
111
  # add another shape here
81
112
  part_shape_array = part_def[:verts].collect{|v| vec2(v[0],v[1])}
82
- part_shape = Shape::Poly.new(@body, part_shape_array, part_def[:offset])
113
+ part_shape = CP::Shape::Poly.new(@body, part_shape_array, part_def[:offset])
83
114
  part_shape.collision_type = part_name.to_sym
84
115
  # TODO pass all physics params to parts (ie u and e)
85
- part_shape.u = friction
116
+ part_shape.u = @friction
86
117
  @shapes << part_shape
87
118
  verts = part_def[:verts].dup
88
119
  verts << part_def[:verts][0]
@@ -90,10 +121,10 @@ class Physical < Behavior
90
121
  end
91
122
  end
92
123
  end
124
+ end
93
125
 
94
-
126
+ def register
95
127
  physical_obj = self
96
-
97
128
  if @actor.stage.respond_to? :register_physical_object
98
129
  if @opts[:fixed]
99
130
  @actor.stage.register_physical_object physical_obj, true
@@ -103,64 +134,56 @@ class Physical < Behavior
103
134
  else
104
135
  raise "physical actor in a non-physical stage!"
105
136
  end
137
+ end
106
138
 
107
- # write code here to keep physics and x,y of actor in sync
108
- @actor.instance_eval do
109
- (class << self; self; end).class_eval do
110
- define_method :x do
111
- physical_obj.body.p.x
112
- end
113
- define_method :y do
114
- physical_obj.body.p.y
115
- end
116
- define_method :x= do |new_x|
117
- raise "I am physical, you should apply forces"
118
- end
119
- define_method :y= do |new_y|
120
- raise "I am physical, you should apply forces"
121
- end
122
- define_method :shape do
123
- physical_obj.shape
124
- end
125
- define_method :body do
126
- physical_obj.body
127
- end
128
- define_method :parts do
129
- physical_obj.parts
130
- end
131
- define_method :deg do
132
- # TODO hack!! why do poly's not work the same?
133
- if physical_obj.opts[:shape] == :poly
134
- -((physical_obj.body.a-1.57) * 180.0 / Math::PI + 90)
135
- else
136
- -((physical_obj.body.a) * 180.0 / Math::PI + 90)
137
- end
138
- end
139
- define_method :warp do |new_p|
140
- physical_obj.body.p = new_p
141
- @stage.space.rehash_static if physical_obj.opts[:fixed]
142
- end
143
- define_method :segment_groups do
144
- physical_obj.segments_groups
145
- end
146
- define_method :physical do
147
- physical_obj
148
- end
149
- define_method :image do
150
- old_image = nil
151
- rot_deg = deg.round % 360
152
-
153
- if is? :animated
154
- old_image = animated.image
155
- elsif is? :graphical
156
- old_image = graphical.image
157
- end
158
-
159
- if old_image
160
- old_image.rotozoom(rot_deg,1,true)
161
- end
162
- end
163
- end
139
+ def x
140
+ body.p.x
141
+ end
142
+
143
+ def y
144
+ body.p.y
145
+ end
146
+
147
+ def x=(new_x)
148
+ body.p = vec2(new_x, y)
149
+ end
150
+
151
+ def y=(new_y)
152
+ body.p = vec2(x, new_y)
153
+ end
154
+
155
+ def rotation
156
+ # TODO hack!! why do poly's not work the same?
157
+ if opts[:shape] == :poly
158
+ ((body.a-1.57) * 180.0 / Math::PI + 90) % 360
159
+ else
160
+ ((body.a) * 180.0 / Math::PI + 90) % 360
164
161
  end
162
+ # rot_deg = rotation.round % 360
165
163
  end
164
+
165
+ def warp(new_p)
166
+ body.p = new_p
167
+ @actor.stage.space.rehash_static if opts[:fixed]
168
+ end
169
+
170
+ def physical
171
+ self
172
+ end
173
+
174
+ # def image
175
+ # old_image = nil
176
+ # rot_deg = rotation.round % 360
177
+ #
178
+ # if @actor.is? :animated
179
+ # old_image = @actor.animated.image
180
+ # elsif @actor.is? :graphical
181
+ # old_image = @actor.graphical.image
182
+ # end
183
+ #
184
+ # if old_image
185
+ # # XXX rotate when drawing, not when getting image
186
+ # old_image.rotozoom(rot_deg,1,true)
187
+ # end
188
+ # end
166
189
  end