gamebox 0.4.0.rc5 → 0.4.0.rc11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/README.md +205 -127
  2. data/bin/gamebox +49 -3
  3. data/bin/gb +87 -0
  4. data/gamebox.gemspec +4 -3
  5. data/lib/gamebox.rb +1 -1
  6. data/lib/gamebox/actors/collidable_debugger.rb +4 -4
  7. data/lib/gamebox/actors/icon.rb +7 -0
  8. data/lib/gamebox/actors/label.rb +41 -42
  9. data/lib/gamebox/behaviors/animated.rb +6 -0
  10. data/lib/gamebox/behaviors/audible.rb +1 -2
  11. data/lib/gamebox/behaviors/collidable.rb +1 -1
  12. data/lib/gamebox/behaviors/graphical.rb +8 -4
  13. data/lib/gamebox/behaviors/physical.rb +6 -1
  14. data/lib/gamebox/behaviors/positioned.rb +4 -11
  15. data/lib/gamebox/behaviors/projectile.rb +8 -0
  16. data/lib/gamebox/behaviors/visible.rb +3 -3
  17. data/lib/gamebox/core/aabb_tree.rb +1 -1
  18. data/lib/gamebox/core/actor.rb +37 -50
  19. data/lib/gamebox/core/actor_definition.rb +41 -0
  20. data/lib/gamebox/core/actor_view.rb +6 -21
  21. data/lib/gamebox/core/actor_view_definition.rb +19 -0
  22. data/lib/gamebox/core/actor_view_factory.rb +9 -3
  23. data/lib/gamebox/core/behavior.rb +8 -27
  24. data/lib/gamebox/core/behavior_definition.rb +24 -0
  25. data/lib/gamebox/core/config_manager.rb +45 -30
  26. data/lib/gamebox/core/configuration.rb +5 -0
  27. data/lib/gamebox/core/core.rb +4 -0
  28. data/lib/gamebox/core/debug_helpers.rb +46 -0
  29. data/lib/gamebox/core/director.rb +32 -5
  30. data/lib/gamebox/core/event_symbols.rb +214 -0
  31. data/lib/gamebox/core/game.rb +1 -1
  32. data/lib/gamebox/core/input_manager.rb +1 -4
  33. data/lib/gamebox/core/input_mapper.rb +85 -0
  34. data/lib/gamebox/core/physics.rb +7 -3
  35. data/lib/gamebox/core/physics_manager.rb +5 -1
  36. data/lib/gamebox/core/renderer.rb +72 -0
  37. data/lib/gamebox/core/stage.rb +25 -81
  38. data/lib/gamebox/core/stage_definition.rb +60 -0
  39. data/lib/gamebox/core/stage_factory.rb +56 -0
  40. data/lib/gamebox/core/stage_manager.rb +5 -11
  41. data/lib/gamebox/core/timer_manager.rb +6 -2
  42. data/lib/gamebox/core/viewport.rb +12 -5
  43. data/lib/gamebox/core/wrapped_screen.rb +8 -5
  44. data/lib/gamebox/gamebox_application.rb +21 -19
  45. data/lib/gamebox/lib/array_ext.rb +9 -0
  46. data/lib/gamebox/lib/observable_attributes.rb +24 -0
  47. data/lib/gamebox/lib/vector2.rb +432 -0
  48. data/lib/gamebox/post_setup_handlers/file_watcher.rb +37 -0
  49. data/lib/gamebox/post_setup_handlers/gamebox_debug_helpers.rb +13 -0
  50. data/lib/gamebox/post_setup_handlers/pry_remote_server.rb +29 -0
  51. data/lib/gamebox/spec/helper.rb +165 -17
  52. data/lib/gamebox/tasks/gamebox_tasks.rake +27 -12
  53. data/lib/gamebox/version.rb +1 -1
  54. data/lib/gamebox/views/graphical_actor_view.rb +4 -5
  55. data/script/perf_aabb.rb +13 -8
  56. data/spec/acceptance/animation_spec.rb +1 -3
  57. data/spec/acceptance/basic_actor_lifecycle_spec.rb +1 -1
  58. data/spec/acceptance/fps_actor_spec.rb +8 -12
  59. data/spec/acceptance/input_mapper_spec.rb +17 -24
  60. data/spec/acceptance/update_ordering_spec.rb +64 -0
  61. data/spec/actors/label_spec.rb +90 -5
  62. data/spec/behaviors/animated_spec.rb +1 -1
  63. data/spec/behaviors/collidable_spec.rb +7 -15
  64. data/spec/behaviors/positioned_spec.rb +12 -5
  65. data/spec/core/actor_spec.rb +31 -3
  66. data/spec/core/actor_view_spec.rb +1 -1
  67. data/spec/core/behavior_spec.rb +3 -0
  68. data/spec/core/configuration_spec.rb +49 -2
  69. data/spec/core/input_mapper_spec.rb +7 -0
  70. data/spec/core/renderer_spec.rb +89 -0
  71. data/spec/core/stage_definition_spec.rb +41 -0
  72. data/spec/core/stage_manager_spec.rb +11 -11
  73. data/spec/core/stage_spec.rb +38 -78
  74. data/spec/core/viewport_spec.rb +5 -2
  75. data/spec/core/wrapped_screen_spec.rb +18 -12
  76. data/spec/views/graphical_actor_view_spec.rb +33 -62
  77. data/templates/actor_template.erb +11 -0
  78. data/templates/app/README.md +1 -0
  79. data/templates/app/src/actors/{player.rb → player_actor.rb} +3 -1
  80. data/templates/app/src/behaviors/.gitkeep +0 -0
  81. data/templates/app/src/stages/demo_stage.rb +14 -0
  82. data/templates/behavior_template.erb +13 -0
  83. data/templates/stage_template.erb +13 -0
  84. metadata +60 -21
  85. data/component_generators/actor_generator.rb +0 -17
  86. data/lib/gamebox/actors/emitter.rb +0 -12
  87. data/lib/gamebox/behaviors/emitting.rb +0 -48
  88. data/lib/gamebox/behaviors/input_mapper.rb +0 -11
  89. data/lib/gamebox/lib/ftor.rb +0 -372
  90. data/spec/actors/emitter_spec.rb +0 -5
  91. data/templates/app/NEXT_STEPS.txt +0 -1
  92. data/templates/app/README.rdoc +0 -24
  93. data/templates/app/src/demo_stage.rb +0 -7
@@ -0,0 +1,37 @@
1
+ module PostSetupHandlers
2
+
3
+ class FileWatcher
4
+
5
+ def self.setup(argv,env,config)
6
+ start_file_watcher if config[:debug] or argv.include?('--debug')
7
+ end
8
+
9
+ def self.filepaths
10
+ [ "src/behaviors/", "src/actors" ]
11
+ end
12
+
13
+ def self.start_file_watcher
14
+ log "File Watcher is now watching (#{filepaths.join(', ')}) for changes."
15
+
16
+ Thread.abort_on_exception = true
17
+
18
+ Thread.new do
19
+ require 'listen'
20
+ Listen.to(*filepaths, filter: /\.rb$/) do |modified, added, removed|
21
+ (modified + added).each do |path|
22
+ path[/([^\/]*)\.rb/]
23
+ filename = $1
24
+ case path
25
+ when /behaviors/
26
+ reload_behavior filename
27
+ when /actors/
28
+ load_actor filename
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module PostSetupHandlers
3
+
4
+ class GameboxAppAddDebugHelpers
5
+ def self.setup(argv,env,config)
6
+ if config[:debug] or ARGV.include?("--debug")
7
+ log "GameboxApp now includes DEBUG Helpers"
8
+ GameboxApp.send :include, DebugHelpers
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ module PostSetupHandlers
2
+ class PryRemoteServer
3
+ def self.setup(argv,env,config)
4
+ start_remote_pry if config[:debug] or argv.include?('--debug')
5
+ end
6
+
7
+ def self.start_remote_pry
8
+ log "Pry Remote Server started!"
9
+
10
+ Thread.abort_on_exception = true
11
+
12
+ Thread.new do
13
+ loop do
14
+ begin
15
+ if th = DRb.thread
16
+ th.kill
17
+ end
18
+
19
+ binding.remote_pry
20
+ log "remote_pry returned"
21
+ rescue Exception => e
22
+ log "finished remote pry"
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -18,10 +18,114 @@ module GameboxSpecHelpers
18
18
  before { @_mocks_created = create_mocks(*mock_names_array) }
19
19
  subject { described_class.new @_mocks_created }
20
20
  end
21
+
22
+ def subjectify_behavior(behavior_name)
23
+ before {
24
+ @_beh_mock_names = Behavior.object_definition.component_names
25
+ @actor = evented_stub(mock("actor_for_#{behavior_name}"))
26
+ @_mocks_created = create_mocks *(@_beh_mock_names - [:actor])
27
+ @_mocks_created[:actor] = @actor
28
+
29
+
30
+ @behavior_definition = Behavior.definitions[behavior_name]
31
+ reqs = @behavior_definition.required_injections || []
32
+ reqs -= @_beh_mock_names
33
+ @_req_mocks = create_mocks(*reqs)
34
+ }
35
+ let (:opts) { {} }
36
+ subject {
37
+
38
+ # TODO so much duplication here from the *Factories
39
+ Behavior.new(@_mocks_created).tap do |behavior|
40
+ @_req_mocks.keys.each do |req|
41
+ object = @_req_mocks[req]
42
+ behavior.define_singleton_method req do
43
+ components[req]
44
+ end
45
+ components = behavior.send :components
46
+ components[req] = object
47
+ end
48
+
49
+ helpers = @behavior_definition.helpers_block
50
+ if helpers
51
+ helpers_module = Module.new &helpers
52
+ behavior.extend helpers_module
53
+ end
54
+
55
+ behavior.define_singleton_method :react_to, @behavior_definition.react_to_block if @behavior_definition.react_to_block
56
+
57
+ # TODO not sure the right way to mock this out
58
+ # deps = @behavior_definition.required_behaviors
59
+ # if deps
60
+ # deps.each do |beh|
61
+ # _add_behavior actor, beh unless actor.has_behavior?(beh)
62
+ # end
63
+ # end
64
+ behavior.configure(opts)
65
+ behavior.instance_eval &@behavior_definition.setup_block if @behavior_definition.setup_block
66
+ end
67
+ }
68
+ end
69
+
70
+ def subjectify_actor(actor_type)
71
+ actor_definition = Actor.definitions[actor_type]
72
+ before {
73
+ @_mocks_created = create_mocks *Actor.object_definition.component_names
74
+ }
75
+ subject {
76
+ Actor.new(@_mocks_created).tap do |actor|
77
+
78
+ actor_definition.behaviors.each do |behavior|
79
+ beh_opts = {}
80
+ beh_key = behavior
81
+
82
+ if behavior.is_a?(Hash)
83
+ beh_opts = behavior.values.first
84
+ beh_key = behavior.keys.first
85
+ end
86
+
87
+ actor_definition.attributes.each do |attr|
88
+ actor.has_attributes attr
89
+ end
90
+
91
+ actor.add_behavior beh_key, beh_opts
92
+ end
93
+ end
94
+ }
95
+ end
96
+
97
+ def subjectify_actor_view(view_name)
98
+ view_definition = ActorView.definitions[view_name]
99
+ before {
100
+ reqs = view_definition.required_injections || []
101
+
102
+ @_mocks_created = create_mocks( *ActorView.object_definition.component_names + reqs)
103
+ @_mocks_created[:actor] = evented_stub(@_mocks_created[:actor])
104
+
105
+ }
106
+ subject {
107
+ ActorView.new(@_mocks_created).tap do |view|
108
+ view.define_singleton_method :draw, &view_definition.draw_block if view_definition.draw_block
109
+ if view_definition.setup_block
110
+ view.define_singleton_method :setup, &view_definition.setup_block
111
+ view.configure
112
+ end
113
+ end
114
+ }
115
+ end
21
116
  end
22
117
 
23
118
  module InstanceMethods
24
119
 
120
+
121
+ def actor_stubs(actor, attributes={})
122
+ attributes.each do |att, value|
123
+ actor.stubs(att).returns(value)
124
+ actor.stubs(:do_or_do_not).with(att).returns(value)
125
+ end
126
+ end
127
+
128
+
25
129
  def create_actor(type=:actor, args={})
26
130
  act = create_conjected_object type, nil, false
27
131
  act.configure args.merge(actor_type: type)
@@ -130,21 +234,24 @@ module GameboxAcceptanceSpecHelpers
130
234
 
131
235
  def caption=(new_caption)
132
236
  end
237
+
238
+ def rotate(*args)
239
+ yield
240
+ end
133
241
  end
134
242
 
135
243
 
136
- class ::TestingStage < Stage
244
+ module ::TestStageHelpers
137
245
  attr_accessor :actors
138
-
139
- def initialize
140
- @actors = []
246
+ def actors
247
+ @actors ||= []
141
248
  end
142
249
 
143
250
  def create_actor(actor_type, *args)
144
251
  super.tap do |act|
145
- @actors << act
252
+ actors << act
146
253
  act.when :remove_me do
147
- @actors.delete act
254
+ actors.delete act
148
255
  end
149
256
  end
150
257
  end
@@ -155,6 +262,12 @@ module GameboxAcceptanceSpecHelpers
155
262
  end
156
263
  end
157
264
 
265
+ define_stage :testing do
266
+ helpers do
267
+ include TestStageHelpers
268
+ end
269
+ end
270
+
158
271
  module MockCalls
159
272
  attr_accessor :calls
160
273
  def method_missing(*args)
@@ -168,14 +281,13 @@ module GameboxAcceptanceSpecHelpers
168
281
 
169
282
  class ::MockImage
170
283
  include MockCalls
171
- attr_accessor :filename
172
- def initialize(filename)
284
+ attr_accessor :filename, :width, :height
285
+ def initialize(filename, w, h)
173
286
  _reset!
174
287
  @filename = filename
288
+ @width = w
289
+ @height = h
175
290
  end
176
-
177
- def width; 10; end
178
- def height; 20; end
179
291
  end
180
292
 
181
293
  class ::MockFont
@@ -200,7 +312,7 @@ module GameboxAcceptanceSpecHelpers
200
312
  public *Game.object_definition.component_names
201
313
 
202
314
  def configure
203
- stage_manager.change_stage_to :testing
315
+ stage_manager.change_stage_to stage_manager.default_stage
204
316
  end
205
317
 
206
318
  def stage(&blk)
@@ -211,6 +323,10 @@ module GameboxAcceptanceSpecHelpers
211
323
  stage_manager.current_stage
212
324
  end
213
325
 
326
+ def actors(actor_type)
327
+ stage_manager.current_stage.actors.select { |act| act.actor_type == actor_type }
328
+ end
329
+
214
330
  def actor(actor_type)
215
331
  stage_manager.current_stage.actors.detect { |act| act.actor_type == actor_type }
216
332
  end
@@ -220,10 +336,23 @@ module GameboxAcceptanceSpecHelpers
220
336
  end
221
337
 
222
338
  module InstanceMethods
223
- def mock_image(filename)
339
+ def mock_tiles(filename, width, height)
340
+ context = Conject.default_object_context
341
+ resource_manager = context[:resource_manager]
342
+
343
+ [].tap do |tiles|
344
+ (width * height).times do |i|
345
+ tiles << MockImage.new("#{filename}_#{i}", 16, 16)
346
+ end
347
+
348
+ resource_manager.stubs(:load_tiles).returns(tiles)
349
+ end
350
+ end
351
+
352
+ def mock_image(filename, w=10, h=20)
224
353
  context = Conject.default_object_context
225
354
  resource_manager = context[:resource_manager]
226
- MockImage.new(filename).tap do |img|
355
+ MockImage.new(filename, w, h).tap do |img|
227
356
  resource_manager.stubs(:load_image).with(filename).returns(img)
228
357
  end
229
358
  end
@@ -246,7 +375,17 @@ module GameboxAcceptanceSpecHelpers
246
375
  def see_text_drawn(text, opts)
247
376
  font = opts[:in]
248
377
  font.calls.should_not be_empty
249
- font.calls.first.first.should == :draw
378
+ first_call = font.calls.first
379
+
380
+ first_call[0].should == :draw
381
+ first_call[1].to_s.should == text
382
+ first_call[2].should == opts[:x] if opts[:x]
383
+ first_call[3].should == opts[:y] if opts[:y]
384
+ first_call[4].should == opts[:z] if opts[:z]
385
+ first_call[5].should == opts[:x_scale] if opts[:x_scale]
386
+ first_call[6].should == opts[:y_scale] if opts[:y_scale]
387
+ first_call[7].should == opts[:color] if opts[:color]
388
+
250
389
  font._reset!
251
390
  end
252
391
 
@@ -290,8 +429,15 @@ module GameboxAcceptanceSpecHelpers
290
429
  act.should have_no_attrs(attrs)
291
430
  end
292
431
 
293
- def update(time)
294
- gosu.update time
432
+ def update(time, opts={})
433
+ step = opts[:step] || time
434
+
435
+ num_updates = time / step
436
+ num_updates.times do
437
+ gosu.update step
438
+ end
439
+ left_over = time % step
440
+ gosu.update left_over unless left_over == 0
295
441
  end
296
442
 
297
443
  def draw
@@ -364,6 +510,8 @@ RSpec.configure do |configuration|
364
510
  config.fonts_path = "spec/fixtures/"
365
511
  config.music_path = "spec/fixtures/"
366
512
  config.sound_path = "spec/fixtures/"
513
+ config.game_name = "Some Title!"
514
+ config.needs_cursor = true
367
515
  config.stages = [:testing]
368
516
  end
369
517
 
@@ -1,9 +1,10 @@
1
1
  require 'gamebox/lib/platform'
2
+ require "erb"
2
3
 
3
4
  desc "Run the game"
4
5
  task :run do |t|
5
- sh "bundle exec ruby src/app.rb"
6
- end
6
+ sh "bundle exec ruby #{APP_ROOT}src/app.rb"
7
+ end
7
8
  task :default => :run
8
9
 
9
10
  desc "Report code statistics (KLOCs, etc) from the application"
@@ -15,7 +16,7 @@ end
15
16
 
16
17
  desc "Run the game with debug server"
17
18
  task :debug do |t|
18
- sh "ruby src/app.rb -debug-server"
19
+ sh "bundle exec ruby #{APP_ROOT}src/app.rb -debug-server"
19
20
  end
20
21
 
21
22
  desc "Bundle in all required gems"
@@ -40,6 +41,21 @@ task :spec do
40
41
  end
41
42
  end
42
43
 
44
+ namespace :generate do
45
+ #didnt't use pluralize in here because I didnt want to include all of active support just for pluralize
46
+ [:actor, :stage, :behavior].each do |generator_name|
47
+ desc "generate a new #{generator_name} in the #{ generator_name }s folder"
48
+ task generator_name, "#{generator_name}_name".to_sym do |t, args|
49
+ File.open(File.join(File.dirname(__FILE__), "../../..", "/templates/#{generator_name}_template.erb")) do |io|
50
+ template = ERB.new io.read
51
+ instance_variable_set("@#{generator_name}_name", args["#{generator_name}_name"])
52
+ File.open "#{APP_ROOT}src/#{ generator_name}s/#{args["#{generator_name}_name"]}_#{generator_name}.rb", "w" do |out|
53
+ out.puts template.result binding
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
43
59
 
44
60
  namespace :dist do
45
61
  desc "Build a .app for your gamebox game"
@@ -47,7 +63,7 @@ namespace :dist do
47
63
  GAME_NAME = "UntitledGame" unless defined?(GAME_NAME)
48
64
  # DL template os x app
49
65
  remote_file = "gosu-mac-wrapper-#{Gosu::VERSION}.tar.gz"
50
- mac_build = "build/mac"
66
+ mac_build = "#{APP_ROOT}build/mac"
51
67
  local_file = "#{mac_build}/#{remote_file}"
52
68
 
53
69
  require 'net/http'
@@ -55,12 +71,11 @@ namespace :dist do
55
71
  # if false
56
72
  Net::HTTP.start("www.libgosu.org") do |http|
57
73
  resp = http.get("/downloads/#{remote_file}")
58
- open(local_file, "wb") { |file| file.write(resp.body) }
74
+ open(local_file, "wb") { |file| file.write(resp.body) }
59
75
  end
60
76
  # end
61
77
 
62
78
  # Expand it
63
- root = pwd
64
79
  cd mac_build
65
80
  `tar xzf #{remote_file}`
66
81
  app_name = "#{GAME_NAME}.app"
@@ -78,10 +93,10 @@ namespace :dist do
78
93
  clean_em_out = %w(chingu chingu.rb).map{|it| "#{dot_app_lib}/#{it}"}
79
94
  rm_rf clean_em_out#, :verbose => true, :noop => true
80
95
 
81
- cd root
96
+ cd APP_ROOT
82
97
  p `bundle --system package`
83
98
  p `bundle package`
84
- p `bundle --deployment`
99
+ p `bundle --deployment`
85
100
  mkdir_p gem_vendored
86
101
  rejects = %w(chipmunk gosu)
87
102
  Dir["vendor/bundle/ruby/**/gems/**/lib"].each do |gemmy|
@@ -98,7 +113,7 @@ namespace :dist do
98
113
  rejects = %w(spec src/app.rb vendor Main.rb)
99
114
  ok_dirs = %w(config gems src)
100
115
  REQUIRE_ALLS = ok_dirs.map{|dir| Dir.glob("\#{dir}/*.rb").reject{ |f| rejects.any?{|exclude| f.match exclude}}}.flatten
101
-
116
+
102
117
  require 'environment'
103
118
 
104
119
  GameboxApp.run ARGV, ENV
@@ -113,13 +128,13 @@ namespace :dist do
113
128
  f.puts plist.gsub "UntitledGame", GAME_NAME
114
129
  end
115
130
  end
116
-
131
+
117
132
  task :win do
118
133
  # create dist dir
119
- FileUtils.mkdir "dist" unless File.exist? "dist"
134
+ FileUtils.mkdir "#{APP_ROOT}dist" unless File.exist? "dist"
120
135
  # pull down windows app shell
121
136
  # expand into place
122
- sh 'cd dist; wget http://github.com/downloads/shawn42/gamebox/gamebox_app.zip; unzip gamebox_app.zip; mv gamebox_app/* .; rm gamebox_app.zip; rm -rf gamebox_app'
137
+ sh 'cd #{APP_ROOT}dist; wget http://github.com/downloads/shawn42/gamebox/gamebox_app.zip; unzip gamebox_app.zip; mv gamebox_app/* .; rm gamebox_app.zip; rm -rf gamebox_app'
123
138
 
124
139
  # copy config/src/lib/data into dist/src
125
140
  %w{vendor config data }.each do |dir|