chingu 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +3 -2
- data/README.rdoc +53 -12
- data/chingu.gemspec +2 -2
- data/examples/example14.rb +11 -5
- data/examples/example4.rb +3 -3
- data/examples/example6.rb +11 -2
- data/examples/example9.rb +6 -2
- data/examples/game1.rb +6 -8
- data/examples/high_score_list.yml +2 -2
- data/lib/chingu.rb +1 -1
- data/lib/chingu/basic_game_object.rb +8 -6
- data/lib/chingu/core_ext/array.rb +23 -0
- data/lib/chingu/game_object.rb +2 -3
- data/lib/chingu/game_state.rb +19 -9
- data/lib/chingu/game_state_manager.rb +10 -1
- data/lib/chingu/helpers/class_inheritable_accessor.rb +22 -20
- data/lib/chingu/helpers/game_object.rb +1 -0
- data/lib/chingu/helpers/gfx.rb +1 -1
- data/lib/chingu/parallax.rb +8 -8
- data/lib/chingu/text.rb +1 -1
- data/lib/chingu/traits/bounding_box.rb +29 -2
- data/lib/chingu/traits/bounding_circle.rb +20 -3
- data/lib/chingu/traits/collision_detection.rb +11 -10
- data/lib/chingu/window.rb +9 -2
- metadata +2 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
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
|
-
|
470
|
-
|
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) {
|
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) {
|
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 "
|
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.
|
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.
|
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(
|
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.
|
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-
|
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.}
|
data/examples/example14.rb
CHANGED
@@ -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
|
-
|
15
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
47
|
-
|
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 /
|
79
|
+
# GameObject.each_collsion / each_bounding_box_collision wont collide an object with itself
|
80
80
|
#
|
81
|
-
FireCube.
|
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
|
-
|
40
|
-
|
41
|
-
@
|
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.
|
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.
|
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
|
data/lib/chingu.rb
CHANGED
@@ -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
|
-
|
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.
|
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.
|
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
|
data/lib/chingu/game_object.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/chingu/game_state.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
#
|
79
|
-
|
80
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
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
|
-
##
|
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
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
data/lib/chingu/helpers/gfx.rb
CHANGED
@@ -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
|
|
data/lib/chingu/parallax.rb
CHANGED
@@ -36,7 +36,8 @@ module Chingu
|
|
36
36
|
#
|
37
37
|
# Options (in hash-format):
|
38
38
|
#
|
39
|
-
#
|
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 @
|
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
|
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
@@ -32,8 +32,23 @@ module Chingu
|
|
32
32
|
trait_options[:bounding_box] = options
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
def
|
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[:
|
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[:
|
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[:
|
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
|
-
|
52
|
+
bounding_circle_collision?(object2)
|
53
53
|
else
|
54
|
-
|
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
|
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
|
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
|
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
|
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.
|
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
|
-
|
63
|
-
|
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.
|
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-
|
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
|