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.
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/History.txt +5 -0
- data/README.txt +4 -3
- data/Rakefile +12 -4
- data/TODO.txt +1 -5
- data/VERSION +1 -1
- data/docs/getting_started.rdoc +2 -2
- data/gamebox.gemspec +26 -10
- data/lib/gamebox/actor.rb +10 -3
- data/lib/gamebox/actor_factory.rb +2 -2
- data/lib/gamebox/actor_view.rb +14 -11
- data/lib/gamebox/actors/collidable_debugger.rb +35 -0
- data/lib/gamebox/actors/curtain.rb +2 -2
- data/lib/gamebox/actors/logo.rb +0 -6
- data/lib/gamebox/actors/score.rb +2 -5
- data/lib/gamebox/actors/spatial_debugger.rb +47 -0
- data/lib/gamebox/actors/svg_actor.rb +4 -6
- data/lib/gamebox/arbiter.rb +108 -15
- data/lib/gamebox/behavior.rb +29 -1
- data/lib/gamebox/behaviors/animated.rb +14 -23
- data/lib/gamebox/behaviors/audible.rb +1 -12
- data/lib/gamebox/behaviors/collidable.rb +29 -22
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +61 -0
- data/lib/gamebox/behaviors/collidable/circle_collidable.rb +17 -0
- data/lib/gamebox/behaviors/collidable/collidable_shape.rb +35 -0
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +85 -0
- data/lib/gamebox/behaviors/graphical.rb +13 -10
- data/lib/gamebox/behaviors/layered.rb +6 -20
- data/lib/gamebox/behaviors/physical.rb +116 -93
- data/lib/gamebox/class_finder.rb +6 -2
- data/lib/gamebox/config_manager.rb +24 -4
- data/lib/gamebox/data/config/objects.yml +5 -3
- data/lib/gamebox/ftor.rb +372 -0
- data/lib/gamebox/gamebox_application.rb +2 -8
- data/lib/gamebox/hooked_gosu_window.rb +30 -0
- data/lib/gamebox/input_manager.rb +78 -79
- data/lib/gamebox/lib/code_statistics.rb +1 -1
- data/lib/gamebox/lib/numbers_ext.rb +1 -1
- data/lib/gamebox/lib/rect.rb +612 -0
- data/lib/gamebox/physical_stage.rb +12 -2
- data/lib/gamebox/physics.rb +14 -3
- data/lib/gamebox/resource_manager.rb +28 -65
- data/lib/gamebox/sound_manager.rb +7 -13
- data/lib/gamebox/spatial_hash.rb +60 -14
- data/lib/gamebox/spatial_stagehand.rb +19 -0
- data/lib/gamebox/stage.rb +16 -1
- data/lib/gamebox/stage_manager.rb +1 -1
- data/lib/gamebox/svg_document.rb +1 -0
- data/lib/gamebox/tasks/gamebox_tasks.rb +23 -11
- data/lib/gamebox/templates/template_app/.gitignore +1 -0
- data/lib/gamebox/templates/template_app/Gemfile +1 -1
- data/lib/gamebox/templates/template_app/Rakefile +6 -21
- data/lib/gamebox/templates/template_app/config/environment.rb +14 -0
- data/lib/gamebox/templates/template_app/config/game.yml +2 -1
- data/lib/gamebox/templates/template_app/script/generate +0 -3
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -11
- data/lib/gamebox/templates/template_app/src/game.rb +0 -1
- data/lib/gamebox/templates/template_app/src/my_actor.rb +2 -2
- data/lib/gamebox/version.rb +1 -1
- data/lib/gamebox/views/graphical_actor_view.rb +15 -9
- data/lib/gamebox/wrapped_screen.rb +114 -7
- data/load_paths.rb +20 -0
- data/script/perf_spatial_hash.rb +73 -0
- data/spec/actor_view_spec.rb +1 -1
- data/spec/arbiter_spec.rb +264 -0
- data/spec/behavior_spec.rb +19 -2
- data/spec/collidable_spec.rb +105 -5
- data/spec/helper.rb +1 -1
- data/spec/label_spec.rb +1 -1
- data/spec/resource_manager_spec.rb +1 -1
- data/spec/spatial_hash_spec.rb +1 -1
- metadata +52 -10
- data/lib/gamebox/lib/surface_ext.rb +0 -76
@@ -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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
36
|
+
build_main_shape
|
37
|
+
setup_main_collisions
|
38
|
+
setup_position
|
39
|
+
setup_elasticity
|
40
|
+
setup_friction
|
38
41
|
|
39
|
-
|
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
|
-
|
44
|
-
shape_array = @opts[:verts].collect{|v| vec2(v[0],v[1])}
|
44
|
+
register
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
-
|
67
|
+
@shape.collision_type = @collision_type
|
68
|
+
end
|
59
69
|
|
60
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|