gamebox 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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