chingu 0.7.0 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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