[Python] RiceRocks游戏 Mini-project #8

RiceRocks是Asteroids游戏的升级版,也是Spaceship完善后的结果。

相较于Mini-project#7,更改并补充了许多功能,包括对原来的飞船类、Sprite类进行修改,创建星石、导弹组,碰撞函数,开始与结束界面,也增加了星石被击中的音效、动效。这样阶段性地完成项目,是很值得采用的方法!

Mini-project #8详细描述:https://www.coursera.org/learn/interactive-python-2/supplement/GjfKF/mini-project-description

1. 对星石块的处理:

初始化时,rock、missile、explosion因为有多个,所以改为组。

# initialize ship and two sprites
my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info, )
rock_group = set([])
missile_group = set([])
explosion_group = set([])

星石生成函数做很多更改:
def rock_spawner(): #随机生成星石
    global rock_group, started
    if len(rock_group)<12 and started: #限定数量最多12个,且在游戏开始后产生
        rock_pos = [random.randrange(0, WIDTH), random.randrange(0, HEIGHT)]
        rock_vel = [random.random() * .6 - .3, random.random() * .6 - .3]
        rock_avel = random.random() * .2 - .1
        
        while dist(rock_pos, my_ship.pos) < 60 : #当星石与飞船离得太近,重新生成
            rock_pos = [random.randrange(0, WIDTH), random.randrange(0, HEIGHT)]
        a_rock = Sprite(rock_pos, rock_vel, 0, rock_avel, asteroid_image, asteroid_info)
        rock_group.add(a_rock) #将星石归入石组中
Sprite class中:

    def update(self): #Sprite类的update部分,添加了随着时间消失效果
        # 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

        if self.lifespan:
            if self.age > self.lifespan:
                return True #如果年龄大于寿命,消失
            else:
                self.age += 1
        return False
添加石组处理函数:

def process_sprite_group(canvas, group): 
    for sprite in set(group):
        sprite.draw(canvas)
        if sprite.update(): #update部分返回的参数传到此,决定星石是否消失
            group.remove(sprite)

2. 碰撞部分:

首先在Sprite类中添加碰撞函数:

    def collide(self, other_object):
        if dist( self.pos, other_object.pos ) <= self.radius+my_ship.radius:
            return True
        else:
            return False
当飞船撞上星石,就需要增加组与物体的碰撞函数:
def group_collide(group, other_object):
    global explosion_group #爆炸组,在星石被子弹击中或被飞船撞,都会使用这个,从而产生动效,下文会讲
    for sprite in list(group): #在复制的组中循环,可以更改原组
        if sprite.collide(other_object):
            explosion_group.add(Sprite(sprite.get_position(), (0, 0), 0, 0, explosion_image, explosion_info, explosion_sound)) 
            group.remove(sprite)
            return True
    else:
        return False
当导弹击中星石,就是组与组间碰撞了:

def group_group_collide(group1, group2):
    global score
    for sprite in list(group2):
        if group_collide(group1, sprite): #调用物体与组的碰撞函数
            group2.remove(sprite)
            score += 1 #每击中1次,子弹与星石消失,分数加1

最后,在draw函数中,调用各种类型的碰撞函数,检测碰撞:

    # draw collision
    if group_collide(rock_group, my_ship):
        lives -= 1 
    group_group_collide(rock_group, missile_group)

3. 添加星石爆炸效果:

在Sprite类中更新draw函数:

    def draw(self, canvas):
        if self.animated:
            image_tile = (self.age%24) // 1  #动画效果 由24个图像组成
            self.image_center = [self.image_center[0]+image_tile*self.image_size[0],self.image_center[1]]
        canvas.draw_image(self.image, self.image_center, self.image_size,
                          self.pos, self.image_size, self.angle)
在碰撞中,在爆炸组中添加被撞到的星石

def group_collide(group, other_object):
    global explosion_group
    for sprite in list(group): #在复制的组中循环,可以更改原组
        if sprite.collide(other_object):
            explosion_group.add(Sprite(sprite.get_position(), (0, 0), 0, 0, explosion_image, explosion_info, explosion_sound))
            group.remove(sprite)
            return True
    else:
        return False

4. 与Mini-project #7相比做的其它改变:

1) 由于导弹成组,所以对Ship类中的shoot函数做了更新:

    def shoot(self):
        global 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]]
        missile_group.add(Sprite(missile_pos, missile_vel, self.angle, 0, missile_image, missile_info, missile_sound))

对飞船的运动做了更改:

    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

2) 对Sprite类添加了返回位置、半径函数

    def get_position(self):
        return self.pos

    def get_radius(self):
        return self.radius
3) 在draw(canvas)函数中,引入全局变量:

started = False #最开始started初始化为False

    global time, started, lives, rock_group

sprite的更新与绘制都集中在process_sprite_group函数中

    # draw ship and update sprites
    my_ship.draw(canvas)
    process_sprite_group(canvas, rock_group)
    process_sprite_group(canvas, missile_group)
    process_sprite_group(canvas, explosion_group)

    # update ship
    my_ship.update()
添加游戏开始与结束画面:
# reset game
    if lives <1:
        started = False
        rock_group = set([])
        soundtrack.pause()
        timer.stop()

    # 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())
4) 添加鼠标点击开始游戏功能

# mouseclick handlers that reset UI and conditions whether splash image is drawn
def click(pos):
    global started, score, lives, my_ship, rock_group, missile_group
    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
        score = 0
        lives = 3
        timer.start()
        soundtrack.rewind()
        soundtrack.play
        my_ship = Ship([WIDTH / 2, HEIGHT / 2], [0, 0], 0, ship_image, ship_info)
引入鼠标控制

frame.set_mouseclick_handler(click)

5. 

[Python] RiceRocks游戏 Mini-project #8_第1张图片

射中后的动效:

[Python] RiceRocks游戏 Mini-project #8_第2张图片

游戏画面:

[Python] RiceRocks游戏 Mini-project #8_第3张图片

你可能感兴趣的:(游戏,代码,python,总结,Coursera)