gosu-examples 1.0.5 → 1.0.7

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/gosu-examples +3 -5
  4. data/examples/chipmunk_and_rmagick.rb +17 -19
  5. data/examples/chipmunk_integration.rb +42 -44
  6. data/examples/cptn_ruby.rb +19 -21
  7. data/examples/opengl_integration.rb +59 -59
  8. data/examples/rmagick_integration.rb +74 -74
  9. data/examples/text_input.rb +26 -27
  10. data/examples/tutorial.rb +21 -23
  11. data/examples/welcome.rb +17 -19
  12. data/lib/gosu-examples/example.rb +18 -18
  13. data/lib/gosu-examples/sidebar.rb +14 -14
  14. metadata +9 -36
  15. data/examples/media/BrokenPNG.png +0 -0
  16. data/examples/media/Cursor.png +0 -0
  17. data/examples/media/JingleBells.mp3 +0 -0
  18. data/examples/media/JingleBells.ogg +0 -0
  19. data/examples/media/Loop.wav +0 -0
  20. data/examples/media/Sample.wav +0 -0
  21. data/examples/media/SquareTexture.png +0 -0
  22. data/examples/media/Wallpaper.png +0 -0
  23. data/examples/media/WallpaperXXL.png +0 -0
  24. data/examples/media/WhiteAlpha.png +0 -0
  25. data/examples/media/audio_formats/aiff_32bit_float.aiff +0 -0
  26. data/examples/media/audio_formats/au_16bit_pcm.au +0 -0
  27. data/examples/media/audio_formats/caf_be_16bit_44khz.caf +0 -0
  28. data/examples/media/audio_formats/caf_le_16bit_44khz.caf +0 -0
  29. data/examples/media/audio_formats/caf_le_8bit_44khz.caf +0 -0
  30. data/examples/media/audio_formats/general_midi.mid +0 -0
  31. data/examples/media/audio_formats/impulse_tracker.it +0 -0
  32. data/examples/media/audio_formats/mp3_128k_stereo.mp3 +0 -0
  33. data/examples/media/audio_formats/mp3_avg_96kbit_jointstereo.mp3 +0 -0
  34. data/examples/media/audio_formats/ogg_vorbis.ogg +0 -0
  35. data/examples/media/audio_formats/wav_16bit_pcm.wav +0 -0
  36. data/examples/media/audio_formats/wav_32bit_pcm.wav +0 -0
  37. data/examples/media/audio_formats/wav_4bit_ms_adpcm.wav +0 -0
  38. data/examples/media/image_formats/test.jpg +0 -0
  39. data/examples/media/image_formats/test.psd +0 -0
  40. data/examples/media/vera.ttf +0 -0
@@ -1,12 +1,12 @@
1
- # Encoding: UTF-8
2
-
3
1
  # The tutorial game over a landscape rendered with OpenGL.
4
2
  # Basically shows how arbitrary OpenGL calls can be put into
5
3
  # the block given to Window#gl, and that Gosu Images can be
6
4
  # used as textures using the gl_tex_info call.
7
5
 
8
6
  require "gosu"
9
- require "gl"
7
+ require "opengl"
8
+
9
+ OpenGL.load_lib
10
10
 
11
11
  WIDTH, HEIGHT = 640, 480
12
12
 
@@ -28,7 +28,7 @@ class GLBackground
28
28
  @scrolls = 0
29
29
  @height_map = Array.new(POINTS_Y) { Array.new(POINTS_X) { rand } }
30
30
  end
31
-
31
+
32
32
  def scroll
33
33
  @scrolls += 1
34
34
  if @scrolls == SCROLLS_PER_STEP
@@ -37,22 +37,22 @@ class GLBackground
37
37
  @height_map.push Array.new(POINTS_X) { rand }
38
38
  end
39
39
  end
40
-
40
+
41
41
  def draw(z)
42
42
  # gl will execute the given block in a clean OpenGL environment, then reset
43
43
  # everything so Gosu's rendering can take place again.
44
44
  Gosu.gl(z) { exec_gl }
45
45
  end
46
-
46
+
47
47
  private
48
-
49
- include Gl
50
-
48
+
49
+ include OpenGL
50
+
51
51
  def exec_gl
52
52
  glClearColor(0.0, 0.2, 0.5, 1.0)
53
53
  glClearDepth(0)
54
54
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
55
-
55
+
56
56
  # Get the name of the OpenGL texture the Image resides on, and the
57
57
  # u/v coordinates of the rect it occupies.
58
58
  # gl_tex_info can return nil if the image was too large to fit onto
@@ -61,7 +61,7 @@ class GLBackground
61
61
  return unless info
62
62
 
63
63
  # Pretty straightforward OpenGL code.
64
-
64
+
65
65
  glDepthFunc(GL_GEQUAL)
66
66
  glEnable(GL_DEPTH_TEST)
67
67
  glEnable(GL_BLEND)
@@ -72,35 +72,35 @@ class GLBackground
72
72
 
73
73
  glMatrixMode(GL_MODELVIEW)
74
74
  glLoadIdentity
75
- glTranslate(0, 0, -4)
76
-
75
+ glTranslatef(0, 0, -4)
76
+
77
77
  glEnable(GL_TEXTURE_2D)
78
78
  glBindTexture(GL_TEXTURE_2D, info.tex_name)
79
-
79
+
80
80
  offs_y = 1.0 * @scrolls / SCROLLS_PER_STEP
81
-
81
+
82
82
  0.upto(POINTS_Y - 2) do |y|
83
83
  0.upto(POINTS_X - 2) do |x|
84
84
  glBegin(GL_TRIANGLE_STRIP)
85
- z = @height_map[y][x]
86
- glColor4d(1, 1, 1, z)
87
- glTexCoord2d(info.left, info.top)
88
- glVertex3d(-0.5 + (x - 0.0) / (POINTS_X-1), -0.5 + (y - offs_y - 0.0) / (POINTS_Y-2), z)
89
-
90
- z = @height_map[y+1][x]
91
- glColor4d(1, 1, 1, z)
92
- glTexCoord2d(info.left, info.bottom)
93
- glVertex3d(-0.5 + (x - 0.0) / (POINTS_X-1), -0.5 + (y - offs_y + 1.0) / (POINTS_Y-2), z)
94
-
95
- z = @height_map[y][x + 1]
96
- glColor4d(1, 1, 1, z)
97
- glTexCoord2d(info.right, info.top)
98
- glVertex3d(-0.5 + (x + 1.0) / (POINTS_X-1), -0.5 + (y - offs_y - 0.0) / (POINTS_Y-2), z)
99
-
100
- z = @height_map[y+1][x + 1]
101
- glColor4d(1, 1, 1, z)
102
- glTexCoord2d(info.right, info.bottom)
103
- glVertex3d(-0.5 + (x + 1.0) / (POINTS_X-1), -0.5 + (y - offs_y + 1.0) / (POINTS_Y-2), z)
85
+ z = @height_map[y][x]
86
+ glColor4d(1, 1, 1, z)
87
+ glTexCoord2d(info.left, info.top)
88
+ glVertex3d(-0.5 + (x - 0.0) / (POINTS_X - 1), -0.5 + (y - offs_y - 0.0) / (POINTS_Y - 2), z)
89
+
90
+ z = @height_map[y + 1][x]
91
+ glColor4d(1, 1, 1, z)
92
+ glTexCoord2d(info.left, info.bottom)
93
+ glVertex3d(-0.5 + (x - 0.0) / (POINTS_X - 1), -0.5 + (y - offs_y + 1.0) / (POINTS_Y - 2), z)
94
+
95
+ z = @height_map[y][x + 1]
96
+ glColor4d(1, 1, 1, z)
97
+ glTexCoord2d(info.right, info.top)
98
+ glVertex3d(-0.5 + (x + 1.0) / (POINTS_X - 1), -0.5 + (y - offs_y - 0.0) / (POINTS_Y - 2), z)
99
+
100
+ z = @height_map[y + 1][x + 1]
101
+ glColor4d(1, 1, 1, z)
102
+ glTexCoord2d(info.right, info.bottom)
103
+ glVertex3d(-0.5 + (x + 1.0) / (POINTS_X - 1), -0.5 + (y - offs_y + 1.0) / (POINTS_Y - 2), z)
104
104
  glEnd
105
105
  end
106
106
  end
@@ -110,7 +110,7 @@ end
110
110
  # Roughly adapted from the tutorial game. Always faces north.
111
111
  class Player
112
112
  Speed = 7
113
-
113
+
114
114
  attr_reader :score
115
115
 
116
116
  def initialize(x, y)
@@ -123,23 +123,23 @@ class Player
123
123
  def move_left
124
124
  @x = [@x - Speed, 0].max
125
125
  end
126
-
126
+
127
127
  def move_right
128
128
  @x = [@x + Speed, WIDTH].min
129
129
  end
130
-
130
+
131
131
  def accelerate
132
132
  @y = [@y - Speed, 50].max
133
133
  end
134
-
134
+
135
135
  def brake
136
136
  @y = [@y + Speed, HEIGHT].min
137
137
  end
138
-
138
+
139
139
  def draw
140
140
  @image.draw(@x - @image.width / 2, @y - @image.height / 2, ZOrder::Player)
141
141
  end
142
-
142
+
143
143
  def collect_stars(stars)
144
144
  stars.reject! do |star|
145
145
  if Gosu.distance(@x, @y, star.x, star.y) < 35
@@ -157,7 +157,7 @@ end
157
157
  # for extra rotation coolness!
158
158
  class Star
159
159
  attr_reader :x, :y
160
-
160
+
161
161
  def initialize(animation)
162
162
  @animation = animation
163
163
  @color = Gosu::Color.new(0xff_000000)
@@ -168,11 +168,11 @@ class Star
168
168
  @y = 0
169
169
  end
170
170
 
171
- def draw
172
- img = @animation[Gosu.milliseconds / 100 % @animation.size];
171
+ def draw
172
+ img = @animation[Gosu.milliseconds / 100 % @animation.size]
173
173
  img.draw_rot(@x, @y, ZOrder::Stars, @y, 0.5, 0.5, 1, 1, @color, :add)
174
174
  end
175
-
175
+
176
176
  def update
177
177
  # Move towards bottom of screen
178
178
  @y += 3
@@ -184,40 +184,40 @@ end
184
184
  class OpenGLIntegration < (Example rescue Gosu::Window)
185
185
  def initialize
186
186
  super WIDTH, HEIGHT
187
-
187
+
188
188
  self.caption = "OpenGL Integration"
189
-
189
+
190
190
  @gl_background = GLBackground.new
191
-
191
+
192
192
  @player = Player.new(400, 500)
193
-
193
+
194
194
  @star_anim = Gosu::Image::load_tiles("media/star.png", 25, 25)
195
195
  @stars = Array.new
196
-
196
+
197
197
  @font = Gosu::Font.new(20)
198
198
  end
199
-
199
+
200
200
  def update
201
- @player.move_left if Gosu.button_down? Gosu::KB_LEFT or Gosu.button_down? Gosu::GP_LEFT
201
+ @player.move_left if Gosu.button_down? Gosu::KB_LEFT or Gosu.button_down? Gosu::GP_LEFT
202
202
  @player.move_right if Gosu.button_down? Gosu::KB_RIGHT or Gosu.button_down? Gosu::GP_RIGHT
203
- @player.accelerate if Gosu.button_down? Gosu::KB_UP or Gosu.button_down? Gosu::GP_UP
204
- @player.brake if Gosu.button_down? Gosu::KB_DOWN or Gosu.button_down? Gosu::GP_DOWN
205
-
203
+ @player.accelerate if Gosu.button_down? Gosu::KB_UP or Gosu.button_down? Gosu::GP_UP
204
+ @player.brake if Gosu.button_down? Gosu::KB_DOWN or Gosu.button_down? Gosu::GP_DOWN
205
+
206
206
  @player.collect_stars(@stars)
207
-
207
+
208
208
  @stars.reject! { |star| !star.update }
209
-
209
+
210
210
  @gl_background.scroll
211
-
211
+
212
212
  @stars.push(Star.new(@star_anim)) if rand(20) == 0
213
213
  end
214
214
 
215
215
  def draw
216
216
  @player.draw
217
217
  @stars.each { |star| star.draw }
218
- @font.draw("Score: #{@player.score}", 10, 10, ZOrder::UI, 1.0, 1.0, 0xff_ffff00)
218
+ @font.draw_text("Score: #{@player.score}", 10, 10, ZOrder::UI, 1.0, 1.0, 0xff_ffff00)
219
219
  @gl_background.draw(ZOrder::Background)
220
220
  end
221
221
  end
222
222
 
223
- OpenGLIntegration.new.show if __FILE__ == $0
223
+ OpenGLIntegration.new.show if __FILE__ == $0
@@ -1,5 +1,3 @@
1
- # Encoding: UTF-8
2
-
3
1
  # A simple Gorilla-style shooter for two players.
4
2
  # Shows how Gosu and RMagick can be used together to generate a map, implement
5
3
  # a dynamic landscape and generally look great.
@@ -35,15 +33,15 @@ class Map
35
33
  # (Seems to take a while though)
36
34
  sky = Magick::Image.read("media/landscape.svg").first
37
35
  @sky = Gosu::Image.new(sky, tileable: true)
38
-
36
+
39
37
  # Create the map an stores the RMagick image in @image
40
38
  create_rmagick_map
41
-
39
+
42
40
  # Copy the RMagick Image to a Gosu Image (still unchanged)
43
41
  @gosu_image = Gosu::Image.new(@image, tileable: true)
44
42
  end
45
-
46
- def solid? x, y
43
+
44
+ def solid?(x, y)
47
45
  # Map is open at the top.
48
46
  return false if y < 0
49
47
  # Map is closed on all other sides.
@@ -51,7 +49,7 @@ class Map
51
49
  # Inside of the map, determine solidity from the map image.
52
50
  @image.pixel_color(x, y) != NULL_PIXEL
53
51
  end
54
-
52
+
55
53
  def draw
56
54
  # Sky background.
57
55
  @sky.draw 0, 0, 0
@@ -63,41 +61,41 @@ class Map
63
61
  RADIUS = 25
64
62
  # Radius of a crater, Shadow included.
65
63
  SH_RADIUS = 45
66
-
64
+
67
65
  # Create the crater image (basically a circle shape that is used to erase
68
66
  # parts of the map) and the crater shadow image.
69
67
  CRATER_IMAGE = begin
70
- crater = Magick::Image.new(2 * RADIUS, 2 * RADIUS) { self.background_color = "none" }
71
- gc = Magick::Draw.new
72
- gc.fill("black").circle(RADIUS, RADIUS, RADIUS, 0)
73
- gc.draw crater
74
- crater
75
- end
68
+ crater = Magick::Image.new(2 * RADIUS, 2 * RADIUS) { self.background_color = "none" }
69
+ gc = Magick::Draw.new
70
+ gc.fill("black").circle(RADIUS, RADIUS, RADIUS, 0)
71
+ gc.draw crater
72
+ crater
73
+ end
76
74
  CRATER_SHADOW = CRATER_IMAGE.shadow(0, 0, (SH_RADIUS - RADIUS) / 2, 1)
77
-
78
- def blast x, y
75
+
76
+ def blast(x, y)
79
77
  # Draw the shadow (twice for more intensity), then erase a circle from the map.
80
78
  @image.composite! CRATER_SHADOW, x - SH_RADIUS, y - SH_RADIUS, Magick::AtopCompositeOp
81
79
  @image.composite! CRATER_SHADOW, x - SH_RADIUS, y - SH_RADIUS, Magick::AtopCompositeOp
82
- @image.composite! CRATER_IMAGE, x - RADIUS, y - RADIUS, Magick::DstOutCompositeOp
83
-
80
+ @image.composite! CRATER_IMAGE, x - RADIUS, y - RADIUS, Magick::DstOutCompositeOp
81
+
84
82
  # Isolate the affected portion of the RMagick image.
85
83
  dirty_portion = @image.crop(x - SH_RADIUS, y - SH_RADIUS, SH_RADIUS * 2, SH_RADIUS * 2)
86
84
  # Overwrite this part of the Gosu image. If the crater begins outside of the map, still
87
85
  # just update the inner part.
88
86
  @gosu_image.insert dirty_portion, [x - SH_RADIUS, 0].max, [y - SH_RADIUS, 0].max
89
87
  end
90
-
88
+
91
89
  private
92
-
90
+
93
91
  def create_rmagick_map
94
92
  # This is the one large RMagick image that represents the map.
95
93
  @image = Magick::Image.new(WIDTH, HEIGHT) { self.background_color = "none" }
96
-
94
+
97
95
  # Set up a Draw object that fills with an earth texture.
98
96
  earth = Magick::Image.read("media/earth.png").first.resize(1.5)
99
97
  gc = Magick::Draw.new
100
- gc.pattern("earth", 0, 0, earth.columns, earth.rows) { gc.composite(0, 0, 0, 0, earth) }
98
+ gc.pattern("earth", 0, 0, earth.columns, earth.rows) { gc.composite(0, 0, 0, 0, earth) }
101
99
  gc.fill("earth")
102
100
  gc.stroke("#603000").stroke_width(1.5)
103
101
  # Draw a smooth bezier island onto the map!
@@ -108,7 +106,7 @@ class Map
108
106
  polypoints += [WIDTH, HEIGHT]
109
107
  gc.bezier(*polypoints)
110
108
  gc.draw(@image)
111
-
109
+
112
110
  # Create a bright-dark gradient fill, an image from it and change the map's
113
111
  # brightness with it.
114
112
  fill = Magick::GradientFill.new(0, HEIGHT * 0.4, WIDTH, HEIGHT * 0.4, "#fff", "#666")
@@ -121,7 +119,7 @@ class Map
121
119
  star_y = 0
122
120
  star_y += 20 until solid?(WIDTH / 2, star_y)
123
121
  @image.composite!(star, (WIDTH - star.columns) / 2, star_y - star.rows * 0.85,
124
- Magick::DstOverCompositeOp)
122
+ Magick::DstOverCompositeOp)
125
123
  end
126
124
  end
127
125
 
@@ -131,29 +129,29 @@ end
131
129
  # draw: Draws the object (obviously)
132
130
  # update: Moves the object etc., returns false if the object is to be deleted
133
131
  # hit_by?(missile): Returns true if an object is hit by the missile, causing
134
- # it to explode on this object.
132
+ # it to explode on this object.
135
133
 
136
134
  class Player
137
135
  # Magic numbers considered harmful! This is the height of the
138
136
  # player as used for collision detection.
139
137
  HEIGHT = 14
140
-
138
+
141
139
  attr_reader :x, :y, :dead
142
-
140
+
143
141
  def initialize(window, x, y, color)
144
142
  # Only load the images once for all instances of this class.
145
143
  @@images ||= Gosu::Image.load_tiles("media/soldier.png", 40, 50)
146
-
144
+
147
145
  @window, @x, @y, @color = window, x, y, color
148
146
  @vy = 0
149
-
147
+
150
148
  # -1: left, +1: right
151
149
  @dir = -1
152
150
 
153
151
  # Aiming angle.
154
152
  @angle = 90
155
153
  end
156
-
154
+
157
155
  def draw
158
156
  if dead
159
157
  # Poor, broken soldier.
@@ -168,7 +166,7 @@ class Player
168
166
  # No: Stand around (boring).
169
167
  frame = 0
170
168
  end
171
-
169
+
172
170
  # Draw feet, then chest.
173
171
  @@images[frame].draw(x - 10 * @dir, y - 20, 0, @dir * 0.5, 0.5, @color)
174
172
  angle = @angle
@@ -176,14 +174,14 @@ class Player
176
174
  @@images[2].draw_rot(x, y - 5, 0, angle, 1, 0.5, 0.5, @dir * 0.5, @color)
177
175
  end
178
176
  end
179
-
177
+
180
178
  def update
181
179
  # First, assume that no walking happened this frame.
182
180
  @show_walk_anim = false
183
-
181
+
184
182
  # Gravity.
185
183
  @vy += 1
186
-
184
+
187
185
  if @vy > 1
188
186
  # Move upwards until hitting something.
189
187
  @vy.times do
@@ -205,19 +203,19 @@ class Player
205
203
  end
206
204
  end
207
205
  end
208
-
206
+
209
207
  # Soldiers are never deleted (they may die, but that is a different thing).
210
208
  true
211
209
  end
212
-
210
+
213
211
  def aim_up
214
212
  @angle -= 2 unless @angle < 10
215
213
  end
216
-
214
+
217
215
  def aim_down
218
216
  @angle += 2 unless @angle > 170
219
217
  end
220
-
218
+
221
219
  def try_walk(dir)
222
220
  @show_walk_anim = true
223
221
  @dir = dir
@@ -225,27 +223,27 @@ class Player
225
223
  2.times { @y -= 1 unless @window.map.solid?(x, y - HEIGHT - 1) }
226
224
  # Now move into the desired direction.
227
225
  @x += dir unless @window.map.solid?(x + dir, y) or
228
- @window.map.solid?(x + dir, y - HEIGHT)
226
+ @window.map.solid?(x + dir, y - HEIGHT)
229
227
  # To make up for unnecessary movement upwards, sink downward again.
230
228
  2.times { @y += 1 unless @window.map.solid?(x, y + 1) }
231
229
  end
232
-
230
+
233
231
  def try_jump
234
232
  @vy = -12 if @window.map.solid?(x, y + 1)
235
233
  end
236
-
234
+
237
235
  def shoot
238
236
  @window.objects << Missile.new(@window, x + 10 * @dir, y - 10, @angle * @dir)
239
237
  end
240
-
241
- def hit_by? missile
238
+
239
+ def hit_by?(missile)
242
240
  if Gosu.distance(missile.x, missile.y, x, y) < 30
243
241
  # Was hit :(
244
242
  @dead = true
245
243
  return true
246
244
  else
247
245
  return false
248
- end
246
+ end
249
247
  end
250
248
  end
251
249
 
@@ -256,14 +254,14 @@ class Missile
256
254
 
257
255
  # All missile instances use the same sound.
258
256
  EXPLOSION = Gosu::Sample.new("media/explosion.wav")
259
-
257
+
260
258
  def initialize(window, x, y, angle)
261
259
  # Horizontal/vertical velocity.
262
260
  @vx, @vy = Gosu.offset_x(angle, 20).to_i, Gosu.offset_y(angle, 20).to_i
263
-
261
+
264
262
  @window, @x, @y = window, x + @vx, y + @vy
265
263
  end
266
-
264
+
267
265
  def update
268
266
  # Movement, gravity
269
267
  @x += @vx
@@ -281,12 +279,12 @@ class Missile
281
279
  return true
282
280
  end
283
281
  end
284
-
282
+
285
283
  def draw
286
284
  # Just draw a small rectangle.
287
- Gosu.draw_rect x-2, y-2, 4, 4, 0xff_800000
285
+ Gosu.draw_rect x - 2, y - 2, 4, 4, 0xff_800000
288
286
  end
289
-
287
+
290
288
  def hit_by?(missile)
291
289
  # Missiles can't be hit by other missiles!
292
290
  false
@@ -299,24 +297,24 @@ class Particle
299
297
  def initialize(window, x, y)
300
298
  # All Particle instances use the same image
301
299
  @@image ||= Gosu::Image.new("media/smoke.png")
302
-
300
+
303
301
  @x, @y = x, y
304
302
  @color = Gosu::Color.new(255, 255, 255, 255)
305
303
  end
306
-
304
+
307
305
  def update
308
306
  @y -= 5
309
307
  @x = @x - 1 + rand(3)
310
308
  @color.alpha -= 5
311
-
309
+
312
310
  # Remove if faded completely.
313
311
  @color.alpha > 0
314
312
  end
315
-
313
+
316
314
  def draw
317
315
  @@image.draw(@x - 25, @y - 25, 0, 1, 1, @color)
318
316
  end
319
-
317
+
320
318
  def hit_by?(missile)
321
319
  # Smoke can't be hit!
322
320
  false
@@ -328,10 +326,10 @@ end
328
326
 
329
327
  class RMagickIntegration < (Example rescue Gosu::Window)
330
328
  attr_reader :map, :objects
331
-
329
+
332
330
  def initialize
333
331
  super WIDTH, HEIGHT
334
-
332
+
335
333
  self.caption = "RMagick Integration Demo"
336
334
 
337
335
  # Texts to display in the appropriate situations.
@@ -339,65 +337,67 @@ class RMagickIntegration < (Example rescue Gosu::Window)
339
337
  @player_won_messages = []
340
338
  2.times do |plr|
341
339
  @player_instructions << Gosu::Image.from_text(
342
- "It is the #{ plr == 0 ? 'green' : 'red' } toy soldier's turn.\n" +
340
+ "It is the #{plr == 0 ? "green" : "red"} toy soldier's turn.\n" +
343
341
  "(Arrow keys to walk and aim, Return to jump, Space to shoot)",
344
- 30, width: width, align: :center)
342
+ 30, width: width, align: :center,
343
+ )
345
344
  @player_won_messages << Gosu::Image.from_text(
346
- "The #{ plr == 0 ? 'green' : 'red' } toy soldier has won!",
347
- 30, width: width, align: :center)
345
+ "The #{plr == 0 ? "green" : "red"} toy soldier has won!",
346
+ 30, width: width, align: :center,
347
+ )
348
348
  end
349
349
 
350
350
  # Create everything!
351
351
  @map = Map.new
352
352
  @players = [Player.new(self, 100, 40, 0xff_308000), Player.new(self, WIDTH - 100, 40, 0xff_803000)]
353
353
  @objects = @players.dup
354
-
354
+
355
355
  # Let any player start.
356
356
  @current_player = rand(2)
357
357
  # Currently not waiting for a missile to hit something.
358
358
  @waiting = false
359
359
  end
360
-
360
+
361
361
  def draw
362
362
  # Draw the main game.
363
363
  @map.draw
364
364
  @objects.each { |o| o.draw }
365
-
365
+
366
366
  # If any text should be displayed, draw it - and add a nice black border around it
367
367
  # by drawing it four times, with a little offset in each direction.
368
-
368
+
369
369
  cur_text = @player_instructions[@current_player] if not @waiting
370
370
  cur_text = @player_won_messages[1 - @current_player] if @players[@current_player].dead
371
-
371
+
372
372
  if cur_text
373
373
  x, y = 0, 30
374
374
  cur_text.draw(x - 1, y, 0, 1, 1, 0xff_000000)
375
375
  cur_text.draw(x + 1, y, 0, 1, 1, 0xff_000000)
376
376
  cur_text.draw(x, y - 1, 0, 1, 1, 0xff_000000)
377
377
  cur_text.draw(x, y + 1, 0, 1, 1, 0xff_000000)
378
- cur_text.draw(x, y, 0, 1, 1, 0xff_ffffff)
378
+ cur_text.draw(x, y, 0, 1, 1, 0xff_ffffff)
379
379
  end
380
380
  end
381
-
381
+
382
382
  def update
383
383
  # if waiting for the next player's turn, continue to do so until the missile has
384
384
  # hit something.
385
385
  @waiting &&= !@objects.grep(Missile).empty?
386
-
387
- # Remove all objects whose update method returns false.
386
+
387
+ # Remove all objects whose update method returns false.
388
388
  @objects.reject! { |o| o.update == false }
389
389
 
390
390
  # If it's a player's turn, forward controls.
391
391
  if not @waiting and not @players[@current_player].dead
392
392
  player = @players[@current_player]
393
- player.aim_up if Gosu.button_down? Gosu::KB_UP
394
- player.aim_down if Gosu.button_down? Gosu::KB_DOWN
393
+ player.aim_up if Gosu.button_down? Gosu::KB_UP
394
+ player.aim_down if Gosu.button_down? Gosu::KB_DOWN
395
395
  player.try_walk(-1) if Gosu.button_down? Gosu::KB_LEFT
396
396
  player.try_walk(+1) if Gosu.button_down? Gosu::KB_RIGHT
397
- player.try_jump if Gosu.button_down? Gosu::KB_RETURN
397
+ player.try_jump if Gosu.button_down? Gosu::KB_RETURN
398
398
  end
399
399
  end
400
-
400
+
401
401
  def button_down(id)
402
402
  if id == Gosu::KB_SPACE and not @waiting and not @players[@current_player].dead
403
403
  # Shoot! This is handled in button_down because holding space shouldn't auto-fire.