Rice Rock

先翻译评分要点,然后一点点翻译程序实现过程

如何产生一堆岩石?
rock_group = set([])#空集合,全局变量
 
rock_group.add(a_rock)
要画出来draw handler?
用rock_group代替a_rock,因为要产生一组岩石,有很多a_rock,代替哪一个呢?
在draw handler里面我用:
for n in rock_group:
    n.draw(canvea)
可以产生一堆岩石了,但是岩石后来就不转了,而且岩石数目一直增加-------用timer.stop()解决了
 process_sprite_group
看论坛,找到了答案
 
现在做撞击,看论坛,找到了答案。
如何产生一组导弹,岩石碰撞后不能再生
已经可以产生一组导弹了,但是导弹寿命要调整
碰撞后岩石消失,但是分数没有增加,岩石消失不再出现
分数已经增加啦,这个我自己做出来的
 
如何生成的导弹不碰到飞船
完成啦啦啦

Mini-project description - RiceRocks (Asteroids)

 

开发过程

 要有多重火箭和多重导弹。飞船撞到岩石会丢一条命, 导弹打到岩石得一分, 你要更新得分和生命情况,在合适的时候结束游戏。 .当发生碰撞的时候你可以选择添加爆炸动画

Tip #1 - Spawning rocks多重岩石

为了控制多重岩石,用rock_group代替 a_rock.在rock_spawner里面,你应该产生一个本地的a_rock的副本并添加到全局集合rock_group里面。 为了避免超过12个岩石,你可以使用一个基于rock_group长度的测试。 为了测试你的代码,你可以添加一个for循环到draw handler里面以这种形式: 对每个在rock_group里面的岩石, 画出那个岩石。这个draw以后将被放到 process_sprite_group里面在第一部分的最后一步

Phase one -  多重岩石

 

  1. 用rock_group代替a_rock.复位岩石组成空的集合set. 你的rock spawner产生一个新岩石(Sprite的一个对象实例) 并添加到rock_group里面
  2.  修改你的rock spawner使得屏幕里面的岩石数量有上限。我们建议最多12个太多岩石的话游戏会不那么好玩而且动画会明显变慢。
  3. 建立一个process_sprite_group函数. 这个函数应该有一个集合(set)和画布, 并调用update和draw函数对每个群组里面的sprite.
  4. 在draw handler里面调用process_sprite_group功能在rock_group里面
Phase two - 撞击

这部分,你要检测飞船和岩石的撞击。 发生撞击,岩石要毁坏并且玩家要丢失生命.  为了完成飞船岩石撞击:你要这么做:

  1. 在Sprite类里面添加一个collide功能。 这个应该有个other_object并返回True,如果有撞击返回False.  目前,这个其他对象将一直是你的飞船, 但我们也想要能用这个colide方法来侦测跟导弹的撞击。  可以使用这两个对象的半径侦测撞击。这需要你完成 get_position和get_radius在Sprite和get_radius.
  2. 完成group_collide函数。这个函数要有个set group和一个sprit other_object并经检查在other_object和group里的元素的撞击。如果有撞击, 撞击对象应该从group里面移除。为了避免移除你正在迭代的set(可能产生一个严重的bug), 通过 set(group)创建一个副本迭代. 这个函数应该返回 True或者False取决于是否有撞击。确定使用第一部分的collide方法 在sprites在group里面来完成这个任务。
  3. 在draw handler里面使用group_collide判定是否飞船撞击到岩石.要是这样,减少一条生命值。 现在你可以有负的生命值
现在你可以玩这个躲避岩石的游戏了。

Phase three - 导弹

在这部分你要产生一个导弹组,在按空格的时候产生新的导弹加入导弹组里面。需要如下步骤:

  1. 删掉a_missile并用missile_group代替。 复位导弹组为空组。修改my_ship里面的shoot函数来创造新导弹。 (一个Sprite类里面的实例) 并添加到missile_group里面. , 如果你用模板的代码,每次生产导弹的时候开火的声音应该自动播放
  2. 在draw handler里面,使用你的process_sprite_group函数来process  missile_group. 当你发射导弹的时候,你会注意到他们永远在飞。 为了修正这个,我们需要修改Sprite类和process_sprite_group.
  3. 在Sprite类里面的update函数。每次调用 update,sprite要增加。如果寿命大于或者等于sprite的生命,我们要删掉它。. 所以return返回False (意味着我们要保留它) 如果age少于寿命并且True(意味着我们要删掉它) 否则.
  4. 修改process_sprite_group来检查返回的值对sprites. 如果返回 True, 从group里面删掉sprite。再一次 你将希望迭代sprite群的副本在process_sprite_group.来避免删掉从相同的set在你迭代的。
Phase four - Collisions revisited  现在当导弹撞到岩石的时候要毁掉岩石。我们不能用group_collide,  因为我要检查两个group的碰撞。我们要做的就是加一个新的函数 :
  1.  完成最后一个函数group_group_collide ,啥呢,将两个grops的对象作为输入.   group_group_collide应该使用一个for循环在第一组副本元素迭代,然后第二组的所有元素调用group_collide.group_group_collide应该返回第一组元素跟第二在元素撞击并删除第一组中的这些元素。 你可能会发现set的discard 功能在这里很有用。
  2. 在draw handler里面调用 group_group_collide来检测导弹/岩石的碰撞。 根据导弹撞击的数目增加分数。
Phase five - Finish it off完成它

基本完了,再添加一点

  1. 添加代码到draw handler里面 , 要是生命数变成0了,游戏重置,并且出现启动画面.尤其, set the 设置startedFalse, 毁掉所有岩石并阻止任何岩石生成,直到游戏重新开始。
  2. 当游戏开始/重新开始. 确保生命数和分数也重置。开始生成岩石 .播放/重新开始加载在程序模板的soundtrack变量里面背景音乐
  3. 当你生成岩石的时候,你想让他们跟你的飞船有一定距离,否则岩石在你头上生成的时候你就挂了。.那就不好玩了.一个简单的方法来实现这个效果是这样的:如果生的岩石跟飞船太近,忽视岩石生产事件。
  4. 试着根据分数变化岩石的速度来将游戏难度提高
  5. 调整一些参数,以使游戏按我们的想法运行

额外的

 

  1. ,在Sprite类的draw功能里面,检查 self.animated是否是True .如果是的话根据age选择正确的碎片.图片是平铺的.如果self.animated是 False,应该像以前一样画sprite.
  2. 创建一个 explosion_group,全局变量并复位它成为一个空集合。
  3. 在group_collide里面,如果有碰撞,创建一个新的爆炸(一个Sprite类的实例)并添加到explosion_group里面,确认每个爆炸都播放爆炸声音。
  4. 在draw handler里面使用process_sprite_group表达explosion_group.

Grading rubric - 13 pts (scaled to 100 pts)


  • 1 pt - 程序产生很多岩石。
  • 1 pt - 程序正确的判定飞船是否跟岩石相撞
  • 1 pt - 飞船与岩石相撞,该岩石会消失
  • 1 pt - 飞船撞上岩石生命丢失一条
  • 1 pt - 程序产生多重导弹
  • 1 pt - 发射导弹的时候播放导弹发射声音
  • 1 pt - 如果导弹没有击中岩石,导弹在固定的时间后会消失
  • 1 pt - 程序可以正确的判定导弹和岩石是否碰撞
  • 1 pt - 相互碰撞的导弹和岩石会消失
  • 1 pt - 导弹岩石相撞分数要更新
  • 1 pt - 当生命数变成0,显示启动画面并且所有的岩石要消失
  • 1 pt - 当点击启动画面,生命重置为3,分数重置为0,并启动背景音乐。
  • 1 pt - 游戏只有在启动画面不存在还有游戏正在进行的时候产生岩石。
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
# implementation of Spaceship - program template for RiceRocks
import simplegui
import math
import random
 
# globals for user interface
WIDTH = 800
HEIGHT = 600
score = 0
lives = 3
time = 0
started = False
zjcs = 0
 
class ImageInfo:
    def __init__(self, center, size, radius = 0, lifespan = None, animated = False):
        self.center = center
        self.size = size
        self.radius = radius
        if lifespan:
            self.lifespan = lifespan
        else:
            self.lifespan = float('inf')
        self.animated = animated
 
    def get_center(self):
        return self.center
 
    def get_size(self):
        return self.size
 
    def get_radius(self):
        return self.radius
 
    def get_lifespan(self):
        return self.lifespan
 
    def get_animated(self):
        return self.animated
 
     
# art assets created by Kim Lathrop, may be freely re-used in non-commercial projects, please credit Kim
     
# debris images - debris1_brown.png, debris2_brown.png, debris3_brown.png, debris4_brown.png
#                 debris1_blue.png, debris2_blue.png, debris3_blue.png, debris4_blue.png, debris_blend.png
debris_info = ImageInfo([320, 240], [640, 480])
debris_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/debris2_blue.png")
 
# nebula images - nebula_brown.png, nebula_blue.png
nebula_info = ImageInfo([400, 300], [800, 600])
nebula_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/nebula_blue.f2014.png")
 
# splash image
splash_info = ImageInfo([200, 150], [400, 300])
splash_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/splash.png")
 
# ship image
ship_info = ImageInfo([45, 45], [90, 90], 35)
ship_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/double_ship.png")
 
# missile image - shot1.png, shot2.png, shot3.png
missile_info = ImageInfo([5,5], [10, 10], 3, 50)
missile_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/shot2.png")
 
# asteroid images - asteroid_blue.png, asteroid_brown.png, asteroid_blend.png
asteroid_info = ImageInfo([45, 45], [90, 90], 40)
asteroid_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/asteroid_blue.png")
 
# animated explosion - explosion_orange.png, explosion_blue.png, explosion_blue2.png, explosion_alpha.png
explosion_info = ImageInfo([64, 64], [128, 128], 17, 24, True)
explosion_image = simplegui.load_image("http://commondatastorage.googleapis.com/codeskulptor-assets/lathrop/explosion_alpha.png")
 
# sound assets purchased from sounddogs.com, please do not redistribute
# .ogg versions of sounds are also available, just replace .mp3 by .ogg
soundtrack = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/soundtrack.mp3")
missile_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/missile.mp3")
missile_sound.set_volume(.5)
ship_thrust_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/thrust.mp3")
explosion_sound = simplegui.load_sound("http://commondatastorage.googleapis.com/codeskulptor-assets/sounddogs/explosion.mp3")
 
# helper functions to handle transformations
def angle_to_vector(ang):
    return [math.cos(ang), math.sin(ang)]
 
def dist(p, q):
    return math.sqrt((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2)
 
 
# Ship class
class Ship:
 
    def __init__(self, pos, vel, angle, image, info):
        self.pos = [pos[0], pos[1]]
        self.vel = [vel[0], vel[1]]
        self.thrust = False
        self.angle = angle
        self.angle_vel = 0
        self.image = image
        self.image_center = info.get_center()
        self.image_size = info.get_size()
        self.radius = info.get_radius()
         
    def draw(self,canvas):
        if self.thrust:
            canvas.draw_image(self.image, [self.image_center[0] + self.image_size[0], self.image_center[1]] , self.image_size,
                              self.pos, self.image_size, self.angle)
        else:
            canvas.draw_image(self.image, self.image_center, self.image_size,
                              self.pos, self.image_size, self.angle)
        # canvas.draw_circle(self.pos, self.radius, 1, "White", "White")
 
    def update(self):
        # update angle
        self.angle += self.angle_vel
         
        # update position
        self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH
        self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT
 
        # update velocity
        if self.thrust:
            acc = angle_to_vector(self.angle)
            self.vel[0] += acc[0] * .1
            self.vel[1] += acc[1] * .1
             
        self.vel[0] *= .99
        self.vel[1] *= .99
 
    def set_thrust(self, on):
        self.thrust = on
        if on:
            ship_thrust_sound.rewind()
            ship_thrust_sound.play()
        else:
            ship_thrust_sound.pause()
        
    def increment_angle_vel(self):
        self.angle_vel += .05
         
    def decrement_angle_vel(self):
        self.angle_vel -= .05
         
    def shoot(self):
        global a_missile, missile_group
        forward = angle_to_vector(self.angle)
        missile_pos = [self.pos[0] + self.radius * forward[0], self.pos[1] + self.radius * forward[1]]
        missile_vel = [self.vel[0] + 6 * forward[0], self.vel[1] + 6 * forward[1]]
        a_missile = Sprite(missile_pos, missile_vel, self.angle, 0, missile_image, missile_info, missile_sound)
        missile_group.add(a_missile)
    def get_position(self):
        return self.pos 
    def get_radius(self):
        return self.radius
     
     
# Sprite class
class Sprite:
    def __init__(self, pos, vel, ang, ang_vel, image, info, sound = None):
        self.pos = [pos[0],pos[1]]
        self.vel = [vel[0],vel[1]]
        self.angle = ang
        self.angle_vel = ang_vel
        self.image = image
        self.image_center = info.get_center()
        self.image_size = info.get_size()
        self.radius = info.get_radius()
        self.lifespan = info.get_lifespan()
        self.animated = info.get_animated()
        self.age = 0
        if sound:
            sound.rewind()
            sound.play()
    
    def draw(self, canvas):
        canvas.draw_image(self.image, self.image_center, self.image_size,
                          self.pos, self.image_size, self.angle)
 
    def update(self):
        # update angle
        self.angle += self.angle_vel
         
        # update position
        self.pos[0] = (self.pos[0] + self.vel[0]) % WIDTH
        self.pos[1] = (self.pos[1] + self.vel[1]) % HEIGHT
        self.age += 1
        if self.age < self.lifespan:
            return False
        else:
            return True
         
    def get_position(self):
        return self.pos 
    def get_radius(self):
        return self.radius
         
    def collide(self, other_object):
 
        if dist(self.pos, other_object.get_position()) <= self.radius + other_object.get_radius():
            return True
        else:
            return False
  #参考https://class.coursera.org/interactivepython-005/forum/thread?thread_id=5328
 
def group_collide(group, other_object):
    global collided
    collided = False
    group_copy = list(group)
    for item in group_copy:
        if item.collide(other_object) == True:
            collided = True
            group.discard(item)
            return collided
     
def group_group_collide(group1, group2):
    global zjcs
    group1_copy = list(group1)
    for i in group1_copy:
        if group_collide(group2, i) == True:
            group1.discard(i)
            zjcs += 1
            return True
     
# key handlers to control ship  
def keydown(key):
    if key == simplegui.KEY_MAP['left']:
        my_ship.decrement_angle_vel()
    elif key == simplegui.KEY_MAP['right']:
        my_ship.increment_angle_vel()
    elif key == simplegui.KEY_MAP['up']:
        my_ship.set_thrust(True)
    elif key == simplegui.KEY_MAP['space']:
        my_ship.shoot()
         
def keyup(key):
    if key == simplegui.KEY_MAP['left']:
        my_ship.increment_angle_vel()
    elif key == simplegui.KEY_MAP['right']:
        my_ship.decrement_angle_vel()
    elif key == simplegui.KEY_MAP['up']:
        my_ship.set_thrust(False)
 
     
         
# mouseclick handlers that reset UI and conditions whether splash image is drawn
def click(pos):
    timer.start()
    global started
    center = [WIDTH / 2, HEIGHT / 2]
    size = splash_info.get_size()
    inwidth = (center[0] - size[0] / 2) < pos[0] < (center[0] + size[0] / 2)
    inheight = (center[1] - size[1] / 2) < pos[1] < (center[1] + size[1] / 2)
    if (not started) and inwidth and inheight:
        started = True
        soundtrack.rewind()
        soundtrack.play()   
 
def draw(canvas):
    global time, started, lives, score, zjcs, rock_group
     
    # animiate background
    time += 1
    wtime = (time / 4) % WIDTH
    center = debris_info.get_center()
    size = debris_info.get_size()
    canvas.draw_image(nebula_image, nebula_info.get_center(), nebula_info.get_size(), [WIDTH / 2, HEIGHT / 2], [WIDTH, HEIGHT])
    canvas.draw_image(debris_image, center, size, (wtime - WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT))
    canvas.draw_image(debris_image, center, size, (wtime + WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT))
 
    # draw UI
    canvas.draw_text("Lives", [50, 50], 22, "White")
    canvas.draw_text("Score", [680, 50], 22, "White")
    if group_collide(rock_group, my_ship) == True:
        lives -= 1
        if lives < 1:
            started = False
            lives = 3
            score = 0
            zjcs = 0
            rock_group = set([])
            timer.stop()
        #number -= 1
    #canvas.draw_text(str(lives), [50, 80], 22, "White")
    #canvas.draw_text(str(score), [680, 80], 22, "White")
    if group_group_collide(missile_group, rock_group) == True:
        score = zjcs * 10
 
    # draw ship and sprites
    my_ship.draw(canvas)
    #a_rock.draw(canvas)
    process_sprite_group(canvas,rock_group)
    process_sprite_group(canvas,missile_group)
    #for n in rock_group:
     #   n.draw(canvas)
    #a_missile.draw(canvas)注释掉这一行,导弹就不是一直存在了
     
    # update ship and sprites
    my_ship.update()
    #a_rock.update()?????????????
    #a_missile.update()
 
    # draw splash screen if not started
    if not started:
        canvas.draw_image(splash_image, splash_info.get_center(),
                          splash_info.get_size(), [WIDTH / 2, HEIGHT / 2],
                          splash_info.get_size())
    canvas.draw_text("Lives", [50, 50], 22, "White")
    canvas.draw_text("Score", [680, 50], 22, "White")       
    canvas.draw_text(str(lives), [50, 80], 22, "White")#放下面,可以一直在上面显示
    canvas.draw_text(str(score), [680, 80], 22, "White")
 
# timer handler that spawns a rock   
def rock_spawner():
    global a_rock, rock_group, zjcs
    rock_pos = [random.randrange(0, WIDTH), random.randrange(0, HEIGHT)]
     
    rock_vel = [random.random() * .6 - .3, random.random() * .6 - .3]
    if zjcs > 5:#得分超过5,速度加快
        rock_vel = [random.random() * 6 - .3, random.random() * 6 - .3]
    rock_avel = random.random() * .2 - .1
    a_rock = Sprite(rock_pos, rock_vel, 0, rock_avel, asteroid_image, asteroid_info)
    #rock_group.add(a_rock)
    if len(rock_group) < 13 and dist(rock_pos, my_ship.pos) > 150:
        rock_group.add(a_rock)
         
     
 
def process_sprite_group(canvas, group):
    #if a_missile.update == True:
        #missile_group.remove(a_missile)
    for m in list(group):
        #m.update()
        if m.update() == True:
            missile_group.remove(m)
        m.draw(canvas)
         
         
             
# initialize stuff
frame = simplegui.create_frame("Asteroids", WIDTH, HEIGHT)
 
# initialize ship and two sprites
my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info)
a_rock = Sprite([WIDTH / 3, HEIGHT / 3], [1, 1], 0, .1, asteroid_image, asteroid_info)
rock_group = set([])
 
     
 
a_missile = Sprite([2 * WIDTH / 3, 2 * HEIGHT / 3], [-1,1], 0, 0, missile_image, missile_info, missile_sound)
missile_group = set([])
 
# register handlers
frame.set_keyup_handler(keyup)
frame.set_keydown_handler(keydown)
frame.set_mouseclick_handler(click)
frame.set_draw_handler(draw)
 
timer = simplegui.create_timer(1000.0, rock_spawner)
 
 
# get things rolling
timer.stop()
frame.start()

  

posted on   土匪7  阅读(277)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示