Permalink
Browse files

pulled out attribute stuff from Actor; update now fires as event from…

… director
  • Loading branch information...
1 parent e2580f2 commit 82e8b51ba3a89b754607c4975c832123bcd0b4a5 @shawn42 committed Apr 2, 2012
View
@@ -1,13 +1,18 @@
# Actor represent a game object.
# Actors can have behaviors added and removed from them. Such as :physical or :animated.
# They are created and hooked up to their optional View class in Stage#create_actor.
+class Actor
+ extend Publisher
+ include EventedAttributes
+end
class Actor
include Gamebox::Extensions::Object::Yoda
- include Kvo
can_fire_anything
+ construct_with :this_object_context
+ public :this_object_context
# TODO show/hide methods? go in a behavior? base behavior ActorBehavior?
- kvo_attr_accessor :alive
+ has_attribute :alive
attr_accessor :actor_type
def initialize
@@ -31,18 +36,9 @@ def react_to(message, *opts)
end
end
- def add_attribute(name, value=nil)
- self.metaclass.send :kvo_attr_accessor, name
- self.send("#{name}=", value)
- end
-
- def has_attribute?(name)
- respond_to? name
- end
-
# Tells the actor's Director that he wants to be removed; and unsubscribes
# the actor from all input events.
- def remove_self
+ def remove
self.alive = false
fire :remove_me
end
@@ -102,14 +98,6 @@ def initialize
@behaviors = {}
end
- # Tells the actor's Director that he wants to be removed; and unsubscribes
- # the actor from all input events.
- def remove_self
- self.alive = false
- fire :remove_me
- input_manager.unsubscribe_all self
- end
-
# Does this actor have this behavior?
def is?(behavior_sym)
!@behaviors[behavior_sym].nil?
@@ -25,7 +25,7 @@ def build(actor, stage, opts={})
beh_key = behavior.keys.first
end
- model.add_behavior beh_key, behavior_factory.add_behavior(actor_context, model, beh_key, beh_opts)
+ model.add_behavior beh_key, behavior_factory.add_behavior(model, beh_key, beh_opts)
end
model.configure(merged_opts)
View
@@ -10,7 +10,15 @@ def configure(opts={})
def setup
end
+ def reacts_with(*messages_with_methods)
+ @message_handlers = messages_with_methods
+ end
+
def react_to(message_type, *opts)
+ # TODO perf analysis, should I use a hash here?
+ if @message_handlers && @message_handlers.include?(message_type)
+ send message_type, *opts
+ end
end
def required_behaviors
@@ -9,16 +9,16 @@ class BehaviorFactory
# add_behavior(:shootable) or add_behavior(:shootable => {:range=>3})
# this will create a new instance of Shootable and pass
# :range=>3 to it
- def add_behavior(object_context, actor, behavior, opts = {})
+ def add_behavior(actor, behavior, opts = {})
raise "nil actor" if actor.nil?
raise "nil behavior definition" if behavior.nil?
- object_context[behavior].tap do |behavior|
+ actor.this_object_context[behavior].tap do |behavior|
deps = behavior.required_behaviors
deps.each do |beh|
add_behavior actor, beh unless @actor.is? beh
end
- behavior.configure(actor, opts)
+ behavior.configure(opts)
end
end
@@ -4,38 +4,32 @@
# by default it expects images to be:
# data/graphics/classname/action/01..n.png
class Animated < Behavior
- # TODO uh oh.. inheritance again!! maybe remove the base class all together?
- construct_with :actor, :resource_manager
+ construct_with :actor, :resource_manager, :director
attr_accessor :frame_time, :frame_num, :animating, :frame_update_time
def setup
@images = {}
@frame_update_time = @opts[:frame_update_time]
@frame_update_time ||= 60
@frame_time = 0
-
+
# all animated actors have to have an idle animation
# data/graphics/ship/idle/1.png
@frame_num = 0
- self.action = :idle
-
- relegates :image, :width, :height,
- :start_animating, :stop_animating, :animated,
- :action, :action=
-
- end
- def animated
- self
- end
+ actor.has_attributes :action, :image, :width, :height
+ actor.action = :idle
+ actor.when :action_changed do |old_action, new_action|
+ action_changed old_action, new_action
+ end
- def width
- image.width
- end
+ # TODO use director
+ director.when :update do |time|
+ update time
+ end
- def height
- image.height
- end
+ reacts_with :start_animating, :stop_animating
+ end
def update(time)
return unless @animating
@@ -44,6 +38,7 @@ def update(time)
next_frame
@frame_time = @frame_time-@frame_update_time
end
+ set_image
end
def next_frame()
@@ -52,14 +47,10 @@ def next_frame()
# load all the images for this action
def load_action(action)
- @actor.resource_manager.load_animation_set @actor, action
- end
-
- def action
- @action
+ resource_manager.load_animation_set @actor, action
end
- def action=(new_action)
+ def action_changed(old_action, new_action)
@images[new_action] ||= load_action(new_action)
if @images[new_action].size > 1
start_animating
@@ -68,11 +59,13 @@ def action=(new_action)
end
@frame_num = 0
@action = new_action
+ set_image
end
- # returns the current image, or nil if no action is defined
- def image
- @images[@action][@frame_num]
+ def set_image
+ actor.image = @images[@action][@frame_num]
+ actor.width = image.width
+ actor.height = image.height
end
def start_animating
View
@@ -49,8 +49,9 @@ def update(time)
fire :actor_removed, act
end
@dead_actors = []
- for act in @actors
- act.update time if act.alive?
- end
+ fire :update, time
+ # for act in @actors
+ # act.update time if act.alive?
+ # end
end
end
@@ -0,0 +1,31 @@
+module EventedAttributes
+
+ def has_attributes(*names)
+ # TODO make this take a hash or an array
+ names.each do |name|
+ has_attribute name
+ end
+ end
+
+ def has_attribute(name, value=nil)
+ unless has_attribute? name
+ self.metaclass.send :kvo_attr_accessor, name
+ self.send("#{name}=", value)
+ end
+ end
+
+ def has_attribute?(name)
+ respond_to? name
+ end
+
+ def self.included(klass)
+ klass.instance_eval do
+ include Kvo
+ def has_attribute(name)
+ kvo_attr_accessor name
+ end
+ end
+
+ end
+
+end
@@ -13,9 +13,9 @@ def inject_mocks(*mock_names_array)
module InstanceMethods
def create_actor(type=:actor, args={})
- Actor.new.tap do |act|
- act.configure args.merge(actor_type: type)
- end
+ act = create_conjected_object type, nil, false
+ act.configure args.merge(actor_type: type)
+ act
end
def create_conjected_object(type, args={}, configure=true)
@@ -14,22 +14,20 @@
let(:gosu) { MockGosuWindow.new }
class Shooty < Behavior
- construct_with :wrapped_screen
- attr_accessor :bullets
+ construct_with :actor, :director
def setup
- relegates :bullets
- @bullets = opts[:bullets]
- wrapped_screen.screen.when :update do |time|
- @bullets -= time
+ actor.has_attribute :bullets, opts[:bullets]
+ director.when :update do |time|
+ actor.bullets -= time
end
end
end
class DeathOnD < Behavior
- construct_with :input_manager
+ construct_with :actor, :input_manager
def setup
input_manager.reg :up, KbD do
- @actor.remove_self
+ actor.remove
end
end
end
View
@@ -1,9 +1,7 @@
require File.join(File.dirname(__FILE__),'helper')
describe Actor do
- before do
- subject.configure actor_type: :actor
- end
+ subject { create_actor :actor }
it 'should be alive' do
subject.alive.should be_true
@@ -36,7 +34,7 @@
it 'can add a behavior to the actors list of behaviors'
end
- describe "#add_attribute" do
+ describe "#has_attribute" do
it 'adds an evented attribute'
end
View
@@ -16,8 +16,8 @@
end
it 'should accept layered behavior params from actor' do
- actor.add_attribute :layer, 6
- actor.add_attribute :parallax, 3
+ actor.has_attribute :layer, 6
+ actor.has_attribute :parallax, 3
subject.layer.should == 6
subject.parallax.should == 3
View
@@ -1,25 +1,31 @@
require File.join(File.dirname(__FILE__),'helper')
-describe 'A new animated behavior' do
- subject { create_conjected_object :animated, actor }
+describe Animated do
+ subject {
+ mocks = create_mocks *Animated.object_definition.component_names
+ mocks[:actor] = actor
+ Animated.new(mocks).configure
+ }
let(:actor) { create_actor }
before do
+ @director.stubs(:when)
@rm = stub(:load_animation_set => ['1.png_img_obj','2.png_img_obj'])
- @actor = create_actor
- @actor.expects(:is?).with(:updatable).returns(true)
- @actor.stubs(:resource_manager).returns(@rm)
+ actor.stubs(:resource_manager).returns(@rm)
end
- it 'should define methods on actor' do
- @actor.respond_to?(:image).should be(true)
- @actor.respond_to?(:start_animating).should be(true)
- @actor.respond_to?(:stop_animating).should be(true)
- @actor.respond_to?(:action=).should be(true)
- @actor.respond_to?(:animated).should be(true)
+ it 'should define attributes on actor' do
+ subject
+ actor.has_attribute?(:image).should be_true
+ actor.has_attribute?(:action).should be_true
+ actor.has_attribute?(:width).should be_true
+ actor.has_attribute?(:height).should be_true
+ actor.has_attribute?(:image=).should be_true
+ actor.has_attribute?(:action=).should be_true
+ actor.has_attribute?(:height=).should be_true
end
- it 'shouldn\'t update frame for non-animating' do
+ it 'shouldnt update frame for non-animating' do
subject.stop_animating
subject.update subject.frame_update_time+1
@@ -56,30 +62,29 @@
subject.start_animating
subject.animating.should equal(true)
end
-
+
it 'should return itself for animated' do
subject.animated.should == subject
end
it 'should set the action and animate accordingly for single frame' do
subject.animating = true
- @rm.expects(:load_animation_set).with(@actor, :foo).returns([:frame_one])
+ @rm.expects(:load_animation_set).with(actor, :foo).returns([:frame_one])
subject.action = :foo
-
+
subject.animating.should be_false
subject.frame_num.should == 0
subject.action.should == :foo
end
it 'should set the action and animate accordingly for many frames' do
subject.animating = false
- @rm.expects(:load_animation_set).with(@actor, :foo).returns([:frame_one, :frame_two])
+ @rm.expects(:load_animation_set).with(actor, :foo).returns([:frame_one, :frame_two])
subject.action = :foo
-
+
subject.animating.should be_true
subject.frame_num.should == 0
subject.action.should == :foo
end
-
end
Oops, something went wrong.

0 comments on commit 82e8b51

Please sign in to comment.