-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathasteroids.rb
379 lines (320 loc) · 8.34 KB
/
asteroids.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# asteroids game by lljk
# have fun!
class LaserBulletThing < Shoes::Widget
attr_accessor :x, :y, :x_vec, :y_vec
def initialize(x, y)
@x = x; @y = y
@x_vec = 0; @y_vec = 0
fill lime; oval(0, 0, 5)
self.move(@x, @y)
end
end #LaserBulletThing
class FirstClassFlyingShip < Shoes::Widget
attr_accessor :center_x, :center_y, :shots, :paused
def initialize(x, y)
@paused = false
@x = x - 10; @y = y - 12
@center_x = x; @center_y = y
@shots = []
@x_vec = 0; @y_vec = 0
@start_angle = 0
@rotate_by = 0
@slot = stack fill: black, stroke: lime
@slot.move(@x, @y)
draw_ship
motion{|x, y|
unless @paused
@rads = Math.atan2(y - @center_y, x - @center_x)
degs = 270 - (@rads * (180 / Math::PI)).round(2)
@rotate_by = degs - @start_angle
@start_angle = degs
draw_ship
end
}
#put this bit in a slot, or it won't work
stack width: 700, height: 600, top: 0, left: 0 do
click{|btn, x, y|
unless @paused
shoot if btn == 1
if btn == 3
@x_vec += 1 if x > @x + 20
@x_vec -= 1 if x < @x
@y_vec +=1 if y > @y + 24
@y_vec -= 1 if y < @y
end
end
}
end
end #init
def draw_ship
@slot.clear
@slot.append{
rotate @rotate_by
@ship = shape{
move_to(10, 0)
line_to(20, 24)
line_to(10, 20)
line_to(0, 24)
line_to(10, 0)
}
}
end
def move_ship
@x += @x_vec
@y += @y_vec
@x = 0 if @x > 700; @y = 0 if @y > 600
@x = 700 if @x < 0; @y = 600 if @y < 0
@center_x = @x + 10; @center_y = @y + 12
@slot.move(@x, @y)
draw_shots unless @shots.empty?
end
def shoot
if @rads
bullet_x = ((15 * Math.cos(@rads)) + @center_x).round
bullet_y = ((15 * Math.sin(@rads)) + @center_y).round
bullet = laser_bullet_thing(bullet_x, bullet_y)
bullet.x_vec = bullet_x - @center_x
bullet.y_vec = bullet_y - @center_y
@shots << bullet
end
end
def draw_shots
@shots.each{|bullet|
bullet.x += bullet.x_vec
bullet.y += bullet.y_vec
if bullet.x < 0 || bullet.x > 695 || bullet.y < 0 || bullet.y > 595
bullet.remove
@shots.delete(bullet)
else
bullet.move(bullet.x, bullet.y)
end
}
end
end #Ship
class Asteroid < Shoes::Widget
attr_accessor :x, :y, :x_vec, :y_vec, :size, :area
def initialize(size, x, y)
@size = size
@x_vec = 0; @y_vec = 0
until @x_vec != 0
@x_vec = (30 / size).round + ((rand(5) - 2) * (rand(3) - 1))
end
until @y_vec != 0
@y_vec = (30 / size).round + ((rand(5) - 2) * (rand(3) - 1))
end
x1 = rand(size * 0.1).round + (size * 0.1); y1 = rand(size * 0.1).round + (size * 0.1)
x2 = x1 + rand(size * 0.4).round; y2 = 0
x3 = size - (rand(size * 0.1).round + (size * 0.1)); y3 = rand(size * 0.1).round + (size * 0.1)
x4 = size - (rand(size * 0.1).round + (size * 0.1)); y4 = rand(size * 0.1).round + (size * 0.1)
x5 = size; y5 = y4 + rand(size * 0.4).round
x6 = size - (rand(size * 0.1).round + (size * 0.1)); y6 = size - (rand(size * 0.1).round + (size * 0.1))
x7 = size - (rand(size * 0.1).round + (size * 0.1)); y7 = size - (rand(size * 0.1).round + (size * 0.1))
x8 = x7 - rand(size * 0.4).round; y8 = size
x9 = rand(size * 0.1).round + (size * 0.1); y9 = size - (rand(size * 0.1).round + (size * 0.1))
x10 = rand(size * 0.1).round + (size * 0.1); y10 = size - (rand(size * 0.1).round + (size * 0.1))
x11 = 0; y11 = y10 - rand(size * 0.4).round
x12 = rand(size * 0.1).round + (size * 0.1); y12 = rand(size * 0.1).round + (size * 0.1)
@slot = stack top: 30 do
shape{
fill black
stroke lime
move_to(x1, y1)
line_to(x2, y2)
line_to(x3, y3)
line_to(x4, y4)
line_to(x5, y5)
line_to(x6, y6)
line_to(x7, y7)
line_to(x8, y8)
line_to(x9, y9)
line_to(x10, y10)
line_to(x11, y11)
line_to(x12, y12)
line_to(x1, y1)
}
end
set_coords(x, y)
end
def set_coords(x, y)
x = 0 if x > 700; x = 700 if x < 0 - @size
y = 0 if y > 600; y = 600 if y < 0
@x = x; @y = y
@area = [@x..(@x + @size), @y..(@y + @size)]
self.move(@x, @y)
end
def move_asteroid
x = @x + @x_vec; y = @y + @y_vec
set_coords(x, y)
end
def check_hits(x, y)
if @area[0].include?(x) && @area[1].include?(y)
@hit = true
end
end
def hit?
@hit
end
end #Asteroid
#######################
Shoes.app width: 700, height: 630 do
background black
def init_game
@lives = 3
@score = 0
@level = 1
@rocks = []
@game_over = false
status_area = flow height: 30 do
border lime
@status_info = para " ", stroke: lime, align: "center", top: 2
end
init_level(1)
end
def init_level(level)
update_status(@lives, @score, @level)
unless @rocks.empty?
@rocks.each{|rock| rock.remove}
@rocks.clear
end
unless @level == 1 || @no_congrats
salutations = ["Hey There", "Woah", "Nice One", "Well Done", "Awesome"]
names = ["Dude", "Buddy", "Pal", "Friend", "Amigo"]
actions = ["Rocked", "Destroyed", "Annihilated", "Kicked Butt On", "Creamed"]
self.append{
@congrats = title "#{salutations[rand(5)]} #{names[rand(5)]},
You #{actions[rand(5)]} Level #{@level - 1}!
On To...", stroke: lime, align: "center", top: 100
}
timer(3){@congrats.remove}
end
self.append{
@level_info = banner "level #{@level}", stroke: lime, align: "center", top: 280
}
timer(3){
@level_info.remove
self.append{@ship = first_class_flying_ship(350, 300)}
n = @level
n.times{
self.append{@rock = asteroid(60, rand(80) - 70, rand(80) - 70)}
@rocks << @rock
}
@no_congrats = false
start_motion
}
end
def update_status(lives, level, score)
@status_info.text = "lives: #{@lives} score: #{@score} level: #{@level}"
end
def break_rock(size, x, y)
case size
when 60
self.append{@rock1 = asteroid(30, x + 25, y)}
self.append{@rock2 = asteroid(30, x -25, y)}
@rocks << @rock1 << @rock2
@score += 25
when 30
self.append{@rock1 = asteroid(15, x + 25, y)}
self.append{@rock2 = asteroid(15, x - 25, y)}
self.append{@rock3 = asteroid(15, x, y - 25)}
@rocks << @rock1 << @rock2 << @rock3
@score += 50
when 15
@score += 100
end
update_status(@lives, @score, @level)
new_level if @rocks.empty?
end
def new_level
@game_motion.stop
@level += 1
update_status(@lives, @score, @level)
@ship.remove
init_level(@level)
end
def destroy_ship
@game_motion.stop
@ship.remove
@debris = []
fill lime
50.times{
blasted_bit = oval(@ship.center_x + (rand(51) - 25), (@ship.center_y + (rand(51) - 25) + 30), 3)
@debris << blasted_bit
}
@lives -= 1
update_status(@lives, @score, @level)
if @lives == 0
game_over
else
@no_congrats = true
timer(3){
@debris.each{|bit| bit.remove}
init_level(@level)
}
end
end
def game_over
@game_over = true
sorry = stack width: 700 do
banner "GAME OVER", stroke: lime, align: "center"
title "press space to restart", stroke: lime, align: "center"
end
sorry.move(0, 200)
keypress{|key|
if key == " " && @game_over
clear
init_game
end
}
end
def start_motion
@game_motion = animate(16){
@ship.move_ship
@rocks.each{|rock|
rock.move_asteroid
rock.check_hits(@ship.center_x, @ship.center_y)
if rock.hit?
destroy_ship
end
}
unless @ship.shots.empty?
@ship.shots.each{|bullet|
@rocks.each{|rock|
rock.check_hits(bullet.x, bullet.y)
if rock.hit?
@rocks.delete(rock); rock.remove
@ship.shots.delete(bullet); bullet.remove
break_rock(rock.size, rock.x, rock.y)
end
}
}
end
}
end
@first_run = true
intro = stack width: 700 do
banner "ASTEROIDS!\n", stroke: lime, align: "center"
para "move mouse to rotate ship", stroke: lime, align: "center"
para "use right mouse button to accelerate towards the pointer", stroke: lime, align: "center"
para "use left mouse button to shoot\n\n", stroke: lime, align: "center"
title "press space to start and pause", stroke: lime, align: "center"
end
intro.move(0, 100)
keypress{|key|
if key == " "
if @first_run
clear
init_game
@first_run = false
elsif @paused
@pause_message.remove
@game_motion.start; @paused = false; @ship.paused = false
else
@game_motion.stop; @paused = true; @ship.paused = true
@pause_message = stack width: 700 do
title "paused", stroke: lime, align: "center"
end
@pause_message.move(0, 200)
end
end
}
end