chingu 0.7.0 → 0.7.5

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.
Files changed (58) hide show
  1. data/History.txt +1 -1
  2. data/README.rdoc +110 -49
  3. data/benchmarks/game_objects_benchmark.rb +50 -0
  4. data/chingu.gemspec +24 -12
  5. data/examples/example10_traits_retrofy.rb +6 -4
  6. data/examples/example11_animation.rb +14 -23
  7. data/examples/example12_trait_timer.rb +1 -1
  8. data/examples/example13_high_scores.rb +1 -1
  9. data/examples/example14_bounding_box_circle.rb +6 -10
  10. data/examples/example15_trait_timer2.rb +1 -1
  11. data/examples/example16_online_high_scores.rb +1 -1
  12. data/examples/example17_gosu_tutorial.rb +4 -4
  13. data/examples/example18_animation_trait.rb +98 -0
  14. data/examples/example19_edit_viewport.rb +223 -0
  15. data/examples/example19_game_objects.yml +1591 -0
  16. data/examples/example20_trait_inheritence_test.rb +58 -0
  17. data/examples/example3_parallax.rb +1 -1
  18. data/examples/example4_gamestates.rb +1 -1
  19. data/examples/example7_gfx_helpers.rb +14 -9
  20. data/examples/example8_traits.rb +4 -4
  21. data/examples/example9_collision_detection.rb +1 -1
  22. data/examples/game1.rb +33 -38
  23. data/examples/game_of_life.rb +291 -0
  24. data/examples/media/droid_11x15.bmp +0 -0
  25. data/examples/media/droid_11x15.gal +0 -0
  26. data/examples/media/heli.bmp +0 -0
  27. data/examples/media/heli.gal +0 -0
  28. data/examples/media/star_25x25_default.png +0 -0
  29. data/examples/media/star_25x25_explode.gal +0 -0
  30. data/examples/media/star_25x25_explode.png +0 -0
  31. data/examples/media/stone_wall.bmp +0 -0
  32. data/lib/chingu.rb +1 -1
  33. data/lib/chingu/animation.rb +78 -9
  34. data/lib/chingu/basic_game_object.rb +16 -8
  35. data/lib/chingu/game_object.rb +36 -7
  36. data/lib/chingu/game_object_list.rb +20 -3
  37. data/lib/chingu/game_state.rb +8 -7
  38. data/lib/chingu/game_states/edit.rb +177 -90
  39. data/lib/chingu/helpers/class_inheritable_accessor.rb +12 -5
  40. data/lib/chingu/helpers/game_object.rb +45 -4
  41. data/lib/chingu/helpers/gfx.rb +150 -172
  42. data/lib/chingu/helpers/input_client.rb +7 -0
  43. data/lib/chingu/inflector.rb +16 -2
  44. data/lib/chingu/traits/animation.rb +84 -0
  45. data/lib/chingu/traits/bounding_box.rb +16 -3
  46. data/lib/chingu/traits/bounding_circle.rb +18 -4
  47. data/lib/chingu/traits/collision_detection.rb +10 -1
  48. data/lib/chingu/traits/velocity.rb +26 -3
  49. data/lib/chingu/traits/viewport.rb +10 -9
  50. data/lib/chingu/viewport.rb +103 -22
  51. data/lib/chingu/window.rb +8 -2
  52. metadata +46 -16
  53. data/examples/example18_viewport.rb +0 -173
  54. data/examples/media/city1.csv +0 -2
  55. data/examples/media/plane.csv +0 -2
  56. data/examples/media/saucer.csv +0 -4
  57. data/examples/media/stickfigure.bmp +0 -0
  58. data/examples/media/stickfigure.png +0 -0
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
- require 'opengl'
4
3
  require File.join(File.dirname($0), "..", "lib", "chingu")
5
4
  include Gosu
6
5
  include Chingu
@@ -14,14 +13,15 @@ class Game < Chingu::Window
14
13
  def initialize
15
14
  super
16
15
  @factor = 6
17
- self.input = { :escape => :exit }
16
+ self.input = { :escape => :exit }
17
+ Gosu::enable_undocumented_retrofication
18
18
  self.caption = "Chingu::Animation / retrofy example. Move with arrows!"
19
19
  Droid.create(:x => $window.width/2, :y => $window.height/2)
20
20
  end
21
21
  end
22
22
 
23
23
  class Droid < Chingu::GameObject
24
- has_traits :timer
24
+ traits :timer
25
25
 
26
26
  def initialize(options = {})
27
27
  super
@@ -33,18 +33,11 @@ class Droid < Chingu::GameObject
33
33
  self.input = [:holding_left, :holding_right, :holding_up, :holding_down]
34
34
 
35
35
  # Load the full animation from tile-file media/droid.bmp
36
- @full_animation = Chingu::Animation.new(:file => "droid.bmp", :size => [11,16]).retrofy
36
+ @animation = Chingu::Animation.new(:file => "droid_11x15.bmp")
37
+ @animation.frame_names = { :scan => 0..5, :up => 6..7, :down => 8..9, :left => 10..11, :right => 12..13 }
37
38
 
38
- # Create new animations from specific frames and stuff them into easy to access hash
39
- @animations = {}
40
- @animations[:scan] = @full_animation[0..5]
41
- @animations[:up] = @full_animation[6..7]
42
- @animations[:down] = @full_animation[8..9]
43
- @animations[:left] = @full_animation[10..11]
44
- @animations[:right] = @full_animation[12..13]
45
-
46
- # Start out by animation frames 0-5 (contained by @animations[:scan])
47
- @animation = @animations[:scan]
39
+ # Start out by animation frames 0-5 (contained by @animation[:scan])
40
+ @frame_name = :scan
48
41
 
49
42
  self.factor = $window.factor
50
43
  @last_x, @last_y = @x, @y
@@ -53,22 +46,22 @@ class Droid < Chingu::GameObject
53
46
 
54
47
  def holding_left
55
48
  @x -= 2
56
- @animation = @animations[:left]
49
+ @frame_name = :left
57
50
  end
58
51
 
59
52
  def holding_right
60
53
  @x += 2
61
- @animation = @animations[:right]
54
+ @frame_name = :right
62
55
  end
63
-
56
+
64
57
  def holding_up
65
58
  @y -= 2
66
- @animation = @animations[:up]
59
+ @frame_name = :up
67
60
  end
68
61
 
69
62
  def holding_down
70
63
  @y += 2
71
- @animation = @animations[:down]
64
+ @frame_name = :down
72
65
  end
73
66
 
74
67
  # We don't need to call super() in update().
@@ -77,14 +70,12 @@ class Droid < Chingu::GameObject
77
70
 
78
71
  # Move the animation forward by fetching the next frame and putting it into @image
79
72
  # @image is drawn by default by GameObject#draw
80
- @image = @animation.next
73
+ @image = @animation[@frame_name].next
81
74
 
82
75
  #
83
76
  # If droid stands still, use the scanning animation
84
77
  #
85
- if @x == @last_x && @y == @last_y
86
- @animation = @animations[:scan]
87
- end
78
+ @frame_name = :scan if @x == @last_x && @y == @last_y
88
79
 
89
80
  @x, @y = @last_x, @last_y if outside_window? # return to previous coordinates if outside window
90
81
  @last_x, @last_y = @x, @y # save current coordinates for possible use next time
@@ -18,7 +18,7 @@ class Game < Chingu::Window
18
18
  end
19
19
 
20
20
  class Cube < GameObject
21
- has_trait :timer
21
+ trait :timer
22
22
 
23
23
  def initialize(options)
24
24
  super
@@ -65,7 +65,7 @@ end
65
65
  # colorful pulsating text...
66
66
  #
67
67
  class PulsatingText < Text
68
- has_traits :timer, :effect
68
+ traits :timer, :effect
69
69
 
70
70
  def initialize(text, options = {})
71
71
  super(text, options)
@@ -64,11 +64,10 @@ class Game < Chingu::Window
64
64
  end
65
65
 
66
66
  class Circle < GameObject
67
- has_trait :bounding_circle, :debug => true
68
- has_traits :velocity, :collision_detection
67
+ trait :bounding_circle, :debug => true
68
+ traits :velocity, :collision_detection
69
69
 
70
- def initialize(options)
71
- super
70
+ def setup
72
71
  @image = Image["circle.png"]
73
72
  self.velocity_x = 3 - rand * 6
74
73
  self.velocity_y = 3 - rand * 6
@@ -89,11 +88,10 @@ class Circle < GameObject
89
88
  end
90
89
 
91
90
  class Box < GameObject
92
- has_trait :bounding_box, :debug => true
93
- has_traits :velocity, :collision_detection
91
+ trait :bounding_box, :debug => true
92
+ traits :velocity, :collision_detection
94
93
 
95
- def initialize(options)
96
- super
94
+ def setup
97
95
  @image = Image["rect.png"]
98
96
  self.velocity_x = 3 - rand * 6
99
97
  self.velocity_y = 3 - rand * 6
@@ -104,8 +102,6 @@ class Box < GameObject
104
102
  def update
105
103
  self.velocity_x = -self.velocity_x if @x < 0 || @x > $window.width
106
104
  self.velocity_y = -self.velocity_y if @y < 0 || @y > $window.height
107
- #@x = @x.to_i
108
- #@y = @y.to_i
109
105
  end
110
106
  end
111
107
 
@@ -16,7 +16,7 @@ class Game < Chingu::Window
16
16
  end
17
17
 
18
18
  class Stuff < GameState
19
- has_trait :timer
19
+ trait :timer
20
20
 
21
21
  def initialize(options = {})
22
22
  super
@@ -57,7 +57,7 @@ end
57
57
  # colorful pulsating text...
58
58
  #
59
59
  class PulsatingText < Text
60
- has_traits :timer, :effect
60
+ traits :timer, :effect
61
61
  @@red = Color.new(0xFFFF0000)
62
62
  @@green = Color.new(0xFF00FF00)
63
63
  @@blue = Color.new(0xFF0000FF)
@@ -38,8 +38,8 @@ class Game < Chingu::Window
38
38
  end
39
39
 
40
40
  class Player < GameObject
41
- has_trait :bounding_circle, :debug => DEBUG
42
- has_traits :collision_detection, :effect, :velocity
41
+ trait :bounding_circle, :debug => DEBUG
42
+ traits :collision_detection, :effect, :velocity
43
43
 
44
44
  def initialize(options={})
45
45
  super(options)
@@ -73,8 +73,8 @@ class Player < GameObject
73
73
  end
74
74
 
75
75
  class Star < GameObject
76
- has_trait :bounding_circle, :debug => DEBUG
77
- has_trait :collision_detection
76
+ trait :bounding_circle, :debug => DEBUG
77
+ trait :collision_detection
78
78
 
79
79
  def initialize(options={})
80
80
  super(:zorder=>1)
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.join(File.dirname($0), "..", "lib", "chingu")
4
+ include Gosu
5
+ include Chingu
6
+
7
+ #
8
+ # animation-trait example
9
+ #
10
+ class Game < Chingu::Window
11
+ def initialize
12
+ super(400, 400)
13
+ self.input = { :escape => :exit }
14
+ switch_game_state(Play)
15
+ end
16
+ end
17
+
18
+ class Play < Chingu::GameState
19
+ trait :timer
20
+
21
+ def setup
22
+ Droid.create(:x => 200, :y => 300, :factor => 4, :alpha => 100)
23
+ every(1000) { Spaceship.create(:x => 10, :y => 300, :velocity_x => 1) }
24
+ every(1000) { Plane.create(:x => 10, :y => 350, :velocity => [1,0] ) }
25
+ every(500) { FireBullet.create(:x => 10, :y => 370, :velocity_x => 1) }
26
+ every(500) { Star.create(:x => 400, :y => 400, :velocity => [-2,-rand*2]) }
27
+ #every(400) { Heli.create(:x => 10, :y => 10, :velocity_x => 1) }
28
+ end
29
+
30
+ def update
31
+ super
32
+ game_objects.select { |game_object| game_object.outside_window? }.each(&:destroy)
33
+ $window.caption = "game_objects: #{game_objects.size}"
34
+ end
35
+ end
36
+
37
+ class Actor < GameObject
38
+ trait :velocity
39
+
40
+ def setup
41
+ @image = Image["#{self.filename}.png"]
42
+ @zorder = 10
43
+ end
44
+
45
+ end
46
+
47
+ class Spaceship < Actor; end # spaceship.png will be loaded
48
+ class Plane < Actor; end # plane.png will be loaded
49
+ class FireBullet < Actor; end # fire_bullet.png will be loaded
50
+
51
+ #
52
+ # droid_11x16.png will be loaded and animated with :delay parameter, each frame beeing 11 x 16 pixels
53
+ #
54
+ class Droid < Actor
55
+ trait :animation, :delay => 200
56
+
57
+ def update
58
+ @image = self.animation.next if self.animation
59
+ end
60
+ end
61
+
62
+ #
63
+ # heli.png will be loaded
64
+ # since it doesn't contain any framesize information, chingu will assume same width and height
65
+ #
66
+ class Heli < Actor
67
+ trait :animation, :delay => 200
68
+
69
+ def update
70
+ @image = self.animation.next if self.animation
71
+ p self.animation
72
+ end
73
+ end
74
+
75
+ #
76
+ # star_25x25_default.png and star_25x25_explode.png will be loaded.
77
+ # Access the 2 animation-"states" with self.animations[:default] and self.animations[:explode]
78
+ # self.animation will point to self.animations[:default]
79
+ #
80
+ class Star < Actor
81
+ trait :animation, :delay => 100
82
+
83
+ def setup
84
+ self.animations[:explode].loop = false
85
+ end
86
+
87
+ def update
88
+
89
+ if @x < $window.width/2 || @y < $window.height/2
90
+ @image = self.animations[:explode].next
91
+ else
92
+ @image = self.animations[:default].next
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ Game.new.show
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.join(File.dirname($0), "..", "lib", "chingu")
4
+ include Gosu
5
+ include Chingu
6
+
7
+ #
8
+ # viewport-trait / edit-trait example
9
+ #
10
+ # Press 'E' when demo is running to edit the playfield!
11
+ #
12
+ class Game < Chingu::Window
13
+ def setup
14
+ Gosu::enable_undocumented_retrofication
15
+ self.factor = 3
16
+ #self.input = { :escape => :exit }
17
+ switch_game_state(Level.new)
18
+ end
19
+ end
20
+
21
+ class Level < GameState
22
+ #
23
+ # This adds accessor 'viewport' to class and overrides draw() to use it.
24
+ #
25
+ trait :viewport
26
+
27
+ #
28
+ # We create our 3 different game objects in this order:
29
+ # 1) map 2) stars 3) player
30
+ # Since we don't give any zorders Chingu automatically increments zorder between each object created, putting player on top
31
+ #
32
+ def setup
33
+ self.input = { :escape => :exit, :e => :edit }
34
+
35
+ Sound["laser.wav"] # cache sound by accessing it once
36
+
37
+ self.viewport.lag = 0 # 0 = no lag, 0.99 = a lot of lag.
38
+ self.viewport.game_area = [0, 0, 1000, 1000] # Viewport restrictions, full "game world/map/area"
39
+
40
+ #
41
+ # Create 40 stars scattered around the map. This is now replaced by load_game_objects()
42
+ # ## 40.times { |nr| Star.create(:x => rand * self.viewport.x_max, :y => rand * self.viewport.y_max) }
43
+ #
44
+ load_game_objects( :file => "example19_game_objects.yml" )
45
+
46
+ # Create our mechanic star-hunter
47
+ @droid = Droid.create(:x => 100, :y => 100)
48
+ end
49
+
50
+ def edit
51
+ push_game_state(GameStates::Edit.new(:file => "example19_game_objects.yml", :classes => [Star, StoneWall]))
52
+ end
53
+
54
+ def update
55
+ super
56
+
57
+ # Droid can pick up starts
58
+ @droid.each_collision(Star) do |droid, star|
59
+ star.destroy
60
+ Sound["laser.wav"].play(0.5)
61
+ end
62
+
63
+ # Bullets collide with stone_walls
64
+ Bullet.each_collision(StoneWall) do |bullet, stone_wall|
65
+ bullet.die
66
+ stone_wall.destroy
67
+ end
68
+
69
+ # Destroy game objects that travels outside the viewport
70
+ game_objects.destroy_if { |game_object| self.viewport.outside_game_area?(game_object) }
71
+
72
+ #
73
+ # Align viewport with the droid in the middle.
74
+ # This will make droid will be in the center of the screen all the time...
75
+ # ...except when hitting outer borders and viewport x_min/max & y_min/max kicks in.
76
+ #
77
+ self.viewport.center_around(@droid)
78
+
79
+ $window.caption = "viewport/edit-trait example. Move with arrows! Press 'E' to Edit. x/y: #{@droid.x.to_i}/#{@droid.y.to_i} - viewport x/y: #{self.viewport.x.to_i}/#{self.viewport.y.to_i} - FPS: #{$window.fps}"
80
+ end
81
+ end
82
+
83
+ class Droid < Chingu::GameObject
84
+ trait :bounding_box, :debug => false
85
+ traits :timer, :collision_detection , :timer
86
+ attr_accessor :last_x, :last_y, :direction
87
+
88
+ def setup
89
+ #
90
+ # This shows up the shortened version of input-maps, where each key calls a method of the very same name.
91
+ # Use this by giving an array of symbols to self.input
92
+ #
93
+ self.input = { [:holding_left, :holding_a] => :holding_left,
94
+ [:holding_right, :holding_d] => :holding_right,
95
+ [:holding_up, :holding_w] => :holding_up,
96
+ [:holding_down, :holding_s] => :holding_down,
97
+ :space => :fire
98
+ }
99
+
100
+ # Load the full animation from tile-file media/droid.bmp
101
+ @animations = Chingu::Animation.new(:file => "droid_11x15.bmp")
102
+ @animations.frame_names = { :scan => 0..5, :up => 6..7, :down => 8..9, :left => 10..11, :right => 12..13 }
103
+
104
+ # Start out by animation frames 0-5 (contained by @animations[:scan])
105
+ @animation = @animations[:scan]
106
+ @speed = 3
107
+ @last_x, @last_y = @x, @y
108
+
109
+ update
110
+ end
111
+
112
+ def holding_left
113
+ move(-@speed, 0)
114
+ @animation = @animations[:left]
115
+ end
116
+
117
+ def holding_right
118
+ move(@speed, 0)
119
+ @animation = @animations[:right]
120
+ end
121
+
122
+ def holding_up
123
+ move(0, -@speed)
124
+ @animation = @animations[:up]
125
+ end
126
+
127
+ def holding_down
128
+ move(0, @speed)
129
+ @animation = @animations[:down]
130
+ end
131
+
132
+ def fire
133
+ Bullet.create(:x => self.x, :y => self.y, :velocity => @direction)
134
+ end
135
+
136
+ #
137
+ # Revert player to last positions when:
138
+ # - player is outside the viewport
139
+ # - player is colliding with at least one object of class StoneWall
140
+ #
141
+ def move(x,y)
142
+ @x += x
143
+ @x = @last_x if self.parent.viewport.outside_game_area?(self) || self.first_collision(StoneWall)
144
+
145
+ @y += y
146
+ @y = @last_y if self.parent.viewport.outside_game_area?(self) || self.first_collision(StoneWall)
147
+ end
148
+
149
+ # We don't need to call super() in update().
150
+ # By default GameObject#update is empty since it doesn't contain any gamelogic to speak of.
151
+ def update
152
+
153
+ # Move the animation forward by fetching the next frame and putting it into @image
154
+ # @image is drawn by default by GameObject#draw
155
+ @image = @animation.next
156
+
157
+ if @x == @last_x && @y == @last_y
158
+ # droid stands still, use the scanning animation
159
+ @animation = @animations[:scan]
160
+ else
161
+ # Save the direction to use with bullets when firing
162
+ @direction = [@x - @last_x, @y - @last_y]
163
+ end
164
+
165
+ @last_x, @last_y = @x, @y
166
+ end
167
+ end
168
+
169
+ class Star < GameObject
170
+ trait :bounding_circle, :debug => false
171
+ trait :collision_detection
172
+
173
+ def setup
174
+ @animation = Chingu::Animation.new(:file => "Star.png", :size => 25)
175
+ @image = @animation.next
176
+ self.color = Gosu::Color.new(0xff000000)
177
+ self.color.red = rand(255 - 40) + 40
178
+ self.color.green = rand(255 - 40) + 40
179
+ self.color.blue = rand(255 - 40) + 40
180
+ self.factor = 1
181
+ #self.rotation_center = :center
182
+
183
+ #
184
+ # A cached bounding circle will not adapt to changes in size, but it will follow objects X / Y
185
+ # Same is true for "cache_bounding_box"
186
+ #
187
+ cache_bounding_circle
188
+ end
189
+
190
+ def update
191
+ # Move the animation forward by fetching the next frame and putting it into @image
192
+ # @image is drawn by default by GameObject#draw
193
+ @image = @animation.next
194
+ end
195
+ end
196
+
197
+ class StoneWall < GameObject
198
+ trait :bounding_box, :debug => false
199
+ trait :collision_detection
200
+
201
+ def setup
202
+ @image = Image["stone_wall.bmp"]
203
+ self.factor = 1
204
+ end
205
+ end
206
+
207
+ class Bullet < GameObject
208
+ traits :bounding_circle, :collision_detection, :velocity, :timer
209
+
210
+ def setup
211
+ @image = Image["fire_bullet.png"]
212
+ self.factor = 1
213
+ self.velocity_x *= 2
214
+ self.velocity_y *= 2
215
+ end
216
+
217
+ def die
218
+ self.velocity = [0,0]
219
+ between(0,50) { self.factor += 0.3; self.alpha -= 10; }.then { destroy }
220
+ end
221
+ end
222
+
223
+ Game.new.show