gamebox 0.0.7 → 0.0.8

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.
Files changed (53) hide show
  1. data/.gitignore +6 -0
  2. data/History.txt +6 -0
  3. data/Rakefile +25 -23
  4. data/TODO.txt +5 -3
  5. data/VERSION +1 -0
  6. data/bin/gamebox +2 -2
  7. data/docs/CODE_REVIEW +48 -0
  8. data/docs/getting_started.rdoc +30 -14
  9. data/gamebox.gemspec +184 -0
  10. data/lib/gamebox/actor.rb +29 -37
  11. data/lib/gamebox/actor_factory.rb +7 -24
  12. data/lib/gamebox/actors/curtain.rb +57 -0
  13. data/lib/gamebox/actors/label.rb +23 -0
  14. data/lib/gamebox/actors/score.rb +9 -5
  15. data/lib/gamebox/arbiter.rb +75 -0
  16. data/lib/gamebox/backstage.rb +17 -0
  17. data/lib/gamebox/behavior.rb +24 -1
  18. data/lib/gamebox/behaviors/animated.rb +2 -0
  19. data/lib/gamebox/behaviors/audible.rb +34 -0
  20. data/lib/gamebox/behaviors/collidable.rb +41 -0
  21. data/lib/gamebox/class_finder.rb +29 -0
  22. data/lib/gamebox/data/config/objects.yml +0 -1
  23. data/lib/gamebox/director.rb +13 -0
  24. data/lib/gamebox/gamebox_application.rb +2 -0
  25. data/lib/gamebox/input_manager.rb +58 -36
  26. data/lib/gamebox/{templates/template_app/lib → lib}/code_statistics.rb +0 -0
  27. data/lib/gamebox/lib/platform.rb +1 -0
  28. data/lib/gamebox/lib/surface_ext.rb +1 -1
  29. data/lib/gamebox/sound_manager.rb +11 -5
  30. data/lib/gamebox/spec/helper.rb +25 -0
  31. data/lib/gamebox/stage.rb +69 -2
  32. data/lib/gamebox/stage_manager.rb +6 -5
  33. data/lib/gamebox/tasks/gamebox_tasks.rb +18 -0
  34. data/lib/gamebox/templates/template_app/.gitignore +6 -0
  35. data/lib/gamebox/templates/template_app/README +3 -9
  36. data/lib/gamebox/templates/template_app/Rakefile +0 -13
  37. data/lib/gamebox/templates/template_app/spec/helper.rb +1 -1
  38. data/lib/gamebox/templates/template_app/src/demo_stage.rb +1 -1
  39. data/lib/gamebox/version.rb +1 -1
  40. data/lib/gamebox/views/graphical_actor_view.rb +13 -21
  41. data/spec/actor_spec.rb +12 -4
  42. data/spec/actor_view_spec.rb +16 -0
  43. data/spec/animated_spec.rb +1 -0
  44. data/spec/backstage_spec.rb +45 -0
  45. data/spec/behavior_spec.rb +11 -0
  46. data/spec/collidable_spec.rb +15 -0
  47. data/spec/label_spec.rb +11 -0
  48. data/spec/resource_manager_spec.rb +14 -0
  49. data/spec/stage_spec.rb +65 -0
  50. metadata +66 -34
  51. data/Manifest.txt +0 -97
  52. data/lib/gamebox/ftor.rb +0 -2
  53. data/lib/gamebox/templates/template_app/lib/platform.rb +0 -16
data/lib/gamebox/actor.rb CHANGED
@@ -7,21 +7,20 @@ class Actor
7
7
  can_fire_anything
8
8
 
9
9
  attr_accessor :behaviors, :x, :y, :stage, :input_manager,
10
- :resource_manager, :alive, :opts, :sound_manager, :visible,
11
- :director
12
-
10
+ :resource_manager, :alive, :opts, :visible, :director,
11
+ :actor_type
13
12
 
14
13
  def initialize(opts={}) # :nodoc:
15
14
  @opts = opts
16
- @x = @opts[:x]
17
- @y = @opts[:y]
15
+ @x = opts[:x]
16
+ @y = opts[:y]
18
17
  @x ||= 0
19
18
  @y ||= 0
20
19
  @stage = opts[:stage]
21
20
  @input_manager = opts[:input]
22
- @sound_manager = opts[:sound]
23
21
  @resource_manager = opts[:resources]
24
22
  @director = opts[:director]
23
+ @actor_type = opts[:actor_type]
25
24
  @alive = true
26
25
 
27
26
  @behaviors = {}
@@ -109,18 +108,12 @@ class Actor
109
108
 
110
109
  # Creates a new actor and returns it. (This actor will automatically be added to the Director.
111
110
  def spawn(type, args={})
112
- @stage.create_actor type, args
113
- end
114
-
115
- # Plays a sound via the SoundManager. See SoundManager for
116
- # details on how to "define" sounds.
117
- def play_sound(*args)
118
- @sound_manager.play_sound *args
111
+ @stage.spawn type, args
119
112
  end
120
113
 
121
- # Stops a sound via the SoundManager.
122
- def stop_sound(*args)
123
- @sound_manager.stop_sound *args
114
+ # Access to backstage for storage
115
+ def backstage
116
+ @stage.backstage
124
117
  end
125
118
 
126
119
  # to be defined in child class
@@ -142,29 +135,28 @@ class Actor
142
135
  def visible?
143
136
  @visible
144
137
  end
145
-
146
- # magic
147
- metaclass.instance_eval do
148
- define_method( :behaviors ) do
149
- @behaviors ||= []
150
- end
151
- define_method( :has_behaviors ) do |*args|
152
- @behaviors ||= []
153
- for a in args
154
- if a.is_a? Hash
155
- for k,v in a
156
- h = {}
157
- h[k]=v
158
- @behaviors << h
159
- end
160
- else
161
- @behaviors << a
138
+
139
+ def self.behaviors
140
+ @behaviors ||= []
141
+ end
142
+
143
+ def self.has_behaviors(*args)
144
+ @behaviors ||= []
145
+ for a in args
146
+ if a.is_a? Hash
147
+ for k,v in a
148
+ h = {}
149
+ h[k]=v
150
+ @behaviors << h
162
151
  end
152
+ else
153
+ @behaviors << a
163
154
  end
164
- @behaviors
165
- end
166
- define_method( :has_behavior ) do |*args|
167
- has_behaviors *args
168
155
  end
156
+ @behaviors
157
+ end
158
+
159
+ def self.has_behavior(*args)
160
+ has_behaviors *args
169
161
  end
170
162
  end
@@ -2,10 +2,10 @@ require 'actor'
2
2
  require 'graphical_actor_view'
3
3
 
4
4
  # ActorFactory is responsible for loading all Actors. It passes along required params such as
5
- # stage, input_manager, sound_manager, director, resource_manager. It also creates the ActorView
5
+ # stage, input_manager, director, resource_manager. It also creates the ActorView
6
6
  # associated with the Actor and registers it to the Stage be drawn.
7
7
  class ActorFactory
8
- constructor :input_manager, :sound_manager
8
+ constructor :input_manager
9
9
 
10
10
  attr_accessor :stage_manager, :director
11
11
 
@@ -15,27 +15,9 @@ class ActorFactory
15
15
  cached_actor = @actor_cache[actor]
16
16
  return cached_actor if cached_actor
17
17
 
18
+ model_klass = ClassFinder.find(actor)
19
+ view_klass = ClassFinder.find("#{actor}_view")
18
20
 
19
- model_klass_name = Inflector.camelize actor
20
- begin
21
- model_klass = Object.const_get model_klass_name
22
- rescue NameError
23
- # not there yet
24
- begin
25
- require actor.to_s
26
- require actor.to_s+"_view"
27
- rescue LoadError => ex
28
- # maybe its included somewhere else
29
- ensure
30
- model_klass = Object.const_get model_klass_name
31
- end
32
- end
33
-
34
- begin
35
- view_klass = Object.const_get model_klass_name+"View"
36
- rescue Exception => ex
37
- # hrm...
38
- end
39
21
  actor_def = {
40
22
  :model_klass => model_klass,
41
23
  :view_klass => view_klass
@@ -48,12 +30,13 @@ class ActorFactory
48
30
  def build(actor, stage, opts={})
49
31
  actor_def = cached_actor_def actor
50
32
 
33
+ actor_type = actor_def[:actor_type]
51
34
  basic_opts = {
52
35
  :stage => stage,
53
36
  :input => @input_manager,
54
- :sound => @sound_manager,
55
37
  :director => @director,
56
- :resources => stage.resource_manager
38
+ :resources => stage.resource_manager,
39
+ :actor_type => actor
57
40
  }
58
41
  merged_opts = basic_opts.merge(opts)
59
42
 
@@ -0,0 +1,57 @@
1
+ require 'actor'
2
+ require 'publisher'
3
+ require 'actor_view'
4
+
5
+ class CurtainView < ActorView
6
+ def draw(target,x_off,y_off)
7
+ target.draw_box_s [0,0],[1024,800], [0,0,0,@actor.height]
8
+ end
9
+ end
10
+
11
+ class Curtain < Actor
12
+ extend Publisher
13
+
14
+ can_fire :curtain_up, :curtain_down
15
+
16
+ has_behavior :updatable, :layered => {:layer => 99_999}
17
+
18
+ attr_accessor :height
19
+
20
+ FULL_CURTAIN = 255
21
+ NO_CURTAIN = 0
22
+ def setup
23
+ @duration_in_ms = @opts[:duration]
24
+ @duration_in_ms ||= 1000
25
+
26
+ case @opts[:dir]
27
+ when :up
28
+ @height = FULL_CURTAIN
29
+ @dir = -1
30
+ when :down
31
+ @height = NO_CURTAIN
32
+ @dir = 1
33
+ end
34
+ end
35
+
36
+ # Update curtain height 0-255 (alpha)
37
+ def update(time)
38
+ perc_change = time.to_f/@duration_in_ms
39
+ amount = FULL_CURTAIN * perc_change * @dir
40
+ @height += amount.floor
41
+
42
+ if @height < 0
43
+ @height = 0
44
+ if alive?
45
+ fire :curtain_up
46
+ remove_self
47
+ end
48
+ elsif @height > 255
49
+ @height = 255
50
+ if alive?
51
+ fire :curtain_down
52
+ remove_self
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ class LabelView < ActorView
2
+ def draw(target,x_off,y_off)
3
+ actor.text_image.blit target.screen, [actor.x, actor.y]
4
+ end
5
+ end
6
+ class Label < Actor
7
+ attr_accessor :text, :text_image
8
+
9
+ def setup
10
+ @text = @opts[:text]
11
+ @size = @opts[:size]
12
+ @font = @opts[:font]
13
+ @color = @opts[:color]
14
+
15
+ @text ||= ""
16
+ @size ||= 30
17
+ @font ||= "Asimov.ttf"
18
+ @color ||= [250,250,250,255]
19
+
20
+ font = resource_manager.load_font @font, @size
21
+ @text_image = font.render @text.to_s, true, @color
22
+ end
23
+ end
@@ -13,24 +13,28 @@ class ScoreView < ActorView
13
13
  end
14
14
  end
15
15
  class Score < Actor
16
+
16
17
  has_behavior :layered => {:layer => 999}
17
- attr_accessor :score
18
18
 
19
19
  def setup
20
- clear
20
+ clear if backstage[:score].nil?
21
+ end
22
+
23
+ def score
24
+ backstage[:score]
21
25
  end
22
26
 
23
27
  def clear
24
- @score = 0
28
+ backstage[:score] = 0
25
29
  end
26
30
 
27
31
  def +(amount)
28
- @score += amount
32
+ backstage[:score] += amount
29
33
  self
30
34
  end
31
35
 
32
36
  def -(amount)
33
- @score -= amount
37
+ backstage[:score] -= amount
34
38
  self
35
39
  end
36
40
  end
@@ -0,0 +1,75 @@
1
+ # this module gets mixed into a stage to allow it to handle collision detection
2
+ module Arbiter
3
+
4
+ def register_collidable(actor)
5
+ @collidable_actors ||= []
6
+ unless @collidable_actors.include? actor
7
+ actor.when :remove_me do
8
+ unregister_collidable actor
9
+ end
10
+ @collidable_actors << actor
11
+ end
12
+ end
13
+
14
+ def unregister_collidable(actor)
15
+ @collidable_actors ||= []
16
+ @collidable_actors.delete actor
17
+ end
18
+
19
+ def on_collision_of(first_objs, second_objs, &block)
20
+ first_objs = [first_objs].flatten
21
+ second_objs = [second_objs].flatten
22
+
23
+ @collision_handlers ||= {}
24
+
25
+ first_objs.each do |fobj|
26
+ second_objs.each do |sobj|
27
+ # puts "registering #{fobj} and #{sobj}"
28
+ @collision_handlers[fobj] ||= {}
29
+ @collision_handlers[fobj][sobj] = block
30
+ end
31
+ end
32
+ end
33
+
34
+ # TODO how is this going to get called?, method chaining update?
35
+ def find_collisions
36
+ collisions = []
37
+ @collidable_actors.size.times do |i|
38
+ first = @collidable_actors[i]
39
+ (@collidable_actors.size).times do |j|
40
+ second = @collidable_actors[i-j]
41
+
42
+ if collide?(first, second)
43
+ collisions << [first,second]
44
+ end
45
+ end
46
+ end
47
+
48
+ collisions.each do |collision|
49
+ first = collision.first
50
+ second = collision.last
51
+ colliders = @collision_handlers[first.actor_type]
52
+ callback = colliders[second.actor_type] unless colliders.nil?
53
+ callback.call first, second unless callback.nil?
54
+ end
55
+ end
56
+
57
+ def collide?(object, other)
58
+ self.send "collide_#{object.shape}_#{object.shape}?", object, other
59
+ end
60
+
61
+ def collide_circle_circle?(object, other)
62
+ # puts "comparing #{object.actor_type}[#{object.object_id}] to #{other.actor_type}[#{other.object_id}]"
63
+ x = object.x + object.radius
64
+ y = object.y + object.radius
65
+ x_prime = other.x + other.radius
66
+ y_prime = other.y + other.radius
67
+
68
+ x_dist = (x_prime - x) * (x_prime - x)
69
+ y_dist = (y_prime - y) * (y_prime - y)
70
+
71
+ total_radius = object.radius + other.radius
72
+ x_dist + y_dist < (total_radius) * (total_radius)
73
+ end
74
+
75
+ end
@@ -0,0 +1,17 @@
1
+ # Backstage is a place to store things across stages. It does not allow you to store Actors here.
2
+ class Backstage
3
+ def initialize
4
+ @storage = {}
5
+ end
6
+
7
+ def set(key, value)
8
+ raise "Actors cannot wander back stage!" if value.is_a? Actor
9
+ @storage[key] = value
10
+ end
11
+ alias []= set
12
+
13
+ def get(key)
14
+ @storage[key]
15
+ end
16
+ alias [] get
17
+ end
@@ -1,10 +1,16 @@
1
1
  # Behavior is any type of behavior an actor can exibit.
2
2
  class Behavior
3
- attr_accessor :actor
3
+ attr_accessor :actor, :opts
4
4
 
5
5
  def initialize(actor,opts={})
6
6
  @actor = actor
7
7
  @opts = opts
8
+ req_behs = self.class.required_behaviors
9
+ req_behs.each do |beh|
10
+ unless @actor.is? beh
11
+ @actor.is beh
12
+ end
13
+ end
8
14
  setup
9
15
  end
10
16
 
@@ -16,4 +22,21 @@ class Behavior
16
22
 
17
23
  def update(time)
18
24
  end
25
+
26
+ def self.required_behaviors
27
+ @required_behaviors ||= []
28
+ end
29
+
30
+ def self.requires_behaviors(*args)
31
+ @required_behaviors ||= []
32
+ for a in args
33
+ @required_behaviors << a
34
+ end
35
+ @behaviors
36
+ end
37
+
38
+ def self.requires_behavior(*args)
39
+ requires_behaviors(*args)
40
+ end
41
+
19
42
  end
@@ -4,6 +4,8 @@ require 'behavior'
4
4
  # by default it expects images to be:
5
5
  # data/graphics/classname/action/01..n.png
6
6
  class Animated < Behavior
7
+ requires_behavior :updatable
8
+
7
9
  attr_accessor :frame_time, :frame_num, :animating, :frame_update_time
8
10
  def setup
9
11
  @images = {}
@@ -0,0 +1,34 @@
1
+ require 'behavior'
2
+
3
+ class Audible < Behavior
4
+
5
+ def setup
6
+ @sound_manager = @actor.stage.sound_manager
7
+
8
+ audible_obj = self
9
+ @actor.instance_eval do
10
+ (class << self; self; end).class_eval do
11
+ define_method :play_sound do |*args|
12
+ audible_obj.play_sound *args
13
+ end
14
+ define_method :stop_sound do |*args|
15
+ audible_obj.stop_sound *args
16
+ end
17
+ end
18
+ end
19
+
20
+
21
+ end
22
+
23
+ # Plays a sound via the SoundManager. See SoundManager for
24
+ # details on how to "define" sounds.
25
+ def play_sound(*args)
26
+ @sound_manager.play_sound *args
27
+ end
28
+
29
+ # Stops a sound via the SoundManager.
30
+ def stop_sound(*args)
31
+ @sound_manager.stop_sound *args
32
+ end
33
+
34
+ end