class Thing < Sprite include InitializerHooks include ItIsA # TODO Move these. # it_is Imageable it_is Moveable attr_writer :layer attr_reader :window, :shape # Every thing knows the window it is attached to. # def initialize window @window = window self.destroyed = false after_initialize end # Default layer is Layer::Players. # def self.layer layer InitializerHooks.register self do self.layer = layer end end def layer @layer || Layer::Players end def mass 0.1 end def moment 0.1 end class << self @@form_shape_class_mapping = { :circle => CP::Shape::Circle, # :circle, radius :poly => CP::Shape::Poly, # :poly, CP::Vec2.new(-22, -18), CP::Vec2.new(-22, -10), etc. :segment => CP::Shape::Segment # :segment, ... # TODO :image => # Special, just traces the extent of the image. } def shape form, *args form_shape_class_mapping = @@form_shape_class_mapping define_method :radius do args.first # TODO fix! end InitializerHooks.append self do shape_class = form_shape_class_mapping[form] raise "Shape #{form} does not exist." unless shape_class params = [] params << CP::Body.new(self.mass, self.moment) params += args params << CP::Vec2.new(0.0, 0.0) @shape = shape_class.new *params end end def mass amount define_method :mass do amount end end def moment amount define_method :moment do amount end end def collision_type type to_execute = lambda do |shape| shape.collision_type = type end InitializerHooks.append self do # Ensure @shape exists # InitializerHooks.append self.class, &to_execute unless @shape to_execute[@shape] end end # Plays a random sound of the given sounds. # def plays paths, options = {} paths = [*paths] InitializerHooks.register self do sound = Gosu::Sample.new self.window, File.join(Resources.root, paths[rand(paths.size)]) sound.play options[:volume] || 1.0 end end end # Do something threaded. # # Default is: Instantly, in the next step. # def threaded time = 1, &code self.window.threaded time, &code end # Destroy this thing. # attr_writer :destroyed def destroyed? @destroyed end def destroyed! # Override end def destroy! return if self.destroyed? self.destroyed! self.window.unregister self self.destroyed = true end # Some things you can only do every x time units. # # Example: # sometimes :loading, self.frequency do # projectile = self.shot.shoot_from self # projectile.rotation = self.muzzle_rotation[target] # projectile.speed = self.muzzle_velocity[target] * projectile.velocity # end # def sometimes variable, units = 1, &block name = :"@#{variable}" return if instance_variable_get(name) instance_variable_set name, true result = block.call threaded units.to_i do self.instance_variable_set name, false end result end # Add this thing to an environment. # # Note: Adds the body and the shape. # def add_to environment environment.add_body self.shape.body # could develop into adding multiple bodies environment.add_shape self.shape end # Draws its image. # def draw self.image.draw_rot self.position.x, self.position.y, self.layer, self.drawing_rotation, 0.5, 0.5, *self.current_size end def current_size [1.0, 1.0] # default implementation - change this to [1.0, 2.0] if you want a "light" version ;) end end