gamebox 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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