chingu 0.9rc7 → 0.9rc8

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.
@@ -30,7 +30,7 @@ class Stuff < GameState
30
30
  end
31
31
 
32
32
  def stop
33
- stop_timer(:name => :blink)
33
+ stop_timer(:blink)
34
34
  end
35
35
 
36
36
  def fast
@@ -9,11 +9,25 @@ include Chingu
9
9
  # GFXHelpers example - demonstrating Chingus GFX
10
10
  #
11
11
  class Game < Chingu::Window
12
+ @@number_of_game_states = 7
12
13
  def initialize
13
14
  super(640,400)
14
15
  self.input = {:space => :next_effect, :esc => :exit}
15
16
  self.caption = "Example of Chingus GFX Helpers"
16
-
17
+ load_game_states
18
+ end
19
+
20
+ def next_effect
21
+ @@number_of_game_states -= 1
22
+ if @@number_of_game_states == 0
23
+ load_game_states
24
+ @@number_of_game_states = 7
25
+ else
26
+ pop_game_state
27
+ end
28
+ end
29
+
30
+ def load_game_states
17
31
  push_game_state(Fill)
18
32
  push_game_state(FillRect)
19
33
  push_game_state(FillGradient)
@@ -22,15 +36,13 @@ class Game < Chingu::Window
22
36
  push_game_state(DrawCircle)
23
37
  push_game_state(Particles)
24
38
  end
25
-
26
- def next_effect
27
- pop_game_state
28
- end
29
39
  end
30
40
 
41
+
42
+
31
43
  class DrawCircle < Chingu::GameState
32
44
  def draw
33
- $window.caption = "circles and arcs (space to continue)"
45
+ $window.caption = "circles and arcs (press space to continue)"
34
46
  draw_circle(0, 0, 300, Color::RED)
35
47
  fill_circle($window.width, $window.height, 200, Color::RED)
36
48
 
@@ -44,14 +56,14 @@ end
44
56
 
45
57
  class Fill < Chingu::GameState
46
58
  def draw
47
- $window.caption = "fill (space to continue)"
59
+ $window.caption = "fill (press space to continue)"
48
60
  fill(Color::RED)
49
61
  end
50
62
  end
51
63
 
52
64
  class FillRect < Chingu::GameState
53
65
  def draw
54
- $window.caption = "fill_rect (space to continue)"
66
+ $window.caption = "fill_rect (press space to continue)"
55
67
  fill_rect([10,10,100,100], Color::WHITE)
56
68
  end
57
69
  end
@@ -63,7 +75,7 @@ class FillGradient < Chingu::GameState
63
75
  end
64
76
 
65
77
  def draw
66
- $window.caption = "fill_gradient (space to continue)"
78
+ $window.caption = "fill_gradient (press space to continue)"
67
79
  fill_gradient(:from => @pinkish, :to => @blueish, :orientation => :vertical)
68
80
  end
69
81
  end
@@ -74,7 +86,7 @@ class FillGradientMultipleColors < Chingu::GameState
74
86
  end
75
87
 
76
88
  def draw
77
- $window.caption = "fill_gradient with more than two colors (space to continue)"
89
+ $window.caption = "fill_gradient with more than two colors (press space to continue)"
78
90
  fill_gradient(:colors => @colors, :orientation => :horizontal)
79
91
  end
80
92
  end
@@ -86,7 +98,7 @@ class FillGradientRect < Chingu::GameState
86
98
  end
87
99
 
88
100
  def draw
89
- $window.caption = "fill_gradient with :rect-option (space to continue)"
101
+ $window.caption = "fill_gradient with :rect-option (press space to continue)"
90
102
  fill_gradient(:from => @color1, :to => @color2, :rect => [100,100,200,200], :orientation => :horizontal)
91
103
  end
92
104
  end
@@ -8,12 +8,20 @@ require 'rubygems' rescue nil
8
8
  $LOAD_PATH.unshift File.join(File.expand_path(__FILE__), "..", "..", "lib")
9
9
  require 'chingu'
10
10
  require 'texplay' # adds Image#get_pixel
11
+ require 'optparse'
11
12
 
12
13
  include Gosu
13
14
  include Chingu
14
15
 
16
+
15
17
  class Game < Chingu::Window
16
18
  def initialize
19
+ $debug = false
20
+ ARGV.each do |a|
21
+ if a == "-debug"
22
+ $debug = true
23
+ end
24
+ end
17
25
  super(1000,400,false)
18
26
  self.input = { :escape => :exit }
19
27
  retrofy
@@ -30,14 +38,18 @@ class Level < Chingu::GameState
30
38
 
31
39
  def initialize(options = {})
32
40
  super
33
-
34
- @parallax = Parallax.create(:rotation_center => :top_left, :zorder => 200)
35
- @parallax << { :image => "city2.png", :damping => 2, :zorder => 200}
36
- @parallax << { :image => "city1.png", :damping => 1, :zorder => 200}
37
- @player = Player.create(:x => 30, :y => 10)
41
+
42
+ @parallax = Parallax.create(:rotation_center => :top_left, :zorder => 0)
43
+ @parallax << { :image => "city2.png", :damping => 2, :zorder => 0}
44
+ @parallax << { :image => "city1.png", :damping => 1, :zorder => 1000}
45
+
46
+ @player = Player.create(:x => 30, :y => 10, :zorder=> 500)
38
47
 
39
48
  @bg1 = Color.new(0xFFCE28FF)
40
49
  @bg2 = Color.new(0xFF013E87)
50
+ @text = Text.create("Score:", :size => 20, :x => 30, :y => 370, :zorder => 1001) #initialize score string
51
+ @text1 = Text.create("0", :size => 20, :x => 90, :y => 370, :zorder => 1001) #initialize score value to 0
52
+
41
53
  end
42
54
 
43
55
  #
@@ -53,7 +65,7 @@ class Level < Chingu::GameState
53
65
  @player.y = 100
54
66
 
55
67
  @parallax.camera_x = 0
56
- @total_game_ticks = 100000
68
+ @total_game_ticks = 10000#100000
57
69
  @timer = 100
58
70
  @total_ticks = 0
59
71
  end
@@ -94,19 +106,183 @@ class Level < Chingu::GameState
94
106
  bullet.die
95
107
  if enemy.hit_by(bullet)
96
108
  @player.score += 20
109
+ @text1.destroy! #destroy old score
110
+ @text1 = Text.create(@player.score, :size => 20, :x => 90, :y => 370, :zorder => 1001 ) #update the new score
111
+
112
+ end
113
+ end
114
+
115
+ Bullet.each_bounding_circle_collision(EnemyPlane) do |bullet, enemy|
116
+ bullet.die
117
+ if enemy.hit_by(bullet)
118
+ @player.score += 20
119
+ @text1.destroy! #destroy old score
120
+ @text1 = Text.create(@player.score, :size => 20, :x => 90, :y => 370, :zorder => 1001 ) #update the new score
121
+
97
122
  end
98
123
  end
124
+
125
+ # clean up objects
126
+ game_objects.destroy_if { |object| object.outside_window? || object.color.alpha == 0 }
99
127
 
100
128
  @timer = @timer * 0.9999
101
129
  @total_ticks += 1
102
130
  if @total_ticks > @timer
103
- Enemy.create(:x => $window.width, :y => rand(300))
131
+ Enemy.create(:x => $window.width, :y => rand(300), :zorder => (rand(20) * 100))
104
132
  @total_ticks = 0
105
133
  end
106
-
107
- $window.caption = "City Battle! Player x/y: #{@player.x}/#{@player.y} - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
134
+
135
+ if @player.score > 100
136
+ switch_game_state(Level2)
137
+ end
138
+
139
+ if($debug)
140
+ $window.caption = "City Battle! - Player x/y: #{@player.x}/#{@player.y} - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
141
+ else
142
+ $window.caption = "City Battle! - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
143
+ end
144
+ end
145
+ def draw
146
+ fill_gradient(:from => @bg2, :to => @bg1)
147
+ @parallax.draw
148
+ super
149
+ end
150
+ end
151
+
152
+
153
+ #
154
+ # GAME STATE: LEVEL
155
+ #
156
+ class Level2 < Chingu::GameState
157
+ has_trait :timer
158
+
159
+ def initialize(options = {})
160
+ super
161
+
162
+ @parallax = Parallax.create(:rotation_center => :top_left, :zorder => 0)
163
+ @parallax << { :image => "city1.png", :damping => 2, :zorder => 0}
164
+ @parallax << { :image => "city3.png", :damping => 1, :zorder => 1000}
165
+
166
+ @player = Player.create(:x => 30, :y => 10, :zorder=> 500)
167
+
168
+ @bg1 = Color.new(0xFFCE28FF)
169
+ @bg2 = Color.new(0xFF013E87)
170
+ @text = Text.create("Score:", :size => 20, :x => 30, :y => 370, :zorder => 1001) #initialize score string
171
+ @text1 = Text.create("0", :size => 20, :x => 90, :y => 370, :zorder => 1001) #initialize score value to 0
172
+
173
+
174
+ end
175
+
176
+ #
177
+ # This is called each time this GameState is switched/pushed/poped to.
178
+ #
179
+ def setup
180
+ # Remove all lingering game objects
181
+ Enemy.destroy_all
182
+ Bullet.destroy_all
183
+
184
+ @player.score = 0
185
+ @player.x = 10
186
+ @player.y = 100
187
+
188
+ @parallax.camera_x = 0
189
+ @total_game_ticks = 10000#100000
190
+ @timer = 100
191
+ @total_ticks = 0
192
+ end
193
+
194
+ #
195
+ # The foremost layer in our parallax scroller is the collidable terrain
196
+ #
197
+ def solid_pixel_at?(x, y)
198
+ begin
199
+ @parallax.layers.last.get_pixel(x, y)[3] != 0
200
+ rescue
201
+ puts "Error in get_pixel(#{x}, #{y})"
202
+ end
108
203
  end
109
204
 
205
+ def update
206
+ super
207
+
208
+ # Move the level forward by increasing the parallax-scrollers camera x-coordinate
209
+ @parallax.camera_x += 1.5
210
+
211
+ # Remove all objects outside screen
212
+ game_objects.destroy_if { |game_object| game_object.respond_to?("outside_window?") && game_object.outside_window? }
213
+
214
+ # Collide bullets with terrain
215
+ Bullet.select { |o| solid_pixel_at?(o.x, o.y)}.each { |o| o.die }
216
+
217
+ # Collide player with terrain
218
+ push_game_state(GameOver) if solid_pixel_at?(@player.x, @player.y)
219
+
220
+ # Collide player with enemies and enemy bullets
221
+ @player.each_bounding_circle_collision(Enemy) do |player, enemy|
222
+ enemy.die
223
+ push_game_state(GameOver)
224
+ end
225
+
226
+ # Collide player with enemies and enemy bullets
227
+ @player.each_bounding_circle_collision(EnemyPlane) do |player, enemy|
228
+ enemy.die
229
+ push_game_state(GameOver)
230
+ end
231
+
232
+ Bullet.each_bounding_circle_collision(Enemy) do |bullet, enemy|
233
+ bullet.die
234
+ if enemy.hit_by(bullet)
235
+ @player.score += 20
236
+ @text1.destroy! #destroy old score
237
+ @text1 = Text.create(@player.score, :size => 20, :x => 90, :y => 370, :zorder => 1001 ) #update the new score
238
+ end
239
+ end
240
+
241
+ Bullet.each_bounding_circle_collision(EnemyPlane) do |bullet, enemy|
242
+ bullet.die
243
+ if enemy.hit_by(bullet)
244
+ @player.score += 20
245
+ @text1.destroy! #destroy old score
246
+ @text1 = Text.create(@player.score, :size => 20, :x => 90, :y => 370, :zorder => 1001 ) #update the new score
247
+ end
248
+ end
249
+
250
+ Bullet.each_bounding_circle_collision(EnemyPlane) do |bullet, enemy|
251
+ bullet.die
252
+ if enemy.hit_by(bullet)
253
+ @player.score += 20
254
+ @text1.destroy! #destroy old score
255
+ @text1 = Text.create(@player.score, :size => 20, :x => 90, :y => 370, :zorder => 1001 ) #update the new score
256
+
257
+ end
258
+ end
259
+
260
+
261
+ @timer = @timer * 0.9999
262
+ @total_ticks += 1
263
+ if @total_ticks > @timer
264
+ @select=rand(2)
265
+ if @select==1
266
+ Enemy.create(:x => $window.width, :y => rand(300), :zorder => (rand(20) * 100))
267
+ else
268
+ EnemyPlane.create(:x => $window.width, :y => rand(300), :zorder => (rand(20) * 100))
269
+ end
270
+ @total_ticks = 0
271
+ end
272
+
273
+ if @player.score > 100
274
+ switch_game_state(Done)
275
+ end
276
+
277
+ # clean up objects
278
+ game_objects.destroy_if { |object| object.outside_window? || object.color.alpha == 0 }
279
+
280
+ if($debug)
281
+ $window.caption = "City Battle! - Player x/y: #{@player.x}/#{@player.y} - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
282
+ else
283
+ $window.caption = "City Battle! - Score: #{@player.score} - FPS: #{$window.fps} - game objects: #{game_objects.size}"
284
+ end
285
+ end
110
286
  def draw
111
287
  fill_gradient(:from => @bg2, :to => @bg1)
112
288
  @parallax.draw
@@ -280,6 +456,8 @@ class Enemy < GameObject
280
456
  @black = Color.new(0xFF000000)
281
457
  @status == :default
282
458
 
459
+ @fireball_animation = Chingu::Animation.new(:file => media_path("fireball.png"), :size => [32,32])
460
+
283
461
  #
284
462
  # Cache explosion and shrapnel images (created with texplay, not recomended doing over and over each time)
285
463
  #
@@ -323,7 +501,19 @@ class Enemy < GameObject
323
501
  # Create some shrapnel-objects
324
502
  #
325
503
  Sound["explosion.wav"].play(0.3)
326
- Explosion.create(:x => @x, :y => @y, :image => @@explosion_image )
504
+
505
+ #Explosion.create(:x => @x, :y => @y, :image => @@explosion_image )
506
+ 5.times{ Chingu::Particle.create( :x => @x,
507
+ :y => @y,
508
+ :animation => @fireball_animation,
509
+ :scale_rate => +0.05,
510
+ :fade_rate => -10,
511
+ :rotation_rate => +1,
512
+ :mode => :default
513
+ )
514
+ @x -= @velocity
515
+ }
516
+
327
517
  5.times { Shrapnel.create(:x => @x, :y => @y, :image => @@shrapnel_image)}
328
518
 
329
519
  #
@@ -343,6 +533,103 @@ class Enemy < GameObject
343
533
  end
344
534
 
345
535
 
536
+ #
537
+ # OUR ENEMY Plane
538
+ #
539
+ class EnemyPlane < GameObject
540
+ has_traits :collision_detection, :timer
541
+ attr_reader :radius
542
+
543
+ def setup
544
+ @velocity = options[:velocity] || 2
545
+ @health = options[:health] || 100
546
+
547
+ @anim = Animation.new(:file => "media/enemy_plane.png", :size => [32,20], :delay => 100)
548
+ @image = @anim.first
549
+
550
+ @radius = 5
551
+ @black = Color.new(0xFF000000)
552
+ @status == :default
553
+
554
+ @fireball_animation = Chingu::Animation.new(:file => media_path("fireball.png"), :size => [32,32])
555
+
556
+ #
557
+ # Cache explosion and shrapnel images (created with texplay, not recomended doing over and over each time)
558
+ #
559
+ @@shrapnel_image ||= Shrapnel.create_image_for(self)
560
+ @@explosion_image ||= Explosion.create_image_for(self)
561
+ end
562
+
563
+ def hit_by(object)
564
+ return if @status == :dying
565
+
566
+ #
567
+ # During 20 millisecons, use Gosus :additive draw-mode, which here results in a white sprite
568
+ # Classic "hit by a bullet"-effect
569
+ #
570
+ during(20) { @mode = :additive; }.then { @mode = :default }
571
+
572
+ @health -= 20
573
+
574
+ if @health <= 0
575
+ die
576
+ return true
577
+ else
578
+ return false
579
+ end
580
+ end
581
+
582
+ def fire
583
+ EnemyBullet.create(:x => self.x, :y => self.y)
584
+ end
585
+
586
+ def die
587
+ #
588
+ # Make sure die() is only called once
589
+ #
590
+ return if @status == :dying
591
+ @status = :dying
592
+
593
+ #
594
+ # Play our explosion-sound file
595
+ # Create an explosion-object
596
+ # Create some shrapnel-objects
597
+ #
598
+ Sound["explosion.wav"].play(0.3)
599
+
600
+ #Explosion.create(:x => @x, :y => @y, :image => @@explosion_image )
601
+ 5.times{ Chingu::Particle.create( :x => @x,
602
+ :y => @y,
603
+ :animation => @fireball_animation,
604
+ :scale_rate => +0.05,
605
+ :fade_rate => -10,
606
+ :rotation_rate => +1,
607
+ :mode => :default
608
+ )
609
+ @x -= @velocity
610
+ }
611
+
612
+ 5.times { Shrapnel.create(:x => @x, :y => @y, :image => @@shrapnel_image)}
613
+
614
+ #
615
+ # During 200 ms, fade and scale image, then destroy it
616
+ #
617
+ @color = @black
618
+ @color.alpha = 50
619
+ during(200) { @factor_x += 0.5; @factor_y += 0.5; @x -= 1; @color.alpha -= 1}.then { self.destroy }
620
+ end
621
+
622
+ def update
623
+ return if @status == :dying
624
+
625
+ @image = @anim.next
626
+ @x -= @velocity
627
+ end
628
+ end
629
+
630
+
631
+
632
+
346
633
  #
347
634
  # GAME STATE: GAME OVER
348
635
  #
@@ -368,17 +655,14 @@ end
368
655
  # GAME STATE: GAME OVER
369
656
  #
370
657
  class Done < Chingu::GameState
371
- def initialize(options)
372
- @score = options[:score]
373
- end
374
-
658
+
375
659
  def setup
376
660
  @text = Text.create("You made it! Score #{@score} (ESC to quit, RETURN to try again!)", :size => 40, :x => 30, :y => 100)
377
661
  self.input = { :esc => :exit, :return => :try_again}
378
662
  end
379
663
 
380
664
  def try_again
381
- pop_game_state # pop back to our playing game state
665
+ switch_game_state(Level)
382
666
  end
383
667
  end
384
668