Skip to content
Browse files

big trait-overhaul/refactor, may break your code. replace your has_tr…

…ait with has_traits. the first now works as has_trait :trait, {options}. rewrote traits :bounding_box and :radius, partly to use the new format (try has_trait :bounding_box, :scale => 0.80, :debug => true), see updated readme for more info. shawn24 contributed an elite draw_circle(x,y,radius,color). Examples updated, game1 still in flux.
  • Loading branch information...
1 parent 3626ef7 commit 8740bdecdfbcd270fb21d9177ee57acf39187b6c @ippa committed Nov 20, 2009
View
30 README.rdoc
@@ -66,7 +66,7 @@ For example, inside game state Menu you call push_game_state(Level). When Level
Traits are extensions (or plugins if you so will) to BasicGameObjects.
The aim is so encapsulate common behaivor into modules for easy inclusion in your game classes.
Making a trait is easy, just an ordinary module with the methods setup_trait(), update_trait() and/or draw_trait().
-It currently has to be namespaced to Chingu::Traits for "has_trait" to work inside GameObject-classes.
+It currently has to be namespaced to Chingu::Traits for "has_traits" to work inside GameObject-classes.
== OTHER CLASSES / HELPERS
@@ -454,7 +454,7 @@ Each of those 3 methods must call "super" to continue the trait-chain.
Example:
class Ogre < Chingu::GameObject
- has_trait :velocity, :timer
+ has_traits :velocity, :timer
def initialize(options)
super
@@ -481,7 +481,10 @@ Example:
The flow for a game object then becomes:
- -- creating the object
+ -- creating a GameObject class X ( with a "has_trait :bounding_box, :scale => 0.80" )
+ 1) trait gets merged into X, instance and class methods are added
+ 2) GameObject.initialize_trait(:scale => 0.80)
+ -- creating an instance of X
1) GameObject#initialize(options)
2) GameObject#setup_trait(options)
-- each game iteration
@@ -503,6 +506,20 @@ Adds timer functionality to your game object
Adds accessors velocity_x, velocity_y, acceleration_x, acceleration_y, max_velocity to game object.
They modify x, y as you would expect. *speed / angle will come*
+==== Trait "bounding_box"
+Adds accessor 'bounding_box', which returns a Rect based on current image size,x,y,factor_x,factor_y,center_x,center_y
+You can also scale the calculated rect with has_trait-options:
+
+ # This would return a rect slightly smaller then the image.
+ # Make player think he's better @ dodging bullets then he really is ;)
+ has_trait :bounding_box, :scale => 0.80
+
+==== Trait "radius"
+Adds accessor 'radius', which returns a Fixnum based on current image size,factor_x and factor_y
+You can also scale the calculated radius with has_trait-options:
+
+ # This would return a radius slightly bigger then what initialize was calculated
+ has_trait :radius, :scale => 1.10
==== Trait "effect"
Adds accessors rotation_rate, fade_rate and scale_rate to game object.
@@ -651,3 +668,10 @@ As far as possible, use correct rubyfied english game_objects, not gameobjects.
* gem 'texplay' for some bonus Image-pixel operations, not needed otherwise
+
+
+
+ "If you program and want any longevity to your work, make a game.
+ All else recycles, but people rewrite architectures to keep games alive.", _why
+
+
View
BIN chingu-0.5.9.7.gem
Binary file not shown.
View
12 examples/example11.rb
@@ -15,12 +15,12 @@ def initialize
@factor = 6
self.input = { :escape => :exit }
self.caption = "Chingu::Animation / retrofy example. Move with arrows!"
- Droid.create(:x => $window.width/@factor/2, :y => $window.height/@factor/2)
+ Droid.create(:x => $window.width/2, :y => $window.height/2)
end
end
class Droid < Chingu::GameObject
- has_trait :retrofy # modifies draw(),
+ has_traits :timer
def initialize(options = {})
super
@@ -50,22 +50,22 @@ def initialize(options = {})
end
def left
- @x -= 1
+ @x -= 2
@animation = @animations[:left]
end
def right
- @x += 1
+ @x += 2
@animation = @animations[:right]
end
def up
- @y -= 1
+ @y -= 2
@animation = @animations[:up]
end
def down
- @y += 1
+ @y += 2
@animation = @animations[:down]
end
View
2 examples/example13.rb
@@ -90,7 +90,7 @@ def create_text
# colorful pulsating text...
#
class PulsatingText < Text
- has_trait :timer, :effect
+ has_traits :timer, :effect
@@red = Color.new(0xFFFF0000)
@@green = Color.new(0xFF00FF00)
@@blue = Color.new(0xFF0000FF)
View
124 examples/example14.rb
@@ -0,0 +1,124 @@
+require 'rubygems'
+require File.join(File.dirname($0), "..", "lib", "chingu")
+include Gosu
+include Chingu
+
+#
+# Demonstrating Chingus HighScoreList-class
+# I couldn't keep myself from spicying it up some though :P
+#
+class Game < Chingu::Window
+ def initialize
+ super(640,400)
+ self.input = {:esc => :exit, :space => :remote_high_score, :a => :add}
+ self.caption = "Example of Chingus HighScore class. Press Space to go to fetch high scores remotely!"
+
+ @title = PulsatingText.create("HIGH SCORES", :x => $window.width/2, :y => 50, :size => 70)
+
+ #
+ # Load a list from disk, defaults to "high_score_list.yml"
+ # Argument :size forces list to this size
+ #
+ @high_score_list = HighScoreList.load(:size => 10)
+
+ #
+ # Add some new high scores to the list. :name and :score are required but you can put whatever.
+ # They will mix with the old scores, automatic default sorting on :score
+ #
+ 10.times do
+ data = {:name => "NEW", :score => rand(10000)}
+
+ position = @high_score_list.add(data)
+ if position
+ puts "#{data[:name]} - #{data[:score]} got position #{position}"
+ else
+ puts "#{data[:name]} - #{data[:score]} didn't make it"
+ end
+ end
+
+ create_text
+
+ # @high_score_list.save_to_file # Uncomment to save list to disk
+ end
+
+ def remote_high_score
+ game_objects.destroy_all
+
+ @title = PulsatingText.create("REMOTE WEBSERVICE HIGH SCORES", :x => $window.width/2, :y => 50, :size => 30)
+
+ #
+ # :game_id is the unique ID the game has on www.gamercv.com
+ # :user is the login for that specific game (set by owner)
+ # :password is the password for that specific game (set by owner)
+ #
+ # To read a high score list only :game_id is required
+ # To write to a high score list :user and :password is required as well
+ #
+ @high_score_list = HighScoreList.load_remote(:game_id => 1, :user => "chingu", :password => "chingu", :size => 10)
+ create_text
+ end
+
+ def add
+ data = {:name => "NEW", :score => 1600}
+ position = @high_score_list.add(data)
+ puts "Got position: #{position.to_s}"
+ create_text
+ end
+
+ def create_text
+ @score_texts ||= []
+ @score_texts.each { |text| text.destroy }
+
+ #
+ # Iterate through all high scores and create the visual represenation of it
+ #
+ @high_score_list.each_with_index do |high_score, index|
+ y = index * 25 + 100
+ @score_texts << Text.create(high_score[:name], :x => 200, :y => y, :size => 20)
+ @score_texts << Text.create(high_score[:score], :x => 400, :y => y, :size => 20)
+ end
+
+ 5.times do
+ score = rand(20000)
+ puts "position for possible score #{score}: #{@high_score_list.position_by_score(score)}"
+ end
+ end
+
+end
+
+#
+# colorful pulsating text...
+#
+class PulsatingText < Text
+ has_traits :timer, :effect
+ @@red = Color.new(0xFFFF0000)
+ @@green = Color.new(0xFF00FF00)
+ @@blue = Color.new(0xFF0000FF)
+
+ def initialize(text, options = {})
+ super(text, options)
+
+ options = text if text.is_a? Hash
+ @pulse = options[:pulse] || false
+ self.rotation_center(:center_center)
+ every(20) { create_pulse } if @pulse == false
+ end
+
+ def create_pulse
+ pulse = PulsatingText.create(@text, :x => @x, :y => @y, :height => @height, :pulse => true, :image => @image, :zorder => @zorder+1)
+ colors = [@@red, @@green, @@blue]
+ pulse.color = colors[rand(colors.size)].dup
+ pulse.mode = :additive
+ pulse.alpha -= 150
+ pulse.scale_rate = 0.002
+ pulse.fade_rate = -3 + rand(2)
+ pulse.rotation_rate = rand(2)==0 ? 0.05 : -0.05
+ end
+
+ def update
+ destroy if self.alpha == 0
+ end
+
+end
+
+Game.new.show
View
18 examples/example9.rb
@@ -18,14 +18,7 @@ def next_effect; pop_game_state; end
end
class FireCube < Chingu::GameObject
- has_trait :velocity
- has_trait :collision_detection
- #
- # TODO:
- # has_trait :collision_detection, :type => :bounding_box
- # has_trait :collision_detection, :type => :radius
- #
-
+ has_traits :velocity, :collision_detection
attr_accessor :color, :radius
def initialize(options)
@@ -36,7 +29,7 @@ def initialize(options)
@velocity_x = options[:velocity_x] || 1 + rand(2)
@velocity_y = options[:velocity_y] || 1 + rand(2)
- @bounding_box = Rect.new([@x, @y, 10, 10])
+ @box = Rect.new([@x, @y, 10, 10])
@radius = 6
@blue = Color.new(255,100,255,255)
@@ -45,17 +38,14 @@ def initialize(options)
end
def draw
- $window.fill_rect(@bounding_box, @color)
+ $window.fill_rect(@box, @color)
end
def update
+ @box.x, @box.y = @x, @y
@color = @blue
end
- def collides?(object2)
- radius_collision?(object2)
- end
-
def die!
@color = @red
end
View
163 examples/game1.rb
@@ -9,7 +9,6 @@
require File.join(File.dirname($0), "..", "lib", "chingu")
require 'texplay' # adds Image#get_pixel
-#require 'devil/gosu' # adds Gosu::Window#screenshot and better file support
require 'opengl' # adds raw gl stuff so Image#retrofy works (in some setups this seems to be 'gl')
include Gosu
@@ -26,59 +25,22 @@ def initialize
end
end
-#
-# GAME STATE: GAME OVER
-#
-class GameOver < Chingu::GameState
- def setup
- @text = Text.create(:text => "GAME OVER (ESC to quit, RETURN to try again!)", :size => 40, :x => 30, :y => 100)
- self.input = { :esc => :exit, :return => :try_again}
- @layover = Color.new(0x99000000)
- end
-
- def draw
- super
- previous_game_state.draw
- fill(@layover)
- end
-
- def try_again
- pop_game_state # pop back to our playing game state
- end
-end
-
-#
-# GAME STATE: GAME OVER
-#
-class Done < Chingu::GameState
- def initialize(options)
- @score = options[:score]
- end
-
- def setup
- @text = Text.create(:text => "You made it! Score #{@score} (ESC to quit, RETURN to try again!)", :size => 40, :x => 30, :y => 100)
- self.input = { :esc => :exit, :return => :try_again}
- end
-
- def try_again
- pop_game_state # pop back to our playing game state
- end
-end
-
#
# GAME STATE: LEVEL
#
class Level < Chingu::GameState
+ has_trait :timer
+
def initialize(options = {})
super
@parallax = Parallax.create
- ParallaxLayer.has_trait :retrofy
+ #ParallaxLayer.has_trait :retrofy
#@parallax << ParallaxLayer.new(:image => Image["city3.png"].retrofy, :center => 0, :damping => 4, :factor => $window.factor)
@parallax << ParallaxLayer.new(:image => Image["city2.png"].retrofy, :center => 0, :damping => 2, :factor => $window.factor)
@parallax << ParallaxLayer.new(:image => Image["city1.png"].retrofy, :center => 0, :damping => 1, :factor => $window.factor)
- @player = Player.create(:x => 10, :y => 100)
+ @player = Player.create(:x => 10, :y => 10)
@bg1 = Color.new(0xFFCE28FF)
@bg2 = Color.new(0xFF013E87)
@@ -88,7 +50,7 @@ def initialize(options = {})
# This is called each time this GameState is switched/pushed/poped to.
#
def setup
- # Remove all lingering g
+ # Remove all lingering game objects
Enemy.destroy_all
Bullet.destroy_all
@@ -107,7 +69,11 @@ def setup
#
def solid_pixel_at?(x, y)
begin
- @parallax.layers.last.get_pixel(x, y)[3] != 0
+ #pixel = @parallax.layers.last.get_pixel(x/$window.factor, y/$window.factor)
+ #return false if pixel.nil?
+ #return
+
+ @parallax.layers.last.get_pixel(x/$window.factor, y/$window.factor)[3] != 0
rescue
puts "Error in get_pixel(#{x}, #{y})"
end
@@ -145,13 +111,13 @@ def update
@timer = @timer * 0.9999
@total_ticks += 1
if @total_ticks > @timer
- Enemy.create(:x => $window.width/2, :y => rand(300))
+ Enemy.create(:x => $window.width, :y => rand(300))
@total_ticks = 0
end
#push_game_state(Done.new(:score => @player.score)) if @game_steps == 1
- $window.caption = "City Battle! Score: #{@player.score} .... FPS: #{$window.fps} ... game objects: #{game_objects.size}"
+ $window.caption = "City Battle! Player x/y: #{@player.x}/#{@player.y} - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
end
def draw
@@ -164,7 +130,9 @@ def draw
# OUR PLAYER
#
class Player < GameObject
- has_trait :velocity, :collision_detection, :retrofy, :timer
+ has_traits :velocity, :collision_detection, :timer
+ has_trait :radius, :scale => 0.50, :debug => true
+
attr_accessor :score
def initialize(options = {})
@@ -179,40 +147,39 @@ def initialize(options = {})
:holding_down => :down,
:holding_space => :fire }
- @max_velocity = 1
- @radius = 10
+ @max_velocity = 2
@score = 0
@cooling_down = false
end
def up
- @velocity_y += -@max_velocity
+ self.velocity_y = -@max_velocity
end
def down
- @velocity_y += @max_velocity
+ self.velocity_y = @max_velocity
end
def right
- @velocity_x += @max_velocity
+ self.velocity_x = @max_velocity
end
def left
- @velocity_x -= @max_velocity
+ self.velocity_x = -@max_velocity
end
def fire
return if @cooling_down
@cooling_down = true
- after(100) { @cooling_down = false}
+ after(100) { @cooling_down = false }
Bullet.create(:x => self.x, :y => self.y)
Sound["laser.wav"].play(0.1)
end
def update
- @velocity_y *= 0.6
- @velocity_x *= 0.6
+ self.velocity_y *= 0.6
+ self.velocity_x *= 0.6
- @x = @last_x if @x < 0 || @x > $window.width/$window.factor
- @y = @last_y if @y < 0 || @y > $window.height/$window.factor
+ @x = @last_x if @x < 0 || @x > $window.width#/$window.factor
+ @y = @last_y if @y < 0 || @y > $window.height#/$window.factor
@last_x, @last_y = @x, @y
end
@@ -222,14 +189,14 @@ def update
# OUR PLAYERS BULLETS
#
class Bullet < GameObject
- has_trait :retrofy, :timer, :collision_detection
- attr_reader :status
+ has_traits :timer, :collision_detection, :velocity
+ attr_reader :status, :radius
def initialize(options)
super
@image = Image["bullet.png"].retrofy
self.factor = $window.factor
- @velocity_x = 10
+ self.velocity_x = 10
@status = :default
@radius = 3
end
@@ -241,10 +208,10 @@ def die
during(50) { @factor_x += 1; @factor_y += 1; @x -= 1; }.then { self.destroy }
end
- def update
- return if @status == :dying
- @x += @velocity_x
- end
+ #def update
+ #return if @status == :dying
+ #@x += self.velocity_x
+ #end
end
#
@@ -254,12 +221,12 @@ class EnemyBullet < Bullet
def initialize(options)
super
@image = Image["enemy_bullet.png"].retrofy
- @velocity_x = -3
+ self.velocity_x = -3
end
end
class Explosion < GameObject
- has_trait :timer,:retrofy
+ has_traits :timer
def initialize(options)
super
@@ -271,8 +238,7 @@ def initialize(options)
@image = @@image.dup if @image.nil?
-
- self.rotation_center(:center)
+ self.rotation_center = :center
self.factor = options[:factor] ? options[:factor] : $window.factor
during(100) { self.alpha -= 30}.then { destroy }
end
@@ -287,7 +253,7 @@ def self.create_image_for(object)
end
class Shrapnel < GameObject
- has_trait :retrofy, :timer, :effect, :velocity
+ has_traits :timer, :effect, :velocity
def initialize(options)
super
@@ -296,8 +262,7 @@ def initialize(options)
self.velocity_x = 4 - rand(8)
self.velocity_y = 4 - rand(10)
self.acceleration_y = 0.2 # gravity = downards acceleration
-
- rotation_center(:center)
+ self.rotation_center = :center
self.factor = $window.factor
@status = :default
end
@@ -325,15 +290,16 @@ def die
# OUR ENEMY SAUCER
#
class Enemy < GameObject
- has_trait :collision_detection, :retrofy, :timer
+ has_traits :collision_detection, :timer
+ attr_reader :radius
def initialize(options)
super
@velocity = options[:velocity] || 2
@health = options[:health] || 100
- @anim = Animation.new(:file => "media/saucer.png", :size => [32,13], :delay => 100)
- @anim.retrofy
+ @anim = Animation.new(:file => "media/saucer.png", :size => [32,13], :delay => 100).retrofy
+ # @anim.retrofy
@image = @anim.first
self.factor = $window.factor
@@ -403,4 +369,49 @@ def update
end
end
-Game.new.show
+
+#
+# GAME STATE: GAME OVER
+#
+class GameOver < Chingu::GameState
+ def setup
+ @text = Text.create("GAME OVER (ESC to quit, RETURN to try again!)", :size => 40, :x => 30, :y => 100)
+ self.input = { :esc => :exit, :return => :try_again }
+ @layover = Color.new(0x99000000)
+ end
+
+ def draw
+ super
+ previous_game_state.draw
+ fill(@layover)
+ end
+
+ def try_again
+ pop_game_state # pop back to our playing game state
+ end
+end
+
+#
+# GAME STATE: GAME OVER
+#
+class Done < Chingu::GameState
+ def initialize(options)
+ @score = options[:score]
+ end
+
+ def setup
+ @text = Text.create("You made it! Score #{@score} (ESC to quit, RETURN to try again!)", :size => 40, :x => 30, :y => 100)
+ self.input = { :esc => :exit, :return => :try_again}
+ end
+
+ def try_again
+ pop_game_state # pop back to our playing game state
+ end
+end
+
+
+Game.new.show
+
+
+
+
View
4 examples/high_score_list.yml
@@ -1,5 +1,7 @@
---
- :name: NEW
+ :score: 9987
+- :name: NEW
:score: 9971
- :name: NEW
:score: 9960
@@ -19,5 +21,3 @@
:score: 9742
- :name: NEW
:score: 9736
-- :name: NEW
- :score: 9706
View
3 lib/chingu.rb
@@ -29,4 +29,7 @@
module Chingu
VERSION = "0.5.9.7"
+
+ DEBUG_COLOR = Gosu::Color.new(0xFFFF0000)
+ DEBUG_ZORDER = 9999
end
View
57 lib/chingu/basic_game_object.rb
@@ -8,22 +8,38 @@ module Chingu
class BasicGameObject
attr_reader :options, :paused, :visible
attr_accessor :parent
-
+
+ def self.trait_options; @trait_options; end
+ def trait_options; self.class.trait_options; end
+
#
# Adds a trait or traits to a certain game class
# Executes a standard ruby "include" the specified module
#
- def self.has_trait(*traits)
- has_traits(*traits)
+ def self.has_trait(trait, options = {})
+ @trait_options ||= Hash.new
+ if trait.is_a?(::Symbol) || trait.is_a?(::String)
+ begin
+ # Convert user-given symbol (eg. :timer) to a Module (eg. Chingu::Traits::Timer)
+ mod = Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
+
+ # Include the module, which will add the containing methods as instance methods
+ include mod
+
+ # Add possible classmethods defined in sub-module ClassMethods (eg: Chingu::Traits::Timer::ClassMethods)
+ mod2 = mod.const_get("ClassMethods")
+ extend mod2
+
+ # If the newly included trait has a initialize_trait method...
+ # ... call it with the options provided with the has_trait-call
+ initialize_trait(options) if mod2.method_defined?(:initialize_trait)
+ rescue
+ end
+ end
end
- # See #has_trait
def self.has_traits(*traits)
- Array(traits).each do |trait|
- if trait.is_a?(::Symbol) || trait.is_a?(::String)
- include Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
- end
- end
+ Array(traits).each { |trait| has_trait trait }
end
#
@@ -122,20 +138,15 @@ def visible?
@visible == true
end
- def setup_trait(options)
- end
-
- def update_trait
- end
-
- def draw_trait
- end
-
- def update
- end
-
- def draw
- end
+ #
+ # Empty placeholders to be overridden
+ #
+ def self.initialize_trait(options); end
+ def setup_trait(options); end
+ def update_trait; end
+ def draw_trait; end
+ def update; end
+ def draw; end
#
View
32 lib/chingu/game_state.rb
@@ -58,21 +58,37 @@ class GameState
attr_reader :options
attr_accessor :game_state_manager, :game_objects
+ def self.trait_options; @trait_options; end
+ def trait_options; self.class.trait_options; end
+
#
# Adds a trait or traits to a certain game class
# Executes a standard ruby "include" the specified module
#
- def self.has_trait(*traits)
- has_traits(*traits)
+ def self.has_trait(trait, options = {})
+ @trait_options ||= Hash.new
+ if trait.is_a?(::Symbol) || trait.is_a?(::String)
+ begin
+ # Convert user-given symbol (eg. :timer) to a Module (eg. Chingu::Traits::Timer)
+ mod = Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
+
+ # Include the module, which will add the containing methods as instance methods
+ include mod
+
+ # Add possible classmethods defined in sub-module ClassMethods (eg: Chingu::Traits::Timer::ClassMethods)
+ mod2 = mod.const_get("ClassMethods")
+ extend mod2
+
+ # If the newly included trait has a initialize_trait method...
+ # ... call it with the options provided with the has_trait-call
+ initialize_trait(options) if mod2.method_defined?(:initialize_trait)
+ rescue
+ end
+ end
end
- # See #has_trait
def self.has_traits(*traits)
- Array(traits).each do |trait|
- if trait.is_a?(::Symbol) || trait.is_a?(::String)
- include Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
- end
- end
+ Array(traits).each { |trait| has_trait trait }
end
View
14 lib/chingu/helpers/gfx.rb
@@ -98,7 +98,7 @@ def fill(options, zorder = 99)
end
#
- # Draws a unfilled rect in given color
+ # Draws an unfilled rect in given color
#
def draw_rect(rect, color, zorder)
$window.draw_line(rect.x, rect.y, color, rect.right, rect.y, color, zorder)
@@ -107,6 +107,18 @@ def draw_rect(rect, color, zorder)
$window.draw_line(rect.x, rect.bottom, color, rect.x, rect.y, color, zorder)
end
+
+ #
+ # Draws an unfilled circle, thanks shawn24!
+ #
+ CIRCLE_STEP = 10
+ def draw_circle(cx,cy,r,color)
+ 0.step(360, CIRCLE_STEP) do |a1|
+ a2 = a1 + CIRCLE_STEP
+ $window.draw_line cx + offset_x(a1, r), cy + offset_y(a1, r), color, cx + offset_x(a2, r), cy + offset_y(a2, r), color, 9999
+ end
+ end
+
#
# Fills a given Rect 'rect' with Color 'color', drawing with zorder 'zorder'
#
View
56 lib/chingu/traits/bounding_box.rb
@@ -22,44 +22,42 @@
module Chingu
module Traits
#
- # Providing a bounding_box and keeps it up to date by reading:
+ # Providing a bounding_box-method which generates a AABB on the fly from:
# x, y, factor_x, factor_y and rotation_center
#
module BoundingBox
- attr_accessor :bounding_box
-
- def setup_trait(options)
- @bounding_box_options = {:debug => false}.merge(options)
- @bounding_box ||= Rect.new(self.x, self.y, 1, 1)
- super
- end
-
- def BB
- @bounding_box
+
+ module ClassMethods
+ def initialize_trait(options = {})
+ ## puts "bounding_box initialize_trait #{options}"
+ @trait_options[:bounding_box] = options
+ end
end
-
- def BB=(rect)
- @bounding_box = rect
+
+ def bounding_box
+ width = self.image.width * self.factor_x.abs
+ height = self.image.height * self.factor_y.abs
+
+ if trait_options[:bounding_box][:scale]
+ width = width * trait_options[:bounding_box][:scale]
+ height = height * trait_options[:bounding_box][:scale]
+ end
+
+ x = self.x - (width * self.center_x.abs)
+ y = self.y - (height * self.center_y.abs)
+
+ return Rect.new(x, y, width, height)
end
+ alias :bb :bounding_box
- #
- # Keep bounding_box up 2 date with how the image looks on the screen
- #
- def update_trait
- if self.image
- # Addapt width / height to scaling
- real_width = self.image.width * self.factor_x.abs
- real_height = self.image.height * self.factor_y.abs
-
- self.bounding_box.x = self.x - (real_width * self.center_x.abs)
- self.bounding_box.y = self.y - (real_height * self.center_y.abs)
-
- self.bounding_box.width = real_width
- self.bounding_box.height = real_height
+ def draw_trait
+ if trait_options[:bounding_box][:debug]
+ $window.draw_rect(self.bounding_box, Chingu::DEBUG_COLOR, Chingu::DEBUG_ZORDER)
end
super
- end
+ end
+
end
end
end
View
35 lib/chingu/traits/collision_detection.rb
@@ -28,33 +28,16 @@ module Traits
#
# SEE: http://www.shmup-dev.com/forum/index.php?board=65.0
#
- # Makes use of 3 attributes
- # @bounding_box - a Rect-instance, uses in bounding_box collisions
- # @radius -
- # @detect_collisions - [true|false], should object be checked for collisions with Object.each_collision
+ # Makes use of 2 attributes
+ # bounding_box - a Rect-instance, uses in bounding_box collisions
+ # radius - a number
#
module CollisionDetection
- attr_accessor :bounding_box, :radius
- ## attr_accessor :detect_collisions # slowed down example9 with 3 fps
- def self.included(base)
- base.extend(ClassMethods)
- end
-
- #
- # Automaticly try to set a bounding_box and radius. Don't overwrite if they already exists.
- #
- def setup_trait(options)
- if @x and @y and @image
- @bounding_box ||= Rect.new(@x, @y, @image.width, @image.height)
- end
-
- if @image
- @radius ||= (@image.height + @image.width) / 2 * 0.80
+ module ClassMethods
+ def initialize_trait(options = {})
+ @trait_options[:collision_detection] = options
end
-
- ## @detect_collisions = true
- super
end
#
@@ -102,27 +85,25 @@ def each_collision(klasses = [])
def each_radius_collision(klasses = [])
Array(klasses).each do |klass|
klass.all.each do |object|
- yield(self, object) if distance(@x, @y, object.x, object.y) < @radius + object.radius
+ yield(self, object) if distance(self.x, self.y, object.x, object.y) < self.radius + object.radius
end
end
end
-
#
# Explicit bounding_box-collision
# Works like each_collision but with inline-code for speedups
#
def each_bounding_box_collision(klasses = [])
Array(klasses).each do |klass|
klass.all.each do |object|
- yield(self, object) if @bounding_box.collide_rect?(object.bounding_box)
+ yield(self, object) if self.bounding_box.collide_rect?(object.bounding_box)
end
end
end
module ClassMethods
-
#
# Works like each_collision but with inline-code for speedups
#
View
11 lib/chingu/traits/effect.rb
@@ -42,14 +42,11 @@ module Traits
module Effect
attr_accessor :rotation_rate, :fade_rate, :scale_rate
-
+
#
# Setup
#
- def setup_trait(options)
- @effect_options = {:debug => false}.merge(options)
- puts "Effect#setup" if @effect_options[:debug]
-
+ def setup_trait(options)
@rotation_rate = options[:rotation_rate] || nil
@scale_rate = options[:scale_rate] || nil
@fade_rate = options[:fade_rate] || nil
@@ -60,9 +57,7 @@ def draw_trait
super
end
- def update_trait
- puts "Effect#update" if @effect_options[:debug]
-
+ def update_trait
rotate(@rotation_rate) if @rotation_rate
fade(@fade_rate) if @fade_rate
scale(@scale_rate) if @scale_rate
View
55 lib/chingu/traits/radius.rb
@@ -0,0 +1,55 @@
+#--
+#
+# Chingu -- OpenGL accelerated 2D game framework for Ruby
+# Copyright (C) 2009 ippa / ippa@rubylicio.us
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#++
+
+module Chingu
+ module Traits
+ #
+ # Providing a bounding_box and keeps it up to date by reading:
+ # image, factor_x, factor_y
+ #
+ # ...only makes sense with rotation_center = :center
+ #
+ module Radius
+
+ module ClassMethods
+ def initialize_trait(options = {})
+ @trait_options[:radius] = options
+ end
+ end
+
+ def radius
+ width = self.image.width * self.factor_x.abs
+ height = self.image.height * self.factor_y.abs
+ radius = (width + height) / 2
+ radius = radius * trait_options[:radius][:scale] if trait_options[:radius][:scale]
+ return radius
+ end
+
+ def draw_trait
+ if trait_options[:radius][:debug]
+ $window.draw_circle(self.x, self.y, self.radius, Chingu::DEBUG_COLOR)
+ end
+ super
+ end
+
+ end
+ end
+end
View
20 lib/chingu/traits/retrofy.rb
@@ -23,38 +23,37 @@ module Chingu
module Traits
#
# A chingu trait providing easier handling of the "retrofy" effect (non-blurry zoom)
- # Aims to help out when using zoom-factor to create a retrofeeling with big pixels.
- # Provides screen_x and screen_y which takes the zoom into account
+ # Aims to help out when using scaling with "factor" to create a retrofeeling with big pixels.
+ # Provides screen_x and screen_y which takes the scaling into account
# Also provides new code for draw() which uses screen_x / screen_y instead of x / y
#
module Retrofy
-
+
def setup_trait(options)
@retrofy_options = {:debug => false}.merge(options)
-
super
end
def screen_width
- (@image.width * self.factor).to_i
+ (self.image.width * self.factor).to_i
end
def screen_height
- (@image.heigt * self.factor).to_i
+ (self.image.heigt * self.factor).to_i
end
def screen_x
- (@x * self.factor).to_i
+ (self.x * self.factor).to_i
end
def screen_y
- (@y * self.factor).to_i
+ (self.y * self.factor).to_i
end
-
+
# Returns true if object is inside the game window, false if outside
# this special version takes @factor into consideration
def inside_window?
- @x >= 0 && @x <= $window.width/self.factor && @y >= 0 && @y <= $window.height/self.factor
+ self.x >= 0 && self.x <= $window.width/self.factor && self.y >= 0 && self.y <= $window.height/self.factor
end
# Returns true object is outside the game window
@@ -66,7 +65,6 @@ def outside_window?
def draw
@image.draw_rot(self.screen_x, self.screen_y, @zorder, @angle, @center_x, @center_y, @factor_x, @factor_y, @color, @mode)
end
-
end
end
end
View
7 lib/chingu/traits/timer.rb
@@ -31,10 +31,9 @@ module Traits
# All the above can be combined with a 'then { do_something }'. For example, a classic shmup damage effect:
# during(100) { @color.alpha = 100 }.then { @color.alpha = 255 }
#
- module Timer
- def setup_trait(options)
- @timer_options = {:debug => false}.merge(options)
-
+ module Timer
+
+ def setup_trait(options)
#
# Timers are saved as an array of arrays where each entry contains:
# [start_time, end_time (or nil if one-shot), &block]
View
15 lib/chingu/traits/velocity.rb
@@ -27,15 +27,8 @@ module Traits
module Velocity
attr_accessor :velocity_x, :velocity_y, :acceleration_x, :acceleration_y, :max_velocity
- #def self.initialize_trait(options)
- # @velocity_options = {:debug => false}.merge(options)
- # puts "Velocity#initialize" if @velocity_options[:debug]
- # super
- #end
-
def setup_trait(options)
@velocity_options = {:debug => false}.merge(options)
- puts "Velocity#setup" if @velocity_options[:debug]
@velocity_x = options[:velocity_x] || 0
@velocity_y = options[:velocity_y] || 0
@@ -48,13 +41,11 @@ def setup_trait(options)
#
# Modifies X & Y of parent
#
- def update_trait
- puts "Velocity#update" if @velocity_options[:debug]
-
+ def update_trait
@velocity_y += @acceleration_y if (@velocity_y + @acceleration_y).abs < @max_velocity
@velocity_x += @acceleration_x if (@velocity_x + @acceleration_x).abs < @max_velocity
- @y += @velocity_y
- @x += @velocity_x
+ self.y += @velocity_y
+ self.x += @velocity_x
super
end

0 comments on commit 8740bde

Please sign in to comment.
Something went wrong with that request. Please try again.