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
@@ -1,68 +1,39 @@
|
|
1
1
|
class StageManager
|
2
2
|
|
3
|
-
|
4
|
-
:
|
3
|
+
construct_with :input_manager, :config_manager, :backstage,
|
4
|
+
:this_object_context
|
5
5
|
|
6
|
-
|
6
|
+
attr_reader :stage_names, :stage_opts
|
7
|
+
|
8
|
+
def initialize
|
7
9
|
@stages = {}
|
8
|
-
@backstage = Backstage.new
|
9
10
|
|
10
|
-
|
11
|
-
stages = @config_manager.load_config('stage_config')[:stages]
|
11
|
+
stages = Gamebox.configuration.stages
|
12
12
|
|
13
13
|
@stage_names = []
|
14
14
|
@stage_opts = []
|
15
15
|
stages.each do |stage|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
opts = @stage_opts[index]
|
27
|
-
|
28
|
-
name = opts[:class]
|
29
|
-
name ||= stage_name
|
30
|
-
stage_klass_name ||= Inflector.camelize name.to_s+"Stage"
|
31
|
-
|
32
|
-
begin
|
33
|
-
require name.to_s+"_stage"
|
34
|
-
rescue LoadError => ex
|
35
|
-
STDERR.puts ex
|
36
|
-
# TODO hrm.. should this get logged
|
37
|
-
# hope it's defined somewhere else
|
16
|
+
if stage.is_a? Hash
|
17
|
+
stage_name = stage.keys.first
|
18
|
+
opts = stage.values.first
|
19
|
+
@stage_names << stage_name
|
20
|
+
opts ||= {}
|
21
|
+
@stage_opts << opts
|
22
|
+
else
|
23
|
+
@stage_names << stage
|
24
|
+
@stage_opts << {}
|
25
|
+
end
|
38
26
|
end
|
39
|
-
stage_klass = ObjectSpace.const_get stage_klass_name
|
40
27
|
end
|
41
28
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
stage_instance.when :next_stage do |*args|
|
46
|
-
next_stage *args
|
47
|
-
end
|
48
|
-
stage_instance.when :prev_stage do |*args|
|
49
|
-
prev_stage *args
|
50
|
-
end
|
51
|
-
stage_instance.when :restart_stage do |*args|
|
52
|
-
restart_stage *args
|
53
|
-
end
|
54
|
-
stage_instance.when :change_stage do |stage_name, *args|
|
55
|
-
switch_to_stage stage_name, *args
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
stage_instance
|
29
|
+
def default_stage
|
30
|
+
@stage_names.first
|
60
31
|
end
|
61
32
|
|
62
33
|
def next_stage(*args)
|
63
34
|
index = @stage_names.index @stage
|
64
35
|
if index == @stage_names.size-1
|
65
|
-
|
36
|
+
log "last stage, exiting"
|
66
37
|
exit
|
67
38
|
end
|
68
39
|
|
@@ -72,7 +43,7 @@ class StageManager
|
|
72
43
|
def prev_stage(*args)
|
73
44
|
index = @stage_names.index @stage
|
74
45
|
if index == 0
|
75
|
-
|
46
|
+
log "first stage, exiting"
|
76
47
|
exit
|
77
48
|
end
|
78
49
|
|
@@ -80,9 +51,6 @@ class StageManager
|
|
80
51
|
end
|
81
52
|
|
82
53
|
def restart_stage(*args)
|
83
|
-
current_stage.curtain_dropping *args
|
84
|
-
index = @stage_names.index @stage
|
85
|
-
|
86
54
|
switch_to_stage @stage, *args
|
87
55
|
end
|
88
56
|
|
@@ -117,11 +85,36 @@ class StageManager
|
|
117
85
|
if @stage and @stages and @stages[@stage]
|
118
86
|
current_stage = @stages[@stage]
|
119
87
|
current_stage.curtain_dropping *args
|
120
|
-
|
88
|
+
input_manager.clear_hooks(current_stage)
|
121
89
|
@stages.delete @stage
|
122
90
|
@stage = nil
|
123
91
|
@stage_args = nil
|
124
92
|
end
|
125
93
|
end
|
126
94
|
|
95
|
+
def create_stage(name, opts)
|
96
|
+
stage_instance = nil
|
97
|
+
this_object_context.in_subcontext do |stage_context|
|
98
|
+
name_or_klass = opts[:class] || name
|
99
|
+
stage_instance = stage_context["#{name_or_klass}_stage"]
|
100
|
+
stage_context[:stage] = stage_instance
|
101
|
+
end
|
102
|
+
stage_instance.configure(backstage, opts)
|
103
|
+
|
104
|
+
stage_instance.when :next_stage do |*args|
|
105
|
+
next_stage *args
|
106
|
+
end
|
107
|
+
stage_instance.when :prev_stage do |*args|
|
108
|
+
prev_stage *args
|
109
|
+
end
|
110
|
+
stage_instance.when :restart_stage do |*args|
|
111
|
+
restart_stage *args
|
112
|
+
end
|
113
|
+
stage_instance.when :change_stage do |stage_name, *args|
|
114
|
+
switch_to_stage stage_name, *args
|
115
|
+
end
|
116
|
+
stage_instance
|
117
|
+
end
|
118
|
+
|
119
|
+
|
127
120
|
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class TimerManager
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@timers ||= {}
|
5
|
+
@dead_timers = []
|
6
|
+
end
|
7
|
+
|
8
|
+
# add block to be executed every interval_ms millis
|
9
|
+
def add_timer(name, interval_ms, recurring = true, &block)
|
10
|
+
raise "timer [#{name}] already exists" if @timers[name]
|
11
|
+
@timers[name] = {
|
12
|
+
count: 0, recurring: recurring,
|
13
|
+
interval_ms: interval_ms, callback: block}
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_timer(name)
|
17
|
+
@timers.delete name
|
18
|
+
end
|
19
|
+
|
20
|
+
def timer(name)
|
21
|
+
@timers[name]
|
22
|
+
end
|
23
|
+
|
24
|
+
# update each timers counts, call any blocks that are over their interval
|
25
|
+
def update(time_delta)
|
26
|
+
# TODO handle overwriting the same timer name...
|
27
|
+
@timers.each do |name, timer_hash|
|
28
|
+
timer_hash[:count] += time_delta
|
29
|
+
if timer_hash[:count] > timer_hash[:interval_ms]
|
30
|
+
timer_hash[:count] -= timer_hash[:interval_ms]
|
31
|
+
timer_hash[:callback].call
|
32
|
+
@dead_timers << name unless timer_hash[:recurring]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@dead_timers.each do |name|
|
36
|
+
remove_timer name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def pause
|
41
|
+
@paused_timers = @timers
|
42
|
+
@timers = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def unpause
|
46
|
+
@timers = @paused_timers
|
47
|
+
@paused_timers = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -76,7 +76,6 @@ class Viewport
|
|
76
76
|
scrolled = true
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
79
|
y_diff = @height/2 + @follow_offset_y - y - @y_offset
|
81
80
|
if y_diff.abs > @buffer_y
|
82
81
|
# move screen
|
@@ -120,14 +119,14 @@ class Viewport
|
|
120
119
|
|
121
120
|
@x_offset = @width/2 - @follow_target.x + @follow_offset_x
|
122
121
|
@y_offset = @height/2 - @follow_target.y + @follow_offset_y
|
123
|
-
|
122
|
+
|
124
123
|
fire :scrolled
|
125
124
|
end
|
126
125
|
|
127
126
|
def bounds
|
128
127
|
left = -@x_offset
|
129
128
|
top = -@y_offset
|
130
|
-
|
129
|
+
Rect.new left, top, left + @width, top + @height
|
131
130
|
end
|
132
131
|
|
133
132
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
class WrappedScreen
|
2
|
-
|
2
|
+
construct_with :config_manager
|
3
3
|
attr_accessor :screen
|
4
|
-
def
|
5
|
-
width, height =
|
6
|
-
fullscreen =
|
4
|
+
def initialize
|
5
|
+
width, height = *config_manager[:screen_resolution]
|
6
|
+
fullscreen = config_manager[:fullscreen]
|
7
|
+
needs_cursor = config_manager[:needs_cursor]
|
7
8
|
@screen = HookedGosuWindow.new width, height, fullscreen
|
8
|
-
@screen.
|
9
|
+
@screen.tap do |screen|
|
10
|
+
screen.caption = config_manager[:title]
|
11
|
+
screen.needs_cursor = config_manager[:needs_cursor]
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
def method_missing(name,*args)
|
@@ -114,19 +118,8 @@ class WrappedScreen
|
|
114
118
|
c
|
115
119
|
end
|
116
120
|
|
117
|
-
def
|
118
|
-
|
119
|
-
@font_cache[font_file] ||= {}
|
120
|
-
font = @font_cache[font_file][font_size] ||= Font.new(@screen, font_file, font_size)
|
121
|
-
|
122
|
-
return [font.text_width(text),font.height]
|
123
|
-
end
|
124
|
-
|
125
|
-
def render_text(text, font_file, font_size, color)
|
126
|
-
@font_cache ||= {}
|
127
|
-
@font_cache[font_file] ||= {}
|
128
|
-
font = @font_cache[font_file][font_size] ||= Font.new(@screen, font_file, font_size)
|
129
|
-
|
130
|
-
DelayedText.new font, text
|
121
|
+
def print(text, x, y, z, font_style)
|
122
|
+
font_style.font.draw text, x, y, z, font_style.x_scale, font_style.y_scale, convert_color(font_style.color)
|
131
123
|
end
|
132
124
|
end
|
125
|
+
|
@@ -14,25 +14,16 @@ class GameboxApp
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def initialize
|
17
|
-
|
18
|
-
|
19
|
-
game_objects_file = APP_ROOT + '/config/objects.yml'
|
20
|
-
game_specific_objects = {}
|
21
|
-
if File.exist? game_objects_file
|
22
|
-
game_specific_objects = YAML.load(File.read(game_objects_file))
|
23
|
-
end
|
24
|
-
objects = gamebox_objects.merge! game_specific_objects
|
25
|
-
|
26
|
-
@context = DIY::Context.from_yaml(YAML.dump(objects))
|
17
|
+
@context = Conject.default_object_context
|
27
18
|
end
|
28
|
-
|
19
|
+
|
29
20
|
def setup
|
30
21
|
@game = @context[:game]
|
31
|
-
|
22
|
+
@game.configure
|
32
23
|
@config_manager = @context[:config_manager]
|
33
24
|
setup_debug_server if @config_manager[:debug_server] || ARGV.include?("-debug-server")
|
34
25
|
end
|
35
|
-
|
26
|
+
|
36
27
|
def setup_debug_server
|
37
28
|
Thread.new do
|
38
29
|
loop do
|
@@ -40,10 +31,11 @@ class GameboxApp
|
|
40
31
|
end
|
41
32
|
end
|
42
33
|
end
|
43
|
-
|
34
|
+
|
44
35
|
def main_loop
|
45
36
|
@input_manager = @context[:input_manager]
|
46
|
-
@input_manager.
|
37
|
+
@input_manager.register @game
|
38
|
+
@input_manager.show
|
47
39
|
end
|
48
40
|
|
49
41
|
def shutdown
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module EventedAttributes
|
2
|
+
|
3
|
+
def has_attributes(*names)
|
4
|
+
if names.first.is_a? Hash
|
5
|
+
names.first.each do |name, default|
|
6
|
+
has_attribute name, default
|
7
|
+
end
|
8
|
+
else
|
9
|
+
names.each do |name|
|
10
|
+
has_attribute name
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_attribute(name, value=nil)
|
16
|
+
@evented_attributes ||= []
|
17
|
+
unless has_attribute? name
|
18
|
+
@evented_attributes << name
|
19
|
+
self.metaclass.send :kvo_attr_accessor, name
|
20
|
+
self.define_singleton_method "#{name}?" do
|
21
|
+
self.send name
|
22
|
+
end
|
23
|
+
self.send("#{name}=", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_attribute?(name)
|
28
|
+
@evented_attributes && @evented_attributes.include?(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes
|
32
|
+
{}.tap do |atts|
|
33
|
+
if @evented_attributes
|
34
|
+
@evented_attributes.each do |name|
|
35
|
+
atts[name] = self.send name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.included(klass)
|
42
|
+
klass.instance_eval do
|
43
|
+
include Kvo
|
44
|
+
def has_attribute(name)
|
45
|
+
kvo_attr_accessor name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
File without changes
|
data/lib/gamebox/lib/rect.rb
CHANGED
@@ -68,6 +68,7 @@
|
|
68
68
|
# In Rubygame, Rects are used for collision detection and describing
|
69
69
|
# the area of a Surface to operate on.
|
70
70
|
class Rect < Array
|
71
|
+
include MinMaxHelpers
|
71
72
|
|
72
73
|
#--
|
73
74
|
# GENERAL
|
@@ -142,20 +143,12 @@ class Rect < Array
|
|
142
143
|
def inspect; "#<Rect:#{self.object_id} [%s,%s,%s,%s]>"%self; end
|
143
144
|
|
144
145
|
|
145
|
-
# Returns an SDL::Rect version of this Rect. Float values are
|
146
|
-
# rounded to the nearest integer.
|
147
|
-
#
|
148
|
-
def to_sdl # :nodoc:
|
149
|
-
SDL::Rect.new( self.collect{|n| n.round } )
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
146
|
#--
|
154
147
|
# ATTRIBUTES
|
155
148
|
#++
|
156
149
|
|
157
|
-
# Returns self
|
158
|
-
def x; return self
|
150
|
+
# Returns self[0]
|
151
|
+
def x; return self[0]; end
|
159
152
|
# Sets self[0] to +val+
|
160
153
|
def x=(val); self[0] = val; end
|
161
154
|
|
@@ -164,8 +157,8 @@ class Rect < Array
|
|
164
157
|
alias l x
|
165
158
|
alias l= x=;
|
166
159
|
|
167
|
-
# Returns self
|
168
|
-
def y; return self
|
160
|
+
# Returns self[1]
|
161
|
+
def y; return self[1]; end
|
169
162
|
# Sets self[1] to +val+
|
170
163
|
def y=(val); self[1] = val; end
|
171
164
|
|
@@ -174,16 +167,16 @@ class Rect < Array
|
|
174
167
|
alias t y
|
175
168
|
alias t= y=;
|
176
169
|
|
177
|
-
# Returns self
|
178
|
-
def w; return self
|
170
|
+
# Returns self[2]
|
171
|
+
def w; return self[2]; end
|
179
172
|
# Sets self[2] to +val+
|
180
173
|
def w=(val); self[2] = val; end
|
181
174
|
|
182
175
|
alias width w
|
183
176
|
alias width= w=;
|
184
177
|
|
185
|
-
# Returns self
|
186
|
-
def h; return self
|
178
|
+
# Returns self[3]
|
179
|
+
def h; return self[3]; end
|
187
180
|
# Sets self[3] to +val+
|
188
181
|
def h=(val); self[3] = val; end
|
189
182
|
|
@@ -201,21 +194,21 @@ class Rect < Array
|
|
201
194
|
end
|
202
195
|
|
203
196
|
# Return the x coordinate of the right side of the Rect.
|
204
|
-
def right; return self
|
197
|
+
def right; return self[0]+self[2]; end
|
205
198
|
|
206
199
|
# Set the x coordinate of the right side of the Rect by translating the
|
207
200
|
# Rect (adjusting the x offset).
|
208
|
-
def right=(r); self[0] = r - self
|
201
|
+
def right=(r); self[0] = r - self[2]; return r; end
|
209
202
|
|
210
203
|
alias r right
|
211
204
|
alias r= right=;
|
212
205
|
|
213
206
|
# Return the y coordinate of the bottom side of the Rect.
|
214
|
-
def bottom; return self
|
207
|
+
def bottom; return self[1]+self[3]; end
|
215
208
|
|
216
209
|
# Set the y coordinate of the bottom side of the Rect by translating the
|
217
210
|
# Rect (adjusting the y offset).
|
218
|
-
def bottom=(b); self[1] = b - self
|
211
|
+
def bottom=(b); self[1] = b - self[3]; return b; end
|
219
212
|
|
220
213
|
alias b bottom
|
221
214
|
alias b= bottom=;
|
@@ -234,21 +227,21 @@ class Rect < Array
|
|
234
227
|
alias c= center=;
|
235
228
|
|
236
229
|
# Return the x coordinate of the center of the Rect
|
237
|
-
def centerx; return self
|
230
|
+
def centerx; return self[0]+(self[2].div(2)); end
|
238
231
|
|
239
232
|
# Set the x coordinate of the center of the Rect by translating the
|
240
233
|
# Rect (adjusting the x offset).
|
241
|
-
def centerx=(x); self[0] = x - (self
|
234
|
+
def centerx=(x); self[0] = x - (self[2].div(2)); return x; end
|
242
235
|
|
243
236
|
alias cx centerx
|
244
237
|
alias cx= centerx=;
|
245
238
|
|
246
239
|
# Return the y coordinate of the center of the Rect
|
247
|
-
def centery; return self
|
240
|
+
def centery; return self[1]+(self[3].div(2)); end
|
248
241
|
|
249
242
|
# Set the y coordinate of the center of the Rect by translating the
|
250
243
|
# Rect (adjusting the y offset).
|
251
|
-
def centery=(y); self[1] = y- (self
|
244
|
+
def centery=(y); self[1] = y- (self[3].div(2)); return y; end
|
252
245
|
|
253
246
|
alias cy centery
|
254
247
|
alias cy= centery=;
|
@@ -268,7 +261,7 @@ class Rect < Array
|
|
268
261
|
alias tl= topleft=;
|
269
262
|
|
270
263
|
# Return the x and y coordinates of the top-right corner of the Rect
|
271
|
-
def topright; return self.right, self
|
264
|
+
def topright; return self.right, self[1]; end
|
272
265
|
|
273
266
|
# Set the x and y coordinates of the top-right corner of the Rect by
|
274
267
|
# translating the Rect (adjusting the x and y offsets).
|
@@ -282,7 +275,7 @@ class Rect < Array
|
|
282
275
|
alias tr= topright=;
|
283
276
|
|
284
277
|
# Return the x and y coordinates of the bottom-left corner of the Rect
|
285
|
-
def bottomleft; return self
|
278
|
+
def bottomleft; return self[0], self.bottom; end
|
286
279
|
|
287
280
|
# Set the x and y coordinates of the bottom-left corner of the Rect by
|
288
281
|
# translating the Rect (adjusting the x and y offsets).
|
@@ -311,7 +304,7 @@ class Rect < Array
|
|
311
304
|
|
312
305
|
# Return the x and y coordinates of the midpoint on the left side of the
|
313
306
|
# Rect.
|
314
|
-
def midleft; return self
|
307
|
+
def midleft; return self[0], self.centery; end
|
315
308
|
|
316
309
|
# Set the x and y coordinates of the midpoint on the left side of the Rect
|
317
310
|
# by translating the Rect (adjusting the x and y offsets).
|
@@ -326,7 +319,7 @@ class Rect < Array
|
|
326
319
|
|
327
320
|
# Return the x and y coordinates of the midpoint on the left side of the
|
328
321
|
# Rect.
|
329
|
-
def midtop; return self.centerx, self
|
322
|
+
def midtop; return self.centerx, self[1]; end
|
330
323
|
|
331
324
|
# Set the x and y coordinates of the midpoint on the top side of the Rect
|
332
325
|
# by translating the Rect (adjusting the x and y offsets).
|
@@ -389,31 +382,31 @@ class Rect < Array
|
|
389
382
|
unless rect.contain?(nself)
|
390
383
|
|
391
384
|
#If self is too wide:
|
392
|
-
if nself
|
393
|
-
self[0] = rect.centerx - nself
|
385
|
+
if nself[2] >= rect[2]
|
386
|
+
self[0] = rect.centerx - nself[2].div(2)
|
394
387
|
#Else self is not too wide
|
395
388
|
else
|
396
389
|
#If self is to the left of arg
|
397
|
-
if nself
|
398
|
-
self[0] = rect
|
390
|
+
if nself[0] < rect[0]
|
391
|
+
self[0] = rect[0]
|
399
392
|
#If self is to the right of arg
|
400
393
|
elsif nself.right > rect.right
|
401
|
-
self[0] = rect.right - nself
|
394
|
+
self[0] = rect.right - nself[2]
|
402
395
|
#Otherwise, leave x alone
|
403
396
|
end
|
404
397
|
end
|
405
398
|
|
406
399
|
#If self is too tall:
|
407
|
-
if nself
|
408
|
-
self[1] = rect.centery - nself
|
400
|
+
if nself[3] >= rect[3]
|
401
|
+
self[1] = rect.centery - nself[3].div(2)
|
409
402
|
#Else self is not too tall
|
410
403
|
else
|
411
404
|
#If self is above arg
|
412
|
-
if nself
|
413
|
-
self[1] = rect
|
405
|
+
if nself[1] < rect[1]
|
406
|
+
self[1] = rect[1]
|
414
407
|
#If self below arg
|
415
408
|
elsif nself.bottom > rect.bottom
|
416
|
-
self[1] = rect.bottom - nself
|
409
|
+
self[1] = rect.bottom - nself[3]
|
417
410
|
#Otherwise, leave y alone
|
418
411
|
end
|
419
412
|
end
|
@@ -435,10 +428,10 @@ class Rect < Array
|
|
435
428
|
nself = self.normalize
|
436
429
|
other = Rect.new_from_object(rect).normalize!
|
437
430
|
if self.collide_rect?(other)
|
438
|
-
self[0] = [nself
|
439
|
-
self[1] = [nself
|
440
|
-
self[2] = [nself.right, other.right].min - self
|
441
|
-
self[3] = [nself.bottom, other.bottom].min - self
|
431
|
+
self[0] = [nself[0], other[0]].max
|
432
|
+
self[1] = [nself[1], other[1]].max
|
433
|
+
self[2] = [nself.right, other.right].min - self[0]
|
434
|
+
self[3] = [nself.bottom, other.bottom].min - self[1]
|
442
435
|
else #if they do not intersect at all:
|
443
436
|
self[0], self[1] = nself.topleft
|
444
437
|
self[2], self[3] = 0, 0
|
@@ -505,8 +498,8 @@ class Rect < Array
|
|
505
498
|
|
506
499
|
# True if the caller and the given Rect overlap (or touch) at all.
|
507
500
|
def collide_rect?(rect)
|
508
|
-
nself = self
|
509
|
-
rect = Rect.new_from_object(rect)
|
501
|
+
nself = self #.normalize
|
502
|
+
rect = Rect.new_from_object(rect)#.normalize!
|
510
503
|
return ((nself.l >= rect.l && nself.l <= rect.r) or (rect.l >= nself.l && rect.l <= nself.r)) &&
|
511
504
|
((nself.t >= rect.t && nself.t <= rect.b) or (rect.t >= nself.t && rect.t <= nself.b))
|
512
505
|
end
|
@@ -514,18 +507,18 @@ class Rect < Array
|
|
514
507
|
# True if the given Rect is totally within the caller. Borders may
|
515
508
|
# overlap.
|
516
509
|
def contain?(rect)
|
517
|
-
nself = self
|
518
|
-
rect = Rect.new_from_object(rect)
|
510
|
+
nself = self#.normalize
|
511
|
+
rect = Rect.new_from_object(rect)#.normalize!
|
519
512
|
return (nself.left <= rect.left and rect.right <= nself.right and
|
520
513
|
nself.top <= rect.top and rect.bottom <= nself.bottom)
|
521
514
|
end
|
522
515
|
|
523
516
|
# As #inflate!, but the original caller is not changed.
|
524
517
|
def inflate(x,y)
|
525
|
-
return self.class.new(self
|
526
|
-
self
|
527
|
-
self
|
528
|
-
self
|
518
|
+
return self.class.new(self[0] - x.div(2),
|
519
|
+
self[1] - y.div(2),
|
520
|
+
self[2] + x,
|
521
|
+
self[3] + y)
|
529
522
|
end
|
530
523
|
|
531
524
|
# Increase the Rect's size is the x and y directions, while keeping the
|
@@ -561,11 +554,11 @@ class Rect < Array
|
|
561
554
|
# area it represents. Has no effect on Rects with non-negative width
|
562
555
|
# and height. Some Rect methods will automatically normalize the Rect.
|
563
556
|
def normalize!
|
564
|
-
if self
|
565
|
-
self[0], self[2] = self
|
557
|
+
if self[2] < 0
|
558
|
+
self[0], self[2] = self[0]+self[2], -self[2]
|
566
559
|
end
|
567
|
-
if self
|
568
|
-
self[1], self[3] = self
|
560
|
+
if self[3] < 0
|
561
|
+
self[1], self[3] = self[1]+self[3], -self[3]
|
569
562
|
end
|
570
563
|
self
|
571
564
|
end
|
@@ -606,6 +599,71 @@ class Rect < Array
|
|
606
599
|
return self
|
607
600
|
end
|
608
601
|
|
602
|
+
# calculate the area of the Rect
|
603
|
+
def area
|
604
|
+
w * h
|
605
|
+
end
|
606
|
+
|
607
|
+
def zero_out!
|
608
|
+
self[0] = 0
|
609
|
+
self[1] = 0
|
610
|
+
self[2] = 0
|
611
|
+
self[3] = 0
|
612
|
+
end
|
613
|
+
|
614
|
+
def union_area(rect)
|
615
|
+
rleft = self.left
|
616
|
+
rtop = self.top
|
617
|
+
rright = self.right
|
618
|
+
rbottom = self.bottom
|
619
|
+
r2 = Rect.new_from_object(rect)
|
620
|
+
|
621
|
+
rleft = min(rleft, r2.left)
|
622
|
+
rtop = min(rtop, r2.top)
|
623
|
+
rright = max(rright, r2.right)
|
624
|
+
rbottom = max(rbottom, r2.bottom)
|
625
|
+
|
626
|
+
(rright - rleft) * (rbottom - rtop)
|
627
|
+
end
|
628
|
+
|
629
|
+
def union_fast(rect)
|
630
|
+
rleft = self.left
|
631
|
+
rtop = self.top
|
632
|
+
rright = self.right
|
633
|
+
rbottom = self.bottom
|
634
|
+
r2 = Rect.new_from_object(rect)
|
635
|
+
|
636
|
+
rleft = min(rleft, r2.left)
|
637
|
+
rtop = min(rtop, r2.top)
|
638
|
+
rright = max(rright, r2.right)
|
639
|
+
rbottom = max(rbottom, r2.bottom)
|
640
|
+
|
641
|
+
Rect.new(rleft, rtop, rright - rleft, rbottom - rtop)
|
642
|
+
end
|
643
|
+
|
644
|
+
def expand_to_include!(rect)
|
645
|
+
rleft = self.left
|
646
|
+
rtop = self.top
|
647
|
+
rright = self.right
|
648
|
+
rbottom = self.bottom
|
649
|
+
r2 = Rect.new_from_object(rect)
|
650
|
+
|
651
|
+
rleft = min(rleft, r2.left)
|
652
|
+
rtop = min(rtop, r2.top)
|
653
|
+
rright = max(rright, r2.right)
|
654
|
+
rbottom = max(rbottom, r2.bottom)
|
655
|
+
|
656
|
+
self.x = rleft
|
657
|
+
self.y = rtop
|
658
|
+
self.w = rright - rleft
|
659
|
+
self.h = rbottom - rtop
|
660
|
+
end
|
661
|
+
|
662
|
+
def refit_for!(rect_a, rect_b)
|
663
|
+
self.zero_out!
|
664
|
+
self.expand_to_include! rect_a
|
665
|
+
self.expand_to_include! rect_b
|
666
|
+
end
|
609
667
|
|
610
668
|
end # class Rect
|
611
669
|
|