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.
- data/README.rdoc +38 -0
- data/Rakefile +1 -10
- data/TODO.txt +6 -6
- data/app_generators/gamebox_generator.rb +95 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/.gitignore +0 -0
- data/app_generators/templates/Gemfile +7 -0
- data/app_generators/templates/NEXT_STEPS.txt +1 -0
- data/{lib/gamebox/templates/template_app/README → app_generators/templates/README.rdoc} +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/Rakefile +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/config/boot.rb +0 -0
- data/app_generators/templates/config/environment.rb +30 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/config/game.yml +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/fonts/FONTS_GO_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/graphics/GRAPHICS_GO_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/music/MUSIC_GOES_HERE +0 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/data/sounds/SOUND_FX_GO_HERE +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_spec.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_view.erb +0 -0
- data/{lib/gamebox/templates → app_generators/templates/script}/actor_view_spec.erb +0 -0
- data/app_generators/templates/script/generate +12 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/spec/helper.rb +0 -0
- data/app_generators/templates/src/actors/player.rb +8 -0
- data/{lib/gamebox/templates/template_app → app_generators/templates}/src/app.rb +0 -0
- data/app_generators/templates/src/demo_stage.rb +7 -0
- data/bin/gamebox +8 -70
- data/component_generators/actor_generator.rb +17 -0
- data/docs/CODE_REVIEW +1 -1
- data/docs/REFACTOR_NOTES.txt +25 -0
- data/docs/getting_started.rdoc +1 -1
- data/gamebox.gemspec +7 -4
- data/lib/gamebox.rb +6 -3
- data/lib/gamebox/actors/collidable_debugger.rb +13 -15
- data/lib/gamebox/actors/curtain.rb +44 -43
- data/lib/gamebox/actors/emitter.rb +3 -42
- data/lib/gamebox/actors/fps.rb +13 -6
- data/lib/gamebox/actors/label.rb +42 -34
- data/lib/gamebox/actors/logo.rb +2 -4
- data/lib/gamebox/actors/score.rb +37 -27
- data/lib/gamebox/actors/svg_actor.rb +45 -32
- data/lib/gamebox/behaviors/animated.rb +39 -59
- data/lib/gamebox/behaviors/audible.rb +14 -14
- data/lib/gamebox/behaviors/collidable.rb +65 -36
- data/lib/gamebox/behaviors/collidable/aabb_collidable.rb +2 -3
- data/lib/gamebox/behaviors/collidable/collidable_shape.rb +6 -4
- data/lib/gamebox/behaviors/collidable/polygon_collidable.rb +1 -1
- data/lib/gamebox/behaviors/emitting.rb +48 -0
- data/lib/gamebox/behaviors/graphical.rb +22 -56
- data/lib/gamebox/behaviors/layered.rb +8 -21
- data/lib/gamebox/behaviors/physical.rb +202 -213
- data/lib/gamebox/behaviors/positioned.rb +16 -0
- data/lib/gamebox/behaviors/projectile.rb +15 -0
- data/lib/gamebox/behaviors/visible.rb +16 -0
- data/lib/gamebox/core/aabb_helpers.rb +61 -0
- data/lib/gamebox/core/aabb_node.rb +118 -0
- data/lib/gamebox/core/aabb_tree.rb +137 -0
- data/lib/gamebox/core/actor.rb +102 -0
- data/lib/gamebox/core/actor_factory.rb +56 -0
- data/lib/gamebox/core/actor_view.rb +63 -0
- data/lib/gamebox/core/actor_view_factory.rb +40 -0
- data/lib/gamebox/{arbiter.rb → core/arbiter.rb} +31 -34
- data/lib/gamebox/{backstage.rb → core/backstage.rb} +0 -0
- data/lib/gamebox/core/behavior.rb +64 -0
- data/lib/gamebox/core/behavior_factory.rb +56 -0
- data/lib/gamebox/{class_finder.rb → core/class_finder.rb} +0 -0
- data/lib/gamebox/{config_manager.rb → core/config_manager.rb} +1 -1
- data/lib/gamebox/core/configuration.rb +39 -0
- data/lib/gamebox/core/core.rb +30 -0
- data/lib/gamebox/core/deprecated.rb +15 -0
- data/lib/gamebox/{director.rb → core/director.rb} +6 -11
- data/lib/gamebox/core/font_style.rb +26 -0
- data/lib/gamebox/core/font_style_factory.rb +11 -0
- data/lib/gamebox/core/game.rb +19 -0
- data/lib/gamebox/{hooked_gosu_window.rb → core/hooked_gosu_window.rb} +12 -6
- data/lib/gamebox/{input_manager.rb → core/input_manager.rb} +106 -99
- data/lib/gamebox/core/physics.rb +22 -0
- data/lib/gamebox/{physical_stage.rb → core/physics_manager.rb} +36 -30
- data/lib/gamebox/{resource_manager.rb → core/resource_manager.rb} +19 -18
- data/lib/gamebox/{sound_manager.rb → core/sound_manager.rb} +9 -7
- data/lib/gamebox/{stage.rb → core/stage.rb} +42 -80
- data/lib/gamebox/{stage_manager.rb → core/stage_manager.rb} +46 -53
- data/lib/gamebox/{stagehand.rb → core/stagehand.rb} +0 -0
- data/lib/gamebox/{svg_document.rb → core/svg_document.rb} +0 -0
- data/lib/gamebox/core/timer_manager.rb +50 -0
- data/lib/gamebox/{viewport.rb → core/viewport.rb} +2 -3
- data/lib/gamebox/{wrapped_screen.rb → core/wrapped_screen.rb} +12 -19
- data/lib/gamebox/gamebox_application.rb +7 -15
- data/lib/gamebox/lib/evented_attributes.rb +51 -0
- data/lib/gamebox/{ftor.rb → lib/ftor.rb} +0 -0
- data/lib/gamebox/lib/min_max_helpers.rb +10 -0
- data/lib/gamebox/lib/rect.rb +112 -54
- data/lib/gamebox/lib/yoda.rb +46 -0
- data/lib/gamebox/spec/helper.rb +317 -12
- data/lib/gamebox/stagehands/spatial_tree_stagehand.rb +61 -0
- data/lib/gamebox/version.rb +8 -3
- data/lib/gamebox/views/graphical_actor_view.rb +22 -29
- data/script/perf_aabb.rb +56 -0
- data/script/perf_array_access.rb +16 -0
- data/script/perf_collisions.rb +37 -18
- data/script/perf_struct_vs_array.rb +7 -7
- data/spec/acceptance/animation_spec.rb +65 -0
- data/spec/acceptance/basic_actor_lifecycle_spec.rb +92 -0
- data/spec/acceptance/built_in_collision_handling_spec.rb +55 -0
- data/spec/acceptance/chipmunk_collision_handling_spec.rb +83 -0
- data/spec/acceptance/fps_actor_spec.rb +40 -0
- data/spec/acceptance/pausing_spec.rb +61 -0
- data/spec/acceptance/timer_usage_spec.rb +53 -0
- data/spec/actors/emitter_spec.rb +5 -0
- data/spec/{label_spec.rb → actors/label_spec.rb} +1 -1
- data/spec/behaviors/animated_spec.rb +85 -0
- data/spec/behaviors/collidable_spec.rb +134 -0
- data/spec/{physical_spec.rb → behaviors/physical_spec.rb} +2 -1
- data/spec/behaviors/positioned_spec.rb +6 -0
- data/spec/behaviors/projectile_spec.rb +6 -0
- data/spec/core/aabb_tree_spec.rb +109 -0
- data/spec/core/actor_factory_spec.rb +44 -0
- data/spec/core/actor_spec.rb +78 -0
- data/spec/core/actor_view_spec.rb +53 -0
- data/spec/{arbiter_spec.rb → core/arbiter_spec.rb} +29 -30
- data/spec/core/backstage_spec.rb +37 -0
- data/spec/core/behavior_factory_spec.rb +50 -0
- data/spec/core/behavior_spec.rb +8 -0
- data/spec/core/configuration_spec.rb +8 -0
- data/spec/core/core_spec.rb +13 -0
- data/spec/core/font_style_factory_spec.rb +17 -0
- data/spec/core/font_style_spec.rb +41 -0
- data/spec/core/hooked_gosu_window_spec.rb +75 -0
- data/spec/core/input_manager_spec.rb +285 -0
- data/spec/core/physics_manager_spec.rb +11 -0
- data/spec/core/resource_manager_spec.rb +12 -0
- data/spec/core/stage_manager_spec.rb +140 -0
- data/spec/core/stage_spec.rb +73 -0
- data/spec/core/timer_manager_spec.rb +89 -0
- data/spec/{viewport_spec.rb → core/viewport_spec.rb} +6 -3
- data/spec/core/wrapped_screen_spec.rb +26 -0
- data/spec/fixtures/game.yml +7 -0
- data/spec/fixtures/snelpling/idle/1.png +0 -0
- data/spec/fixtures/snelpling/jump/1.png +0 -0
- data/spec/fixtures/snelpling/jump/2.png +0 -0
- data/spec/fixtures/snelpling/jump/3.png +0 -0
- data/spec/helper.rb +8 -0
- data/spec/{class_finder_spec.rb → lib/class_finder_spec.rb} +2 -1
- data/spec/stagehands/spatial_tree_stagehand_spec.rb +19 -0
- data/spec/views/graphical_actor_view_spec.rb +116 -0
- metadata +343 -144
- data/README.txt +0 -34
- data/lib/gamebox/actor.rb +0 -179
- data/lib/gamebox/actor_factory.rb +0 -57
- data/lib/gamebox/actor_view.rb +0 -44
- data/lib/gamebox/actors/spatial_debugger.rb +0 -62
- data/lib/gamebox/behavior.rb +0 -70
- data/lib/gamebox/behaviors/timed.rb +0 -33
- data/lib/gamebox/behaviors/updatable.rb +0 -12
- data/lib/gamebox/console_app.rb +0 -41
- data/lib/gamebox/gamebox_generator.rb +0 -32
- data/lib/gamebox/generators/actor_generator.rb +0 -43
- data/lib/gamebox/generators/view_generator.rb +0 -42
- data/lib/gamebox/physical_director.rb +0 -17
- data/lib/gamebox/physics.rb +0 -32
- data/lib/gamebox/spatial_bucket.rb +0 -9
- data/lib/gamebox/spatial_hash.rb +0 -194
- data/lib/gamebox/spatial_stagehand.rb +0 -80
- data/lib/gamebox/templates/template_app/Gemfile +0 -6
- data/lib/gamebox/templates/template_app/config/environment.rb +0 -23
- data/lib/gamebox/templates/template_app/config/stage_config.yml +0 -2
- data/lib/gamebox/templates/template_app/script/generate +0 -7
- data/lib/gamebox/templates/template_app/src/demo_stage.rb +0 -11
- data/lib/gamebox/templates/template_app/src/game.rb +0 -19
- data/lib/gamebox/templates/template_app/src/my_actor.rb +0 -14
- data/script/perf_spatial_hash.rb +0 -64
- data/spec/actor_factory_spec.rb +0 -61
- data/spec/actor_spec.rb +0 -71
- data/spec/actor_view_spec.rb +0 -61
- data/spec/animated_spec.rb +0 -83
- data/spec/backstage_spec.rb +0 -45
- data/spec/behavior_spec.rb +0 -28
- data/spec/collidable_spec.rb +0 -135
- data/spec/emitter_spec.rb +0 -20
- data/spec/input_manager_spec.rb +0 -134
- data/spec/resource_manager_spec.rb +0 -13
- data/spec/spatial_hash_spec.rb +0 -119
- data/spec/spatial_stagehand_spec.rb +0 -93
- data/spec/stage_manager_spec.rb +0 -25
- data/spec/stage_spec.rb +0 -65
@@ -0,0 +1,16 @@
|
|
1
|
+
define_behavior :positioned do
|
2
|
+
requires :director
|
3
|
+
setup do
|
4
|
+
actor.has_attributes x: 0, y: 0
|
5
|
+
director.when :update do |time|
|
6
|
+
if @x_dirty || @y_dirty
|
7
|
+
actor.react_to :position_changed
|
8
|
+
actor.emit :position_changed
|
9
|
+
end
|
10
|
+
@x_dirty = false
|
11
|
+
@y_dirty = false
|
12
|
+
end
|
13
|
+
actor.when :x_changed do @x_dirty = true end
|
14
|
+
actor.when :y_changed do @y_dirty = true end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
define_behavior :projectile do
|
2
|
+
|
3
|
+
requires :director
|
4
|
+
requires_behaviors :positioned
|
5
|
+
setup do
|
6
|
+
actor.has_attributes vel_x: 0,
|
7
|
+
vel_y: 0
|
8
|
+
|
9
|
+
director.when :update do |time, secs|
|
10
|
+
actor.x += (actor.vel_x * secs)
|
11
|
+
actor.y += (actor.vel_y * secs)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# in charge of registering / showing / hiding of actor views
|
2
|
+
define_behavior :visible do
|
3
|
+
requires :stage
|
4
|
+
setup do
|
5
|
+
actor.has_attribute :visible
|
6
|
+
end
|
7
|
+
|
8
|
+
react_to do |message, *args|
|
9
|
+
if message == :show
|
10
|
+
stage.register_drawable opts[:view] unless actor.visible
|
11
|
+
elsif message == :hide
|
12
|
+
stage.unregister_drawable opts[:view] if actor.visible
|
13
|
+
end
|
14
|
+
actor.visible = message == :show
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module AABBTreeDebugHelpers
|
2
|
+
def valid?
|
3
|
+
return true unless @root
|
4
|
+
@root.contains_children?
|
5
|
+
end
|
6
|
+
|
7
|
+
def each(&blk)
|
8
|
+
return unless @root
|
9
|
+
query @root.bb, &blk
|
10
|
+
end
|
11
|
+
|
12
|
+
def each_node(&blk)
|
13
|
+
return unless @root
|
14
|
+
@root.each_node &blk
|
15
|
+
end
|
16
|
+
|
17
|
+
def each_leaf(&blk)
|
18
|
+
return unless @root
|
19
|
+
@root.each_leaf &blk
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module AABBNodeDebugHelpers
|
24
|
+
|
25
|
+
def contains_children?
|
26
|
+
if leaf?
|
27
|
+
true
|
28
|
+
else
|
29
|
+
@bb.contain?(a.bb) &&
|
30
|
+
@bb.contain?(b.bb) &&
|
31
|
+
@a.contains_children? &&
|
32
|
+
@b.contains_children?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def each_node(&blk)
|
37
|
+
blk.call self
|
38
|
+
unless leaf?
|
39
|
+
@a.each_node &blk
|
40
|
+
@b.each_node &blk
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def each_leaf(&blk)
|
45
|
+
if leaf?
|
46
|
+
blk.call self
|
47
|
+
else leaf?
|
48
|
+
@a.each_leaf &blk
|
49
|
+
@b.each_leaf &blk
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def root
|
54
|
+
node = self
|
55
|
+
while node.parent
|
56
|
+
node = node.parent
|
57
|
+
end
|
58
|
+
node
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# This is the primary element in an AABBTree.
|
2
|
+
# It acts as both containing elements and leaf elements. Leaves have an @object,
|
3
|
+
# containers have @a and @b nodes. All leaf nodes have a cached list of
|
4
|
+
# collisions that contain references to other nodes in the tree.
|
5
|
+
class AABBNode
|
6
|
+
include AABBNodeDebugHelpers
|
7
|
+
attr_accessor :bb, :a, :b, :parent, :object, :cached_collisions
|
8
|
+
|
9
|
+
def initialize(parent, object, bb)
|
10
|
+
@parent = parent
|
11
|
+
@a = nil
|
12
|
+
@b = nil
|
13
|
+
|
14
|
+
@object = object
|
15
|
+
@bb = bb
|
16
|
+
end
|
17
|
+
|
18
|
+
def insert_subtree(leaf)
|
19
|
+
if leaf?
|
20
|
+
new_node = AABBNode.new nil, nil, @bb.union_fast(leaf.bb)
|
21
|
+
new_node.a = self
|
22
|
+
new_node.b = leaf
|
23
|
+
return new_node
|
24
|
+
else
|
25
|
+
cost_a = @b.bb.area + @a.bb.union_area(leaf.bb)
|
26
|
+
cost_b = @a.bb.area + @b.bb.union_area(leaf.bb)
|
27
|
+
|
28
|
+
if cost_a == cost_b
|
29
|
+
cost_a = @a.proximity(leaf)
|
30
|
+
cost_b = @b.proximity(leaf)
|
31
|
+
end
|
32
|
+
|
33
|
+
if cost_b < cost_a
|
34
|
+
self.b = @b.insert_subtree leaf
|
35
|
+
else
|
36
|
+
self.a = @a.insert_subtree leaf
|
37
|
+
end
|
38
|
+
|
39
|
+
@bb.expand_to_include! leaf.bb
|
40
|
+
return self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove_subtree(leaf)
|
45
|
+
if leaf == self
|
46
|
+
return nil
|
47
|
+
else
|
48
|
+
if leaf.parent == self
|
49
|
+
other_child = other(leaf)
|
50
|
+
other_child.parent = @parent
|
51
|
+
return other_child
|
52
|
+
else
|
53
|
+
leaf.parent.disown_child leaf
|
54
|
+
return self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def query_subtree(search_bb, &blk)
|
60
|
+
if @bb.collide_rect? search_bb
|
61
|
+
if leaf?
|
62
|
+
blk.call @object
|
63
|
+
else
|
64
|
+
@a.query_subtree search_bb, &blk
|
65
|
+
@b.query_subtree search_bb, &blk
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def leaf?
|
71
|
+
@object
|
72
|
+
end
|
73
|
+
|
74
|
+
def a=(new_a)
|
75
|
+
@a = new_a
|
76
|
+
@a.parent = self
|
77
|
+
end
|
78
|
+
|
79
|
+
def b=(new_b)
|
80
|
+
@b = new_b
|
81
|
+
@b.parent = self
|
82
|
+
end
|
83
|
+
|
84
|
+
def other(child)
|
85
|
+
@a == child ? @b : @a
|
86
|
+
end
|
87
|
+
|
88
|
+
def disown_child(leaf)
|
89
|
+
value = other(leaf)
|
90
|
+
raise "Internal Error: Cannot replace child of a leaf." if @parent.leaf?
|
91
|
+
raise "Internal Error: AABBNode is not a child of parent." unless self == @parent.a || self == @parent.b
|
92
|
+
|
93
|
+
if @parent.a == self
|
94
|
+
@parent.a = value
|
95
|
+
else
|
96
|
+
@parent.b = value
|
97
|
+
end
|
98
|
+
|
99
|
+
@parent.update_bb
|
100
|
+
end
|
101
|
+
|
102
|
+
def update_bb
|
103
|
+
node = self
|
104
|
+
unless node.leaf?
|
105
|
+
node.bb.refit_for! node.a.bb, node.b.bb
|
106
|
+
while node = node.parent
|
107
|
+
node.bb.refit_for! node.a.bb, node.b.bb
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def proximity(other_node)
|
113
|
+
other_bb = other_node.bb
|
114
|
+
(@bb.left + @bb.right - other_bb.left - other_bb.right).abs +
|
115
|
+
(@bb.bottom + @bb.top - other_bb.bottom - other_bb.top).abs
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# AABBTree is a binary tree where each node has a bounding box that contains
|
2
|
+
# its children's bounding boxes. It extrapolates and expands the node bounding
|
3
|
+
# boxes before inserting to lower the amount of updates to the tree structure.
|
4
|
+
# It caches all leaf node collisions for quick lookup.
|
5
|
+
class AABBTree
|
6
|
+
include AABBTreeDebugHelpers
|
7
|
+
DEFAULT_BB_SCALE = 1
|
8
|
+
VELOCITY_SCALE = 3
|
9
|
+
|
10
|
+
attr_reader :items
|
11
|
+
extend Forwardable
|
12
|
+
def_delegators :@items, :size, :include?
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@items = {}
|
16
|
+
@root = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def query(search_bb, &callback)
|
20
|
+
return unless @root
|
21
|
+
@root.query_subtree search_bb, &callback
|
22
|
+
end
|
23
|
+
|
24
|
+
def collisions(item, &blk)
|
25
|
+
leaf = @items[item]
|
26
|
+
return unless leaf && leaf.cached_collisions
|
27
|
+
leaf.cached_collisions.each do |collider|
|
28
|
+
blk.call collider.object
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def insert(item)
|
33
|
+
raise "Adding an existing item, please use update" if @items[item]
|
34
|
+
leaf = AABBNode.new nil, item, calculate_bb(item)
|
35
|
+
@items[item] = leaf
|
36
|
+
insert_leaf leaf
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove(item)
|
40
|
+
leaf = @items.delete item
|
41
|
+
@root = @root.remove_subtree leaf if leaf
|
42
|
+
clear_cached_collisions leaf
|
43
|
+
end
|
44
|
+
|
45
|
+
def update(item)
|
46
|
+
node = @items[item]
|
47
|
+
if node && node.leaf?
|
48
|
+
new_bb = calculate_bb(item)
|
49
|
+
unless node.bb.contain? item.bb
|
50
|
+
node.bb = new_bb
|
51
|
+
clear_cached_collisions node
|
52
|
+
@root = @root.remove_subtree node
|
53
|
+
insert_leaf node
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def clear_cached_collisions(leaf)
|
61
|
+
cached_collisions = leaf.cached_collisions
|
62
|
+
|
63
|
+
if cached_collisions
|
64
|
+
leaf.cached_collisions = nil
|
65
|
+
cached_collisions.each do |other|
|
66
|
+
other.cached_collisions.delete leaf
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_cached_collisions(leaf)
|
72
|
+
each_leaf do |other|
|
73
|
+
if leaf != other && leaf.bb.collide_rect?(other.bb)
|
74
|
+
leaf.cached_collisions ||= []
|
75
|
+
other.cached_collisions ||= []
|
76
|
+
leaf.cached_collisions << other
|
77
|
+
other.cached_collisions << leaf
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def insert_leaf(leaf)
|
83
|
+
if @root
|
84
|
+
@root = @root.insert_subtree leaf
|
85
|
+
else
|
86
|
+
@root = leaf
|
87
|
+
end
|
88
|
+
build_cached_collisions leaf
|
89
|
+
end
|
90
|
+
|
91
|
+
def expand_bb_by!(bb, percent)
|
92
|
+
new_w = bb.w * percent
|
93
|
+
new_h = bb.h * percent
|
94
|
+
hw = new_w / 2.0
|
95
|
+
hh = new_h / 2.0
|
96
|
+
|
97
|
+
bb.x = (bb.x - hw).ceil
|
98
|
+
bb.y = (bb.y - hh).ceil
|
99
|
+
bb.w = (bb.w + new_w).ceil
|
100
|
+
bb.h = (bb.h + new_h).ceil
|
101
|
+
bb
|
102
|
+
end
|
103
|
+
|
104
|
+
def project_bb_by_velocity!(bb, velocity_vector)
|
105
|
+
future_vector = velocity_vector * VELOCITY_SCALE
|
106
|
+
projected_bb = [bb.x + velocity_vector.x,
|
107
|
+
bb.y + velocity_vector.y,
|
108
|
+
bb.w, bb.h ]
|
109
|
+
|
110
|
+
u_bb = bb.union_fast(projected_bb)
|
111
|
+
bb.x = u_bb.x
|
112
|
+
bb.y = u_bb.y
|
113
|
+
bb.w = u_bb.w
|
114
|
+
bb.h = u_bb.y
|
115
|
+
end
|
116
|
+
|
117
|
+
def calculate_bb(item)
|
118
|
+
if item.respond_to? :bb
|
119
|
+
bb = item.bb.dup
|
120
|
+
project_bb_by_velocity!(bb, item.velocity) if item.respond_to? :velocity
|
121
|
+
expand_bb_by!(bb, DEFAULT_BB_SCALE)
|
122
|
+
else
|
123
|
+
if item.respond_to? :width
|
124
|
+
w = item.width
|
125
|
+
h = item.height
|
126
|
+
elsif item.respond_to? :radius
|
127
|
+
w = item.radius * 2
|
128
|
+
h = item.radius * 2
|
129
|
+
end
|
130
|
+
w ||= 2
|
131
|
+
h ||= 2
|
132
|
+
|
133
|
+
expand_bb_by!(Rect.new item.x, item.y, w, h, DEFAULT_BB_SCALE)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# Actor represent a game object.
|
2
|
+
# Actors can have behaviors added and removed from them. Such as :physical or :animated.
|
3
|
+
# They are created and hooked up to their optional View class in Stage#create_actor.
|
4
|
+
class Actor
|
5
|
+
extend Publisher
|
6
|
+
include EventedAttributes
|
7
|
+
include Gamebox::Extensions::Object::Yoda
|
8
|
+
can_fire_anything
|
9
|
+
construct_with :this_object_context
|
10
|
+
public :this_object_context
|
11
|
+
|
12
|
+
has_attribute :alive
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@behaviors = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure(opts={}) # :nodoc:
|
19
|
+
has_attributes opts
|
20
|
+
self.actor_type = opts[:actor_type]
|
21
|
+
self.alive = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_behavior(name, behavior)
|
25
|
+
@behaviors[name] = behavior
|
26
|
+
end
|
27
|
+
|
28
|
+
def react_to(message, *opts)
|
29
|
+
# TODO cache the values array?
|
30
|
+
@behaviors.values.each do |behavior|
|
31
|
+
behavior.react_to(message, *opts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_behavior?(name)
|
36
|
+
@behaviors[name]
|
37
|
+
end
|
38
|
+
|
39
|
+
def emit(event, *args)
|
40
|
+
fire event, *args
|
41
|
+
end
|
42
|
+
|
43
|
+
# Tells the actor's Director that he wants to be removed; and unsubscribes
|
44
|
+
# the actor from all input events.
|
45
|
+
def remove
|
46
|
+
self.alive = false
|
47
|
+
react_to :remove
|
48
|
+
fire :remove_me
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
atts = methods.sort - Actor.instance_methods
|
53
|
+
atts_hash = {}
|
54
|
+
atts.each do |att|
|
55
|
+
atts_hash[att] = send(att) unless att.to_s.end_with? "="
|
56
|
+
end
|
57
|
+
"#{self.actor_type}:#{self.object_id} with attributes\n#{atts_hash.inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
# TODO should this live somewhere else?
|
61
|
+
# TODO should we support "inheritance" of components?
|
62
|
+
class << self
|
63
|
+
|
64
|
+
def define(actor_type, opts={}, &blk)
|
65
|
+
@definitions ||= {}
|
66
|
+
definition = ActorDefinition.new
|
67
|
+
definition.instance_eval &blk if block_given?
|
68
|
+
@definitions[actor_type] = definition
|
69
|
+
|
70
|
+
view_blk = definition.view_blk
|
71
|
+
if view_blk
|
72
|
+
ActorView.define "#{actor_type}_view".to_sym, &view_blk
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def definitions
|
77
|
+
@definitions ||= {}
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
class ActorDefinition
|
83
|
+
attr_accessor :behaviors, :attributes, :view_blk
|
84
|
+
def initialize
|
85
|
+
@behaviors = []
|
86
|
+
@attributes = []
|
87
|
+
end
|
88
|
+
|
89
|
+
def has_behaviors(*behaviors)
|
90
|
+
behaviors.each do |beh|
|
91
|
+
@behaviors << beh
|
92
|
+
end
|
93
|
+
end
|
94
|
+
alias has_behavior has_behaviors
|
95
|
+
|
96
|
+
# TODO spec view helper on actor def
|
97
|
+
def view(&blk)
|
98
|
+
@view_blk = blk
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|