chingu 0.6.2 → 0.6.3

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.
data.tar.gz.sig CHANGED
@@ -1,2 +1,3 @@
1
- [H��7��ųhE�u��5�AMܐR��ä'
2
- B��©r@
1
+ ���M���ʜ ��G��5mǂ��tz��5��~ :kLJ����_Qˡ��e�z��(
2
+ 2�7����qh�y�rA�d
3
+ q �G_"Z\��{�N:g�k�� ��Y�m�Aĺ��a��RZ_bW���Fп��". �s��AQ7�~� ㏉ A�R� �]$k�a��D-�1����N#�S�_�u�@og�k��J �</J��ҋ�!�*a�4�!HL�8vG�J7�.��t}��7��x!p��L�ϙ��e�)�Z�Ž�
data/README.rdoc CHANGED
@@ -90,6 +90,8 @@ Both $window and game states gets some new graphical helpers, currently only 3,
90
90
  fill() # Fills whole window with color 'color'.
91
91
  fill_rect() # Fills a given Rect 'rect' with Color 'color'
92
92
  fill_gradient() # Fills window or a given rect with a gradient between two colors.
93
+ draw_circle() # Draws a circle
94
+ draw_rect() # Draws a rect
93
95
 
94
96
  If you base your models on GameObject (or BasicGameObject) you get:
95
97
  Enemy.all # Returns an Array of all Enemy-instances
@@ -445,13 +447,41 @@ Chingus inputhandler will detect that Menu is a GameState-class, create a new in
445
447
 
446
448
  === Traits
447
449
  Traits (often called behaivors) is a way of adding logic to any class inheriting from BasicGameObject / GameObject.
448
- Chingus trait-implementation is just ordinary ruby modules with 3 special methods:
450
+ Chingus trait-implementation is just ordinary ruby modules with 3 special methods:
449
451
  - setup_trait
450
452
  - update_trait
451
453
  - draw_trait
452
454
  Each of those 3 methods must call "super" to continue the trait-chain.
453
455
 
454
- Example:
456
+ Inside a certian trait-module you can also have a module called ClassMethods, methods inside that module will be added,
457
+ yes you guessed it, as class methods. If initialize_trait is defined inside ClassMethods it will be called class-evaluation time
458
+ (basicly on the has_trait :some_trait line).
459
+
460
+ A simple trait could be:
461
+
462
+ module Chingu
463
+ module Trait
464
+ module Inspect
465
+ module ClassMethods
466
+ def initialize_trait(options)
467
+ # possible initialize stuff here
468
+ end
469
+
470
+ def inspect
471
+ "There's {self.size} active instances of class {self.to_s}"
472
+ end
473
+ end
474
+ end
475
+ end
476
+
477
+ class Enemy < GameObject
478
+ has_trait :inspect # includes Chingu::Trait::Inspect and extends Chingu::Trait::Inspect::ClassMethods
479
+ end
480
+ 10.times { Enemy.create }
481
+ Enemy.inspect # => There's 10 active instances of class Enemy
482
+
483
+
484
+ Example of using traits :velocity and :timer:
455
485
 
456
486
  class Ogre < Chingu::GameObject
457
487
  has_traits :velocity, :timer
@@ -466,8 +496,8 @@ Example:
466
496
  # These 2 parameters will affect @x and @y every game-iteration
467
497
  # So if your ogre is standing on the ground, make sure you cancel out the effect of @acceleration_y
468
498
  #
469
- @velocity_x = 1 # move constantly to the right
470
- @acceleration_y = 0.4 # gravity is basicly a downwards acceleration
499
+ self.velocity_x = 1 # move constantly to the right
500
+ self.acceleration_y = 0.4 # gravity is basicly a downwards acceleration
471
501
  end
472
502
 
473
503
  def hit_by(object)
@@ -475,7 +505,7 @@ Example:
475
505
  # during() and then() is provided by the timer-trait
476
506
  # flash red for 300 millisec when hit, then go back to normal
477
507
  #
478
- during(100) { @color = @red; @mode = :additive }.then { @color = @white; @mode = :default }
508
+ during(100) { self.color = @red; self.mode = :additive }.then { self.color = @white; self.mode = :default }
479
509
  end
480
510
  end
481
511
 
@@ -483,7 +513,7 @@ The flow for a game object then becomes:
483
513
 
484
514
  -- creating a GameObject class X ( with a "has_trait :bounding_box, :scale => 0.80" )
485
515
  1) trait gets merged into X, instance and class methods are added
486
- 2) GameObject.initialize_trait(:scale => 0.80)
516
+ 2) GameObject.initialize_trait(:scale => 0.80) (initialize_trait is a class-method!)
487
517
  -- creating an instance of X
488
518
  1) GameObject#initialize(options)
489
519
  2) GameObject#setup_trait(options)
@@ -497,7 +527,7 @@ There's a couple of traits included as default in Chingu:
497
527
 
498
528
  ==== Trait "timer"
499
529
  Adds timer functionality to your game object
500
- during(300) { @color = Color.new(0xFFFFFFFF) } # forces @color to white every update for 300 ms
530
+ during(300) { self.color = Color.new(0xFFFFFFFF) } # forces @color to white every update for 300 ms
501
531
  after(400) { self.destroy } # destroy object after 400 ms
502
532
  between(1000,2000) { self.rotate(10) } # starting after 1 second, call rotate(10) every update during 1 second
503
533
  every(2000) { Sound["bleep.wav"].play } # play bleep.wav every 2 seconds
@@ -514,7 +544,7 @@ You can also scale the calculated rect with has_trait-options:
514
544
  # Make player think he's better @ dodging bullets then he really is ;)
515
545
  has_trait :bounding_box, :scale => 0.80
516
546
 
517
- ==== Trait "radius"
547
+ ==== Trait "bounding_circle"
518
548
  Adds accessor 'radius', which returns a Fixnum based on current image size,factor_x and factor_y
519
549
  You can also scale the calculated radius with has_trait-options:
520
550
 
@@ -530,14 +560,23 @@ Adds class and instance methods for basic collision detection.
530
560
 
531
561
  # Class method example
532
562
  # This will collide all Enemy-instances with all Bullet-instances using the attribute #radius from each object.
533
- Enemy.each_radius_collision(Bullet) do |enemy, bullet|
563
+ Enemy.each_bounding_circle_collision(Bullet) do |enemy, bullet|
534
564
  end
535
565
 
536
566
  # You can also use the instance methods. This will use the Rect bounding_box from @player and each EnemyRocket-object.
537
567
  @player.each_bounding_box_collision(EnemyRocket) do |player, enemyrocket|
538
568
  player.die!
539
569
  end
570
+
571
+ #
572
+ # each_collision automatically tries to access #radius and #bounding_box to see what a certain game object provides
573
+ # It knows how to collide radius/radius, bounding_box/bounding_box and radius/bounding_box !
574
+ # Since You're not explicity telling what collision type to use it might be slighty slower.
575
+ #
576
+ [Player, PlayerBullet].each_collision(Enemy, EnemyBullet) do |friend, foe|
540
577
 
578
+ end
579
+
541
580
  * API isn't stabilized yet! *
542
581
 
543
582
  ==== (IN DEVELOPMENT) Trait "retrofy"
@@ -562,7 +601,7 @@ Chingu solves this problem behind the scenes for the most common assets. The 2 l
562
601
  Image["player.png"]
563
602
 
564
603
  You also have:
565
- Sound["shot.png"]
604
+ Sound["shot.wav"]
566
605
  Song["intromusic.ogg"]
567
606
 
568
607
  The default settings are like this:
@@ -589,7 +628,7 @@ Text is a class to give the use of Gosu::Font more rubyish feel and fit it bette
589
628
  @font.draw("A Text", 200, 50, 55, 2.0)
590
629
 
591
630
  # Chingu
592
- @text = Chingu::Text.create(:text => "A Text", :x => 200, :y => 50, :zorder => 55, :factor_x => 2.0)
631
+ @text = Chingu::Text.create("A Text", :x => 200, :y => 50, :zorder => 55, :factor_x => 2.0)
593
632
  @text.draw
594
633
 
595
634
  @text.draw is usually not needed as Text is a GameObject and therefore automaticly updated/drawn (it #create is used instead of #new)
@@ -610,7 +649,7 @@ GameObject.all is naming straight from rails for example. Most stuff in GameObje
610
649
 
611
650
  As far as possible, use correct rubyfied english game_objects, not gameobjects. class HighScore, not Highscore.
612
651
 
613
- == TODO:
652
+ == TODO - this list is discontinued and no longer updated
614
653
  * add :padding and :align => :topleft etc to class Text
615
654
  * (skip) rename Chingu::Window so 'include Chingu' and 'include Gosu' wont make Window collide
616
655
  * (done) BasicObject vs GameObject vs ScreenObject => Became BasicGameObject and GameObject
@@ -656,9 +695,11 @@ As far as possible, use correct rubyfied english game_objects, not gameobjects.
656
695
 
657
696
  == CREDITS:
658
697
  * Jacius of Rubygame (For doing cool stuff that's well documented as re-usable). So far rect.rb and named_resource.rb is straight outta Rubygame.
698
+ * Banister (of texplay fame) for general feedeback and help with ruby-internals and building the trait-system
659
699
  * Jduff for input / commits
660
700
  * Jlnr,Philymore,Shawn24,JamesKilton for constructive feedback/discussions
661
701
  * Ariel Pillet for codesuggestions and cleanups
702
+ * Deps for making the first real full game with Chingu (and making it better in the process)
662
703
  * Thanks to http://github.com/tarcieri for require_all code, good stuff
663
704
 
664
705
  == REQUIREMENTS:
data/chingu.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{chingu}
5
- s.version = "0.6.2"
5
+ s.version = "0.6.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["ippa"]
9
- s.date = %q{2009-11-25}
9
+ s.date = %q{2009-11-26}
10
10
  s.description = %q{OpenGL accelerated 2D game framework for Ruby.
11
11
  Builds on the awesome Gosu (Ruby/C++) which provides all the core functionality.
12
12
  It adds simple yet powerful game states, prettier input handling, deployment safe asset-handling, a basic re-usable game object and automation of common task.}
@@ -11,8 +11,8 @@ class Game < Chingu::Window
11
11
  super(640,400)
12
12
  self.input = {:esc => :exit, :q => :decrease_size, :w => :increase_size, :a => :decrease_speed, :s => :increase_speed}
13
13
 
14
- 10.times { Circle.create(:x => width/2, :y => height/2) }
15
- 10.times { Box.create(:x => width/2, :y => height/2) }
14
+ 20.times { Circle.create(:x => width/2, :y => height/2) }
15
+ 20.times { Box.create(:x => width/2, :y => height/2) }
16
16
  @blue = Color.new(0xFF0000FF)
17
17
  @white = Color.new(0xFFFFFFFF)
18
18
  end
@@ -38,7 +38,10 @@ class Game < Chingu::Window
38
38
  #
39
39
  # Collide Boxes/Circles, Boxes/Boxes and Circles/Circles (basicly all objects on screen)
40
40
  #
41
- [Box, Circle].each_collision(Box, Circle) { |o, o2| o.color, o2.color = @blue, @blue }
41
+ # Before optmization: 25 FPS (20 boxes and 20 circles)
42
+ # Cached radius and rects:
43
+ #
44
+ #[Box, Circle].each_collision(Box, Circle) { |o, o2| o.color, o2.color = @blue, @blue }
42
45
 
43
46
  #
44
47
  # Only collide boxes with other boxes
@@ -69,8 +72,8 @@ class Circle < GameObject
69
72
  self.velocity_x = 3 - rand * 6
70
73
  self.velocity_y = 3 - rand * 6
71
74
  self.factor = 2
72
-
73
- self.input = [:holding_left, :holding_right, :holding_down, :holding_up]
75
+ self.input = [:holding_left, :holding_right, :holding_down, :holding_up] # NOTE: giving input an Array, not a Hash
76
+ cache_bounding_circle
74
77
  end
75
78
 
76
79
  def holding_left; @x -= 1; end
@@ -94,11 +97,14 @@ class Box < GameObject
94
97
  self.velocity_x = 3 - rand * 6
95
98
  self.velocity_y = 3 - rand * 6
96
99
  self.factor = 2
100
+ cache_bounding_box
97
101
  end
98
102
 
99
103
  def update
100
104
  self.velocity_x = -self.velocity_x if @x < 0 || @x > $window.width
101
105
  self.velocity_y = -self.velocity_y if @y < 0 || @y > $window.height
106
+ #@x = @x.to_i
107
+ #@y = @y.to_i
102
108
  end
103
109
  end
104
110
 
data/examples/example4.rb CHANGED
@@ -34,7 +34,7 @@ class Game < Chingu::Window
34
34
  push_game_state(Intro)
35
35
 
36
36
  # Yes you can do crazy things like this :)
37
- self.input = { :left_mouse_button => lambda{Chingu::Text.create(:text => "Woff!")}, :esc => :exit}
37
+ self.input = { :left_mouse_button => lambda{Chingu::Text.create(:text => "Woff!")}, :esc => :exit}
38
38
  end
39
39
  end
40
40
 
@@ -51,8 +51,8 @@ class Player < Chingu::GameObject
51
51
  def move_down; @y += 1; end
52
52
 
53
53
  def fire
54
- #puts $window.current_parent.to_s
55
- #puts $window.game_state_manager.inside_state
54
+ #puts "current_scope: #{$window.current_scope.to_s}"
55
+ #puts "inside_state: #{$window.game_state_manager.inside_state}"
56
56
  Bullet.create(:x => @x - 20, :y => @y)
57
57
  Bullet.create(:x => @x, :y => @y)
58
58
  Bullet.create(:x => @x + 20, :y => @y)
data/examples/example6.rb CHANGED
@@ -43,9 +43,18 @@ class Game < Chingu::Window
43
43
  end
44
44
 
45
45
  class State1 < Chingu::GameState
46
- def draw
47
- Image["ruby.png"].draw(0,0,0)
46
+
47
+ #
48
+ # This is another way of achieving the same thing as the out-commeted draw-code
49
+ # Since .create is used, it's automatically updated and drawn
50
+ #
51
+ def setup
52
+ Chingu::GameObject.create(:image => "ruby.png", :rotation_center => :top_left)
48
53
  end
54
+
55
+ #def draw
56
+ # Image["ruby.png"].draw(0,0,0)
57
+ #end
49
58
  end
50
59
 
51
60
  class State2 < Chingu::GameState
data/examples/example9.rb CHANGED
@@ -76,9 +76,13 @@ class ParticleState < Chingu::GameState
76
76
  end
77
77
 
78
78
  #
79
- # GameObject.each_collsion / each_radius_collision wont collide an object with itself
79
+ # GameObject.each_collsion / each_bounding_box_collision wont collide an object with itself
80
80
  #
81
- FireCube.each_radius_collision(FireCube) do |cube1, cube2|
81
+ # FireCube.each_bounding_circle_collision(FireCube) do |cube1, cube2| # 30 FPS on my computer
82
+ #
83
+ # Let's see if we can optimize each_collision, starts with 19 FPS
84
+ #
85
+ FireCube.each_collision(FireCube) do |cube1, cube2|
82
86
  cube1.die!
83
87
  cube2.die!
84
88
  end
data/examples/game1.rb CHANGED
@@ -35,12 +35,10 @@ class Level < Chingu::GameState
35
35
  def initialize(options = {})
36
36
  super
37
37
 
38
- @parallax = Parallax.create
39
- #ParallaxLayer.has_trait :retrofy
40
- #@parallax << ParallaxLayer.new(:image => Image["city3.png"].retrofy, :center => 0, :damping => 4, :factor => $window.factor)
41
- @parallax << ParallaxLayer.new(:image => Image["city2.png"].retrofy, :center => 0, :damping => 2, :factor => $window.factor)
42
- @parallax << ParallaxLayer.new(:image => Image["city1.png"].retrofy, :center => 0, :damping => 1, :factor => $window.factor)
43
- @player = Player.create(:x => 10, :y => 10)
38
+ @parallax = Parallax.create(:rotation_center => :top_left)
39
+ @parallax << { :image => Image["city2.png"].retrofy, :damping => 2, :factor => $window.factor }
40
+ @parallax << { :image => Image["city1.png"].retrofy, :damping => 1, :factor => $window.factor }
41
+ @player = Player.create(:x => 30, :y => 10)
44
42
 
45
43
  @bg1 = Color.new(0xFFCE28FF)
46
44
  @bg2 = Color.new(0xFF013E87)
@@ -95,12 +93,12 @@ class Level < Chingu::GameState
95
93
  push_game_state(GameOver) if solid_pixel_at?(@player.x, @player.y)
96
94
 
97
95
  # Collide player with enemies and enemy bullets
98
- @player.each_radius_collision(Enemy) do |player, enemy|
96
+ @player.each_bounding_circle_collision(Enemy) do |player, enemy|
99
97
  enemy.die
100
98
  push_game_state(GameOver)
101
99
  end
102
100
 
103
- Bullet.each_radius_collision(Enemy) do |bullet, enemy|
101
+ Bullet.each_bounding_circle_collision(Enemy) do |bullet, enemy|
104
102
  bullet.die
105
103
  if enemy.hit_by(bullet)
106
104
  @player.score += 20
@@ -9,6 +9,8 @@
9
9
  :score: 9912
10
10
  - :name: NEW
11
11
  :score: 9900
12
+ - :name: NEW
13
+ :score: 9886
12
14
  - :name: NEW
13
15
  :score: 9885
14
16
  - :name: NEW
@@ -19,5 +21,3 @@
19
21
  :score: 9746
20
22
  - :name: NEW
21
23
  :score: 9742
22
- - :name: NEW
23
- :score: 9736
data/lib/chingu.rb CHANGED
@@ -33,7 +33,7 @@ require_all "#{CHINGU_ROOT}/chingu/traits"
33
33
  require_all "#{CHINGU_ROOT}/chingu"
34
34
 
35
35
  module Chingu
36
- VERSION = "0.6.2"
36
+ VERSION = "0.6.3"
37
37
 
38
38
  DEBUG_COLOR = Gosu::Color.new(0xFFFF0000)
39
39
  DEBUG_ZORDER = 9999
@@ -7,7 +7,7 @@ module Chingu
7
7
  # It will also acts as a container for the trait-system of chingu.
8
8
  #
9
9
  class BasicGameObject
10
- include Chingu::ClassInheritableAccessor
10
+ include Chingu::Helpers::ClassInheritableAccessor # adds classmethod class_inheritable_accessor
11
11
 
12
12
  attr_reader :options, :paused, :visible
13
13
  attr_accessor :parent
@@ -65,9 +65,10 @@ module Chingu
65
65
  #
66
66
  # A GameObject either belong to a GameState or our mainwindow ($window)
67
67
  #
68
- if !@parent && $window && $window.respond_to?(:game_state_manager)
69
- @parent = $window.game_state_manager.inside_state || $window
70
- end
68
+ #if !@parent && $window && $window.respond_to?(:game_state_manager)
69
+ # @parent = $window.game_state_manager.inside_state || $window
70
+ #end
71
+ @parent = $window.current_scope if !@parent && $window
71
72
 
72
73
  # if true, BasicGameObject#update will be called
73
74
  @paused = options[:paused] || false
@@ -97,6 +98,7 @@ module Chingu
97
98
  #
98
99
  instance.parent.add_game_object(instance) if instance.parent
99
100
 
101
+
100
102
  return instance
101
103
  end
102
104
 
@@ -168,14 +170,14 @@ module Chingu
168
170
  # Bullet.all.each do {} # Iterate through all bullets in current game state
169
171
  #
170
172
  def self.all
171
- $window.current_parent.game_objects.of_class(self).dup
173
+ $window.current_scope.game_objects.of_class(self).dup
172
174
  end
173
175
 
174
176
  #
175
177
  # Returns
176
178
  #
177
179
  def self.size
178
- $window.current_parent.game_objects.of_class(self).size
180
+ $window.current_scope.game_objects.of_class(self).size
179
181
  end
180
182
 
181
183
  #
@@ -9,4 +9,27 @@ class Array
9
9
  end
10
10
  end
11
11
  end
12
+
13
+ def each_bounding_circle_collision(*args)
14
+ list = (self + args).uniq
15
+ collide_pair = []
16
+ list.each_with_index { |nr, i| self[i..size].collect { |nr2| collide_pair << [nr,nr2] } }
17
+ collide_pair.each do |class1,class2|
18
+ class1.each_bounding_circle_collision(class2) do |object1, object2|
19
+ yield object1, object2
20
+ end
21
+ end
22
+ end
23
+
24
+ def each_bounding_box_collision(*args)
25
+ list = (self + args).uniq
26
+ collide_pair = []
27
+ list.each_with_index { |nr, i| self[i..size].collect { |nr2| collide_pair << [nr,nr2] } }
28
+ collide_pair.each do |class1,class2|
29
+ class1.each_bounding_box_collision(class2) do |object1, object2|
30
+ yield object1, object2
31
+ end
32
+ end
33
+ end
34
+
12
35
  end
@@ -37,7 +37,6 @@ module Chingu
37
37
  include Chingu::Helpers::InputClient # Adds input and input=
38
38
  include Chingu::Helpers::RotationCenter # Adds easy and verbose modification of @center_x and @center_y
39
39
 
40
-
41
40
  def initialize(options = {})
42
41
  super
43
42
 
@@ -45,7 +44,7 @@ module Chingu
45
44
  if options[:image].is_a?(Gosu::Image)
46
45
  @image = options[:image]
47
46
  elsif options[:image].is_a? String
48
- @image = Image[options[:image]]
47
+ @image = Gosu::Image[options[:image]]
49
48
  end
50
49
 
51
50
  @x = options[:x] || 0
@@ -76,7 +75,7 @@ module Chingu
76
75
  @mode = options[:mode] || :default # :additive is also available.
77
76
  @zorder = options[:zorder] || 100
78
77
 
79
- ## setup_trait(options) if self.respond_to?(:setup_trait)
78
+ #setup_trait(options) if self.respond_to?(:setup_trait)
80
79
  end
81
80
 
82
81
  # Quick way of setting both factor_x and factor_y
@@ -54,20 +54,23 @@ module Chingu
54
54
  include Chingu::Helpers::GameObject # Adds game_objects_of_class etc ...
55
55
  include Chingu::Helpers::InputDispatcher # Input dispatch-helpers
56
56
  include Chingu::Helpers::InputClient # GameState can have it's own inputmap
57
+ include Chingu::Helpers::ClassInheritableAccessor # adds classmethod class_inheritable_accessor
57
58
 
58
59
  attr_reader :options
59
60
  attr_accessor :game_state_manager, :game_objects
60
61
 
61
- def self.trait_options; @trait_options; end
62
+ class_inheritable_accessor :trait_options
63
+ @trait_options = Hash.new
62
64
  def trait_options; self.class.trait_options; end
63
-
65
+
64
66
  #
65
67
  # Adds a trait or traits to a certain game class
66
68
  # Executes a standard ruby "include" the specified module
67
69
  #
68
70
  def self.has_trait(trait, options = {})
69
- @trait_options ||= Hash.new
71
+
70
72
  if trait.is_a?(::Symbol) || trait.is_a?(::String)
73
+ ## puts "has_trait #{trait}, #{options}"
71
74
  begin
72
75
  # Convert user-given symbol (eg. :timer) to a Module (eg. Chingu::Traits::Timer)
73
76
  mod = Chingu::Traits.const_get(Chingu::Inflector.camelize(trait))
@@ -75,14 +78,21 @@ module Chingu
75
78
  # Include the module, which will add the containing methods as instance methods
76
79
  include mod
77
80
 
78
- # Add possible classmethods defined in sub-module ClassMethods (eg: Chingu::Traits::Timer::ClassMethods)
79
- mod2 = mod.const_get("ClassMethods")
80
- extend mod2
81
+ # Does sub-module "ClessMethods" exists?
82
+ # (eg: Chingu::Traits::Timer::ClassMethods)
83
+ if mod.const_defined?("ClassMethods")
84
+ # Add methods in scope ClassMethods as.. class methods!
85
+ mod2 = mod.const_get("ClassMethods")
86
+ extend mod2
81
87
 
82
- # If the newly included trait has a initialize_trait method...
83
- # ... call it with the options provided with the has_trait-call
84
- initialize_trait(options) if mod2.method_defined?(:initialize_trait)
88
+ # If the newly included trait has a initialize_trait method in the ClassMethods-scope:
89
+ # ... call it with the options provided with the has_trait-line.
90
+ if mod2.method_defined?(:initialize_trait)
91
+ initialize_trait(options)
92
+ end
93
+ end
85
94
  rescue
95
+ puts $!
86
96
  end
87
97
  end
88
98
  end
@@ -114,6 +114,7 @@ module Chingu
114
114
  current_game_state.finalize if current_game_state.respond_to?(:finalize) && options[:finalize]
115
115
 
116
116
  # So BasicGameObject#create connects object to new state in its setup()
117
+ # Is this doubled in GameState.initialize() ?
117
118
  self.inside_state = new_state
118
119
 
119
120
  # Call setup
@@ -131,8 +132,10 @@ module Chingu
131
132
  @game_states[-1] = new_state
132
133
  end
133
134
  end
134
- ## MOVEDE: self.inside_state = current_game_state
135
+ ## MOVED: self.inside_state = current_game_state
135
136
  end
137
+
138
+ self.inside_state = nil # no longer 'inside' (as in within initialize() etc) a game state
136
139
  end
137
140
  alias :switch :switch_game_state
138
141
 
@@ -157,6 +160,7 @@ module Chingu
157
160
  new_state.setup if new_state.respond_to?(:setup) && options[:setup]
158
161
 
159
162
  # Make sure the game state knows about the manager
163
+ # Is this doubled in GameState.initialize() ?
160
164
  new_state.game_state_manager = self
161
165
 
162
166
  # Give the soon-to-be-disabled state a chance to clean up by calling finalize() on it.
@@ -172,6 +176,8 @@ module Chingu
172
176
  end
173
177
  ## MOVED: self.inside_state = current_game_state
174
178
  end
179
+
180
+ self.inside_state = nil # no longer 'inside' (as in within initialize() etc) a game state
175
181
  end
176
182
  alias :push :push_game_state
177
183
 
@@ -195,6 +201,7 @@ module Chingu
195
201
  @game_states.pop
196
202
 
197
203
  # So BasicGameObject#create connects object to new state in its setup()
204
+ # Is this doubled in GameState.initialize() ?
198
205
  self.inside_state = current_game_state
199
206
 
200
207
  # Call setup on the new current state
@@ -205,7 +212,9 @@ module Chingu
205
212
  transitional_game_state = @transitional_game_state.new(current_game_state, @transitional_game_state_options)
206
213
  self.switch_game_state(transitional_game_state, :transitional => false)
207
214
  end
215
+
208
216
  ## MOVED: self.inside_state = current_game_state
217
+ self.inside_state = nil # no longer 'inside' (as in within initialize() etc) a game state
209
218
  end
210
219
  alias :pop :pop_game_state
211
220
 
@@ -3,27 +3,29 @@
3
3
  # But we use the rails-name for it, class_inheritable_accessor, which should make ppl more @ home.
4
4
  #
5
5
  module Chingu
6
- module ClassInheritableAccessor
7
- def self.included(base)
8
- base.extend(ClassMethods)
9
- end
10
-
11
- module ClassMethods
12
- def class_inheritable_accessor(*args)
13
- @cattr_inheritable_attrs ||= [:cattr_inheritable_attrs]
14
- @cattr_inheritable_attrs += args
15
- args.each do |arg|
16
- class_eval %(
17
- class << self; attr_accessor :#{arg} end
18
- )
19
- end
20
- @cattr_inheritable_attrs
6
+ module Helpers
7
+ module ClassInheritableAccessor
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
21
10
  end
22
-
23
- def inherited(subclass)
24
- @cattr_inheritable_attrs.each do |inheritable_attribute|
25
- instance_var = "@#{inheritable_attribute}"
26
- subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
11
+
12
+ module ClassMethods
13
+ def class_inheritable_accessor(*args)
14
+ @cattr_inheritable_attrs ||= [:cattr_inheritable_attrs]
15
+ @cattr_inheritable_attrs += args
16
+ args.each do |arg|
17
+ class_eval %(
18
+ class << self; attr_accessor :#{arg} end
19
+ )
20
+ end
21
+ @cattr_inheritable_attrs
22
+ end
23
+
24
+ def inherited(subclass)
25
+ @cattr_inheritable_attrs.each do |inheritable_attribute|
26
+ instance_var = "@#{inheritable_attribute}"
27
+ subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
28
+ end
27
29
  end
28
30
  end
29
31
  end
@@ -29,6 +29,7 @@ module Chingu
29
29
  module GameObject
30
30
 
31
31
  def add_game_object(object)
32
+ # puts "#{self.to_s} add_game_object(#{object.to_s})"
32
33
  @game_objects.add_game_object(object)
33
34
  end
34
35
 
@@ -115,7 +115,7 @@ module Chingu
115
115
  def draw_circle(cx,cy,r,color)
116
116
  0.step(360, CIRCLE_STEP) do |a1|
117
117
  a2 = a1 + CIRCLE_STEP
118
- $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
118
+ $window.draw_line cx + Gosu.offset_x(a1, r), cy + Gosu.offset_y(a1, r), color, cx + Gosu.offset_x(a2, r), cy + Gosu.offset_y(a2, r), color, 9999
119
119
  end
120
120
  end
121
121
 
@@ -36,7 +36,8 @@ module Chingu
36
36
  #
37
37
  # Options (in hash-format):
38
38
  #
39
- # repeat: [true|false] When one layer ends within the screen, repeat/loop it
39
+ # repeat_x: [true|false] repeat layer on X-axis
40
+ # repeat_y: [true|false] repeat layer on Y-axis
40
41
  #
41
42
  def initialize(options = {})
42
43
  super(options)
@@ -61,7 +62,7 @@ module Chingu
61
62
  # returns true if any part of the parallax-scroller is inside the window
62
63
  #
63
64
  def inside_window?
64
- return true if @repeat
65
+ return true if @repeat_x || @repeat_y
65
66
  @layers.each { |layer| return true if layer.inside_window? }
66
67
  return false
67
68
  end
@@ -122,31 +123,30 @@ module Chingu
122
123
  #
123
124
  def draw
124
125
  @layers.each do |layer|
125
- layer.draw
126
+ #layer.draw
126
127
 
127
128
  save_x, save_y = layer.x, layer.y
128
129
 
129
130
  # If layer lands inside our window and repeat_x is true (defaults to true), draw it until window ends
130
131
  while layer.repeat_x && layer.x < $window.width
131
132
  while layer.repeat_y && layer.y < $window.height
132
- layer.y += layer.image.height
133
133
  layer.draw
134
+ layer.y += layer.image.height
134
135
  end
135
136
  layer.y = save_y
136
137
 
137
- layer.x += layer.image.width
138
138
  layer.draw
139
+ layer.x += layer.image.width
139
140
  end
140
141
 
141
- # Special loop for when repeat_y is set but not repeat_x
142
+ # Special loop for when repeat_y is true but not repeat_x
142
143
  if layer.repeat_y && !layer.repeat_x
143
144
  while layer.repeat_y && layer.y < $window.height
144
- layer.y += layer.image.height
145
145
  layer.draw
146
+ layer.y += layer.image.height
146
147
  end
147
148
  end
148
149
 
149
-
150
150
  layer.x = save_x
151
151
  end
152
152
  self
data/lib/chingu/text.rb CHANGED
@@ -72,7 +72,7 @@ module Chingu
72
72
  @align = options[:align] || :left
73
73
  @max_width = options[:max_width]
74
74
 
75
- self.rotation_center(:top_left)
75
+ self.rotation_center = :top_left
76
76
 
77
77
  @gosu_font = Gosu::Font.new($window, @font, @height)
78
78
 
@@ -32,8 +32,23 @@ module Chingu
32
32
  trait_options[:bounding_box] = options
33
33
  end
34
34
  end
35
-
36
- def bounding_box
35
+
36
+ def setup_trait(options)
37
+ @cached_bounding_box = nil
38
+ super
39
+ end
40
+
41
+ #
42
+ # Returns an instance of class Rect
43
+ #
44
+ def bounding_box
45
+ if @cached_bounding_box
46
+ @cached_bounding_box.x = self.x + @_x_diff
47
+ @cached_bounding_box.y = self.y + @_y_diff
48
+
49
+ return @cached_bounding_box
50
+ end
51
+
37
52
  width = self.image.width * self.factor_x.abs
38
53
  height = self.image.height * self.factor_y.abs
39
54
 
@@ -49,6 +64,18 @@ module Chingu
49
64
  end
50
65
  alias :bb :bounding_box
51
66
 
67
+ def cache_bounding_box
68
+ @cached_bounding_box = nil
69
+ @cached_bounding_box = self.bounding_box
70
+ @_x_diff = @cached_bounding_box.x - self.x
71
+ @_y_diff = @cached_bounding_box.y - self.y
72
+ end
73
+
74
+ #def update_trait
75
+ # cache_bounding_box if trait_options[:bounding_box][:cache] && !@cached_bounding_box
76
+ # super
77
+ #end
78
+
52
79
  def draw_trait
53
80
  if trait_options[:bounding_box][:debug]
54
81
  $window.draw_rect(self.bounding_box, Chingu::DEBUG_COLOR, Chingu::DEBUG_ZORDER)
@@ -31,15 +31,22 @@ module Chingu
31
31
 
32
32
  module ClassMethods
33
33
  def initialize_trait(options = {})
34
- trait_options[:radius] = options
34
+ trait_options[:bounding_circle] = options
35
35
  end
36
36
  end
37
37
 
38
+ def setup_trait(options)
39
+ @cached_radius = nil
40
+ super
41
+ end
42
+
38
43
  def radius
44
+ return @cached_radius if @cached_radius
45
+
39
46
  width = self.image.width * self.factor_x.abs
40
47
  height = self.image.height * self.factor_y.abs
41
48
  radius = (width + height) / 4
42
- radius = radius * trait_options[:radius][:scale] if trait_options[:radius][:scale]
49
+ radius = radius * trait_options[:bounding_circle][:scale] if trait_options[:bounding_circle][:scale]
43
50
  return radius
44
51
  end
45
52
 
@@ -47,13 +54,23 @@ module Chingu
47
54
  radius * 2
48
55
  end
49
56
 
57
+ def cache_bounding_circle
58
+ @cached_radius = nil
59
+ @cached_radius = self.radius
60
+ end
61
+
62
+ #def update_trait
63
+ # cache_bounding_circle if trait_options[:bounding_circle][:cache] && !@cached_radius
64
+ # super
65
+ #end
66
+
50
67
  def circle_left; self.x - self.radius; end
51
68
  def circle_right; self.x + self.radius; end
52
69
  def circle_top; self.y - self.radius; end
53
70
  def circle_bottom; self.y + self.radius; end
54
71
 
55
72
  def draw_trait
56
- if trait_options[:radius][:debug]
73
+ if trait_options[:bounding_circle][:debug]
57
74
  $window.draw_circle(self.x, self.y, self.radius, Chingu::DEBUG_COLOR)
58
75
  end
59
76
  super
@@ -49,11 +49,12 @@ module Chingu
49
49
  if self.respond_to?(:bounding_box) && object2.respond_to?(:bounding_box)
50
50
  bounding_box_collision?(object2)
51
51
  elsif self.respond_to?(:radius) && object2.respond_to?(:radius)
52
- radius_collision?(object2)
52
+ bounding_circle_collision?(object2)
53
53
  else
54
- bounding_box_radius_collision?(object2)
54
+ bounding_box_bounding_circle_collision?(object2)
55
55
  end
56
56
  end
57
+ alias :collision? :collides?
57
58
 
58
59
  #
59
60
  # Collide self with a given game object by checking both objects bounding_box'es
@@ -67,8 +68,8 @@ module Chingu
67
68
  # Collide self using distance between 2 objects and their radius.
68
69
  # Returns true if colliding.
69
70
  #
70
- def radius_collision?(object2)
71
- distance(self.x, self.y, object2.x, object2.y) < self.radius + object2.radius
71
+ def bounding_circle_collision?(object2)
72
+ Gosu.distance(self.x, self.y, object2.x, object2.y) < self.radius + object2.radius
72
73
  end
73
74
 
74
75
  #
@@ -76,7 +77,7 @@ module Chingu
76
77
  #
77
78
  # http://stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersection
78
79
  #
79
- def bounding_box_radius_collision?(object2)
80
+ def bounding_box_bounding_circle_collision?(object2)
80
81
  rect = self.respond_to?(:bounding_box) ? self.bounding_box : object2.bounding_box
81
82
  circle = self.respond_to?(:radius) ? self : object2
82
83
  radius = circle.radius.to_i
@@ -110,10 +111,10 @@ module Chingu
110
111
  # Explicit radius-collision
111
112
  # Works like each_collsion but with inline-code for speedups
112
113
  #
113
- def each_radius_collision(klasses = [])
114
+ def each_bounding_circle_collision(klasses = [])
114
115
  Array(klasses).each do |klass|
115
116
  klass.all.each do |object|
116
- yield(self, object) if distance(self.x, self.y, object.x, object.y) < self.radius + object.radius
117
+ yield(self, object) if Gosu.distance(self.x, self.y, object.x, object.y) < self.radius + object.radius
117
118
  end
118
119
  end
119
120
  end
@@ -135,7 +136,7 @@ module Chingu
135
136
  #
136
137
  # Works like each_collision but with inline-code for speedups
137
138
  #
138
- def each_radius_collision(klasses = [])
139
+ def each_bounding_circle_collision(klasses = [])
139
140
  Array(klasses).each do |klass|
140
141
  object2_list = klass.all
141
142
  #total_radius = object1.radius + object2.radius # possible optimization?
@@ -143,7 +144,7 @@ module Chingu
143
144
  self.all.each do |object1|
144
145
  object2_list.each do |object2|
145
146
  next if object1 == object2 # Don't collide objects with themselves
146
- yield object1, object2 if distance(object1.x, object1.y, object2.x, object2.y) < object1.radius + object2.radius
147
+ yield object1, object2 if Gosu.distance(object1.x, object1.y, object2.x, object2.y) < object1.radius + object2.radius
147
148
  end
148
149
  end
149
150
  end
@@ -190,7 +191,7 @@ module Chingu
190
191
  # self.all.each do |object1|
191
192
  # object2_list.each do |object2|
192
193
  # next if object1 == object2 # Don't collide objects with themselves
193
- # yield object1, object2 if object1.bounding_box_radius_collision?(object2)
194
+ # yield object1, object2 if object1.bounding_box_bounding_circle_collision?(object2)
194
195
  # end
195
196
  # end
196
197
  #end
data/lib/chingu/window.rb CHANGED
@@ -59,8 +59,15 @@ module Chingu
59
59
  @milliseconds_since_last_tick = 0
60
60
  end
61
61
 
62
- def current_parent
63
- game_state_manager.current_game_state || self
62
+ #
63
+ # Returns self inside GameState.initialize (a game state is not 'active' inside initialize())
64
+ # Or returns current active game state (as in a switched to or pushed game state)
65
+ # ... Falls back to returning $window
66
+ #
67
+ # current_scope is used to make GameObject.all and friends work everywhere.
68
+ #
69
+ def current_scope
70
+ game_state_manager.inside_state || game_state_manager.current_game_state || self
64
71
  end
65
72
 
66
73
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chingu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ippa
@@ -30,7 +30,7 @@ cert_chain:
30
30
  hxtMlw==
31
31
  -----END CERTIFICATE-----
32
32
 
33
- date: 2009-11-25 00:00:00 +01:00
33
+ date: 2009-11-26 00:00:00 +01:00
34
34
  default_executable:
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
metadata.gz.sig CHANGED
Binary file