python/pygame飞机游戏边学边写(五)

精灵碰撞检测

需要检测的精灵,除玩家飞机外,都需要单独建立sprite.Group:玩家子弹、敌方飞机、敌机子弹、buff。

all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
buff_group = pygame.sprite.Group()

把各精灵添加到各自的组中,all_sprites组负责draw和update,其它组负责实现碰撞检测。

写一个碰撞检测方法,包括得分及level增加:

def collision_detection(player):
    global score, level, life_number
    hits = pygame.sprite.groupcollide(player_bullets, enemies, True, False, pygame.sprite.collide_mask)
    for hit in hits:
        if hits[hit][0].defense >= 0:
            hits[hit][0].defense -= hit.damage
        else:
            hits[hit][0].hp -= hit.damage

        if hits[hit][0].hp <= 0:
            hits[hit][0].kill()
            score += hits[hit][0].score
            if score >= 20000:
                level = 2

    hits = pygame.sprite.spritecollide(player, enemy_bullets, True, pygame.sprite.collide_mask)
    for hit in hits:
        player.hp -= hit.damage
        if player.hp <= 0:
            player.kill()
            life_number -= 1

    hits = pygame.sprite.spritecollide(player, enemies, False, pygame.sprite.collide_mask)
    for hit in hits:
        hit.hp -= player.damage
        if hit.hp <= 0:
            hit.kill()
            score += hit.score

        player.hp -= hit.defense
        if player.hp <= 0:
            player.kill()
            life_number -= 1

写的有点匆忙,这里面觉得玩家子弹发射速度太慢了,还有其它一些属性值都有所增加和调整,虽然玩的感受很不好,但是总归是实现了攻击,加分、被攻击,死亡后进入结束界面。完整代码:

import random
import sys
import os
import pygame

pygame.init()

screen_info_height = pygame.display.Info().current_h

HEIGHT = int(screen_info_height * 0.9)
WIDTH = int(screen_info_height * 0.9 * 2 / 3)

RED = (255, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
FPS = 60

game_window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

running = True
state1 = True
state2 = False
level = 0
score = 0
life_number = 3
bomb_number = 3

enemy_time = 0

player_plane = pygame.image.load(os.path.join('image', 'my_plane.png'))
player_plane_mini = pygame.transform.scale(player_plane, (30, 20))
player_bullet = pygame.image.load(os.path.join('image', 'player_bullet1.png'))

enemy_grey_plane = pygame.image.load(os.path.join('image', 'enemy_grey_plane.png'))
enemy_orange_plane = pygame.image.load(os.path.join('image', 'enemy_orange_plane.png'))
enemy_red_plane = pygame.image.load(os.path.join('image', 'enemy_red_plane.png'))
enemy_blue_plane = pygame.image.load(os.path.join('image', 'enemy_blue_plane.png'))
enemy_green_plane = pygame.image.load(os.path.join('image', 'enemy_green_plane.png'))

enemy_bullet = pygame.image.load(os.path.join('image', 'enemy_bullet1.png'))

all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
buff_group = pygame.sprite.Group()


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(player_plane, (WIDTH * 0.09, WIDTH * 0.09 * 2 / 3))
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.centery = HEIGHT - 50
        self.speed = 10
        self.hp = 100
        self.defense = 100
        self.last_shoot = 0
        self.shoot_reload = 100
        self.damage = 500
        # if self.shoot_reload <= 100:
        #     self.shoot_reload = 100

    def update(self):
        key_pressed = pygame.key.get_pressed()
        if key_pressed[pygame.K_UP] and self.rect.top >= 50:
            self.rect.y -= self.speed
        if key_pressed[pygame.K_DOWN] and self.rect.bottom <= HEIGHT:
            self.rect.y += self.speed
        if key_pressed[pygame.K_LEFT] and self.rect.left >= -5:
            self.rect.x -= self.speed
        if key_pressed[pygame.K_RIGHT] and self.rect.right <= WIDTH + 5:
            self.rect.x += self.speed
        if key_pressed[pygame.K_SPACE]:
            now_shoot_time = pygame.time.get_ticks()
            if now_shoot_time - self.last_shoot >= self.shoot_reload:
                self.shoot()
                self.last_shoot = now_shoot_time

    def shoot(self):
        bullet = Bullet('player_bullet', self.rect.centerx, self.rect.top)
        all_sprites.add(bullet)
        player_bullets.add(bullet)


class Enemy(pygame.sprite.Sprite):
    enemy_plane_dic = {
        'grey': [enemy_grey_plane, 5, 100, 2000],
        'orange': [enemy_orange_plane, 4, 200, 1500],
        'red': [enemy_red_plane, 3, 400, 1000],
        'blue': [enemy_blue_plane, 2, 5000, 800],
        'green': [enemy_green_plane, 2, 10000, 800]
    }

    def __init__(self, color):
        pygame.sprite.Sprite.__init__(self)
        self.color = color
        if self.color == 'blue' or self.color == 'green':
            self.image = pygame.transform.scale(self.enemy_plane_dic[self.color][0], (WIDTH * 0.5, WIDTH * 0.5 * 2 / 3))
        else:
            self.image = pygame.transform.scale(self.enemy_plane_dic[self.color][0], (WIDTH * 0.1, WIDTH * 0.1 * 2 / 3))
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(0, WIDTH - self.rect.width)
        self.rect.y = random.randrange(5, 10)
        self.speedx = random.randrange(-3, 3)
        self.speedy = self.enemy_plane_dic[self.color][1]
        self.hp = 100
        self.defense = self.enemy_plane_dic[self.color][2]
        self.score = self.enemy_plane_dic[self.color][1] + self.enemy_plane_dic[self.color][2]
        self.last_shoot = 0
        self.shoot_reload = self.enemy_plane_dic[self.color][3]

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        blood_bar(game_window, self.hp, self.rect.x, self.rect.y - 20, self.rect.width, 3)
        now_shoot_time = pygame.time.get_ticks()
        if now_shoot_time - self.last_shoot >= self.shoot_reload:
            self.shoot()
            self.last_shoot = now_shoot_time

        if self.rect.left <= 0 or self.rect.right >= WIDTH:
            self.speedx = -self.speedx

        if self.rect.bottom >= HEIGHT or self.rect.top <= 0:
            if self.color == 'blue' or self.color == 'green':
                self.speedy = -self.speedy
            else:
                self.kill()

    def shoot(self):
        bullet = Bullet('enemy_bullet', self.rect.centerx, self.rect.bottom)
        all_sprites.add(bullet)
        enemy_bullets.add(bullet)


class Bullet(pygame.sprite.Sprite):
    bullet_dict = {
        'player_bullet': [player_bullet, 200, -15],
        'enemy_bullet': [enemy_bullet, 100, 15]
    }

    def __init__(self, bullet_type, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = self.bullet_dict[bullet_type][0]
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.centery = y
        self.damage = self.bullet_dict[bullet_type][1]
        self.speed = self.bullet_dict[bullet_type][2]

    def update(self):
        self.rect.centery += self.speed
        if self.rect.top <= 0 or self.rect.bottom >= HEIGHT:
            self.kill()


class BackGround:
    def __init__(self, surface):
        self.surface = surface
        self.image1 = pygame.transform.scale(pygame.image.load(os.path.join('image', 'bg.png')), (WIDTH, HEIGHT))
        self.image2 = pygame.transform.scale(pygame.image.load(os.path.join('image', 'bg.png')), (WIDTH, HEIGHT))
        self.rect1 = self.image1.get_rect()
        self.rect2 = self.image2.get_rect()
        self.rect1.x = 0
        self.rect1.y = 0
        self.rect2.x = 0
        self.rect2.y = - HEIGHT

    def background_move(self):
        self.surface.blit(self.image1, (self.rect1.x, self.rect1.y))
        self.surface.blit(self.image2, (self.rect2.x, self.rect2.y))
        self.rect1.y += 1
        if self.rect1.top >= HEIGHT:
            self.rect1.top = -HEIGHT
        self.rect2.y += 1
        if self.rect2.top >= HEIGHT:
            self.rect2.top = -HEIGHT


def mini_icon(surface):
    for i in range(life_number):
        surface.blit(player_plane_mini, (WIDTH - 35 - i * 35, 10))

    for i in range(bomb_number):
        pass


def new_enemy():
    global enemy_time

    now_enemy_time = pygame.time.get_ticks()
    if 0 <= score < 1000:
        color = random.choice(['grey'])
    if 1000 <= score < 2500:
        color = random.choice(['grey', 'orange'])
    if score >= 2500:
        color = random.choice(['grey', 'orange', 'red'])

    if now_enemy_time - enemy_time >= 1100 - level * 100:
        enemy = Enemy(color)
        all_sprites.add(enemy)
        enemies.add(enemy)
        enemy_time = now_enemy_time


def draw_text(surface, text, x, y, color, size):
    font = pygame.font.Font(os.path.join('font', 'simkai.ttf'), size)
    font_surf = font.render(text, True, color)
    font_surf_rect = font_surf.get_rect()
    font_surf_rect.x = x
    font_surf_rect.y = y
    surface.blit(font_surf, (x - font_surf_rect.width / 2, y))


def start_interface(surface):
    if state1:
        image1 = pygame.image.load(os.path.join('image', 'begin_button.png'))
        image2 = pygame.image.load(os.path.join('image', 'exit_button0.png'))
    else:
        image1 = pygame.image.load(os.path.join('image', 'begin_button0.png'))
        image2 = pygame.image.load(os.path.join('image', 'exit_button.png'))

    rect1 = image1.get_rect()
    rect1.x = WIDTH / 2 - rect1.width / 2
    rect1.y = HEIGHT * 0.25
    surface.blit(image1, (rect1.x, rect1.y))

    rect2 = image2.get_rect()
    rect2.x = WIDTH / 2 - rect2.width / 2
    rect2.y = HEIGHT * 0.35
    surface.blit(image2, (rect2.x, rect2.y))

    draw_text(surface, '按Tab键选择,按Enter键确认', WIDTH / 2, HEIGHT * 0.5, WHITE, 20)
    draw_text(surface, '按←↑↓→控制移动飞机', WIDTH / 2, HEIGHT * 0.55, WHITE, 20)
    draw_text(surface, '按空格键发射子弹,按b键释放炸弹', WIDTH / 2, HEIGHT * 0.6, WHITE, 20)


def end_interface():
    draw_text(game_window, 'GAME OVER', WIDTH / 2, 500, RED, 50)


def blood_bar(surface, hp, x, y, bar_length, bar_width):
    hp_max = max(hp, 0)
    blood_bar_fill = pygame.Rect(x, y, hp_max / 100 * bar_length, bar_width)
    blood_bar_outline = pygame.Rect(x, y, bar_length, bar_width)
    if hp_max >= 20:
        pygame.draw.rect(surface, GREEN, blood_bar_fill)
    else:
        pygame.draw.rect(surface, RED, blood_bar_fill)
    pygame.draw.rect(surface, WHITE, blood_bar_outline, 1)


def collision_detection(player):
    global score, level, life_number
    hits = pygame.sprite.groupcollide(player_bullets, enemies, True, False, pygame.sprite.collide_mask)
    for hit in hits:
        if hits[hit][0].defense >= 0:
            hits[hit][0].defense -= hit.damage
        else:
            hits[hit][0].hp -= hit.damage

        if hits[hit][0].hp <= 0:
            hits[hit][0].kill()
            score += hits[hit][0].score
            if score >= 20000:
                level = 2

    hits = pygame.sprite.spritecollide(player, enemy_bullets, True, pygame.sprite.collide_mask)
    for hit in hits:
        player.hp -= hit.damage
        if player.hp <= 0:
            player.kill()
            life_number -= 1

    hits = pygame.sprite.spritecollide(player, enemies, False, pygame.sprite.collide_mask)
    for hit in hits:
        hit.hp -= player.damage
        if hit.hp <= 0:
            hit.kill()
            score += hit.score

        player.hp -= hit.defense
        if player.hp <= 0:
            player.kill()
            life_number -= 1


def control():
    global running, state1, state2, level
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_TAB:
                state1, state2 = state2, state1

            if event.key == pygame.K_RETURN and state1 and level == 0:
                level = 1
            if event.key == pygame.K_RETURN and state2 and level == 0:
                running = False


def main():
    background = BackGround(game_window)
    player = Player()

    while running:
        control()
        if life_number > 0:
            if level == 0:
                background.background_move()
                start_interface(game_window)
            if level == 1:
                background.background_move()
                blood_bar(game_window, player.hp, 10, 40, 150, 10)
                mini_icon(game_window)

                new_enemy()
                all_sprites.add(player)
                all_sprites.draw(game_window)
                all_sprites.update()

                collision_detection(player)

                draw_text(game_window, 'SCORE: ' + str(score),  70, 10, RED, 25)
                draw_text(game_window, '第一关', WIDTH / 2, 300, RED, 30)

        else:
            background.background_move()
            end_interface()

        clock.tick(FPS)
        pygame.display.set_caption('飞机游戏   ' + 'FPS: ' + '{0:0.2F}'.format(clock.get_fps()))
        pygame.display.update()

    pygame.quit()
    sys.exit()


if __name__ == '__main__':
    main()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值