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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/bin/gosu-examples +3 -5
- data/examples/chipmunk_and_rmagick.rb +17 -19
- data/examples/chipmunk_integration.rb +42 -44
- data/examples/cptn_ruby.rb +19 -21
- data/examples/opengl_integration.rb +59 -59
- data/examples/rmagick_integration.rb +74 -74
- data/examples/text_input.rb +26 -27
- data/examples/tutorial.rb +21 -23
- data/examples/welcome.rb +17 -19
- data/lib/gosu-examples/example.rb +18 -18
- data/lib/gosu-examples/sidebar.rb +14 -14
- metadata +9 -36
- data/examples/media/BrokenPNG.png +0 -0
- data/examples/media/Cursor.png +0 -0
- data/examples/media/JingleBells.mp3 +0 -0
- data/examples/media/JingleBells.ogg +0 -0
- data/examples/media/Loop.wav +0 -0
- data/examples/media/Sample.wav +0 -0
- data/examples/media/SquareTexture.png +0 -0
- data/examples/media/Wallpaper.png +0 -0
- data/examples/media/WallpaperXXL.png +0 -0
- data/examples/media/WhiteAlpha.png +0 -0
- data/examples/media/audio_formats/aiff_32bit_float.aiff +0 -0
- data/examples/media/audio_formats/au_16bit_pcm.au +0 -0
- data/examples/media/audio_formats/caf_be_16bit_44khz.caf +0 -0
- data/examples/media/audio_formats/caf_le_16bit_44khz.caf +0 -0
- data/examples/media/audio_formats/caf_le_8bit_44khz.caf +0 -0
- data/examples/media/audio_formats/general_midi.mid +0 -0
- data/examples/media/audio_formats/impulse_tracker.it +0 -0
- data/examples/media/audio_formats/mp3_128k_stereo.mp3 +0 -0
- data/examples/media/audio_formats/mp3_avg_96kbit_jointstereo.mp3 +0 -0
- data/examples/media/audio_formats/ogg_vorbis.ogg +0 -0
- data/examples/media/audio_formats/wav_16bit_pcm.wav +0 -0
- data/examples/media/audio_formats/wav_32bit_pcm.wav +0 -0
- data/examples/media/audio_formats/wav_4bit_ms_adpcm.wav +0 -0
- data/examples/media/image_formats/test.jpg +0 -0
- data/examples/media/image_formats/test.psd +0 -0
- 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 "
|
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
|
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
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
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
|
204
|
-
@player.brake
|
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.
|
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?
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
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,
|
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
|
-
|
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?
|
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 #{
|
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 #{
|
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,
|
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
|
394
|
-
player.aim_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
|
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.
|