摸鱼时间试着玩了一会,发现一些问题,修改了几处小的细节:
1、得分显示,在分数增加,字段变长后会跑出游戏窗口,直接调整到游戏窗口中间显示。
2、限定玩家飞机生命总数不能超过5条,限定炸弹总数不能超过3个,防御值增加最多不超过3000。
3、调整生命血条代码,原来只考虑了hp值,血条瞬间消失,而且玩家飞机在增加防御buff后又会出现超长血条。现将双方飞机的防御值统一考虑进去,可以更真实的体现飞机被击中后的血量变化。
4、boss机没有爆炸效果,调整爆炸规模,如果是boss飞机,加大爆炸效果显示。
import random
import sys
import os
import pygame
import time
pygame.init()
pygame.mixer.init()
screen_info_height = pygame.display.Info().current_h
shoot_sound = pygame.mixer.Sound(os.path.join('sound', 'shoot_sound.mp3'))
bomb_sound = pygame.mixer.Sound(os.path.join('sound', 'bomb_sound.mp3'))
HEIGHT = int(screen_info_height * 0.9)
WIDTH = int(screen_info_height * 0.9 * 2 / 3)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
FPS = 60
game_window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
running = True
state1 = True
state2 = False
new_buff = False
boss_time = False
level = 0
score = 0
life_number = 3
bomb_number = 3
enemy_time = 0
bullet_buff_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'))
new_life = pygame.image.load(os.path.join('image', 'new_life.png'))
defence_buff = pygame.image.load((os.path.join('image', 'defence_buff.png')))
bullet_buff = pygame.image.load(os.path.join('image', 'bullet_buff.png'))
bomb_buff = pygame.image.load(os.path.join('image', 'bomb_buff.png'))
bomb_buff_mini = pygame.transform.scale(bomb_buff, (12, 20))
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player_bullets = pygame.sprite.Group()
enemy_bullets = pygame.sprite.Group()
buff_group = pygame.sprite.Group()
pygame.time.set_timer(pygame.USEREVENT + 1, 30 * 1000)
pygame.time.set_timer(pygame.USEREVENT + 2, 150 * 1000)
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 = 300
self.last_shoot = 0
self.shoot_reload = 100
self.damage = 500
self.total_hp = self.hp + self.defense
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
shoot_sound.set_volume(0.3)
shoot_sound.play()
def shoot(self):
bullet = Bullet('player_bullet', self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
player_bullets.add(bullet)
if int(time.time()) <= 20 + int(bullet_buff_time):
bullet1 = Bullet('player_bullet', self.rect.centerx - 20, self.rect.top)
bullet2 = Bullet('player_bullet', self.rect.centerx + 20, self.rect.top)
all_sprites.add(bullet1, bullet2)
player_bullets.add(bullet1, bullet2)
class Enemy(pygame.sprite.Sprite):
enemy_plane_dic = {
'grey': [enemy_grey_plane, 5, 100, 4000],
'orange': [enemy_orange_plane, 4, 200, 3000],
'red': [enemy_red_plane, 3, 400, 2000],
'blue': [enemy_blue_plane, 2, 100, 1000],
'green': [enemy_green_plane, 2, 200, 1000]
}
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
if self.color == 'blue' or self.color == 'green':
self.defense = self.enemy_plane_dic[self.color][2] + 5000 * level
else:
self.defense = self.enemy_plane_dic[self.color][2]
self.damage = self.enemy_plane_dic[self.color][2]
self.score = int(self.enemy_plane_dic[self.color][2] / 10)
self.last_shoot = 0
self.shoot_reload = self.enemy_plane_dic[self.color][3]
self.total_hp = self.hp + self.defense
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
blood_bar(game_window, self.hp + self.defense, self.total_hp, self.rect.x, self.rect.y - 20, self.rect.width, 5)
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)
bullet.damage = bullet.damage + int(self.damage / 10)
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, 20, 10]
}
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 Buff(pygame.sprite.Sprite):
buff_dict = {
'bullet_buff': bullet_buff,
'bomb_buff': bomb_buff,
'new_life': new_life,
'defence_buff': defence_buff
}
def __init__(self, buff_type):
pygame.sprite.Sprite.__init__(self)
self.buff_type = buff_type
self.image = self.buff_dict[self.buff_type]
self.rect = self.image.get_rect()
self.rect.x = random.randrange(0, WIDTH - self.rect.width)
self.rect.y = 10
self.speedx = random.randrange(-3, 3)
self.speedy = 5
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.left <= 0 or self.rect.right >= WIDTH:
self.speedx = -self.speedx
if self.rect.top <= 0 or self.rect.bottom >= HEIGHT:
self.speedy = - self.speedy
class Explosion:
def __init__(self, surface, x, y, size='small'):
self.explosions = []
self.last_bom = 0
self.bom_reload = 200
self.surface = surface
self.size = size
for i in range(6):
if self.size == 'small':
self.image = pygame.image.load(os.path.join('image', 'bomb' + str(i + 1) + '.png'))
if self.size == 'big':
self.image = pygame.image.load(os.path.join('image', 'big_bomb' + str(i + 1) + '.png'))
self.explosions.append(self.image)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def explosion(self):
now_time = pygame.time.get_ticks()
if now_time - self.last_bom >= self.bom_reload:
for i in range(len(self.explosions)):
self.surface.blit(self.explosions[i], (self.rect.x, self.rect.y))
self.last_bom = now_time
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):
surface.blit(bomb_buff_mini, (WIDTH - 25 - i * 35, 40))
def buff_produce():
global new_buff
if new_buff:
game_buff = Buff(random.choice(['bullet_buff', 'bullet_buff', 'defence_buff', 'new_life', 'bomb_buff']))
all_sprites.add(game_buff)
buff_group.add(game_buff)
new_buff = False
def new_player(player):
if life_number > 0:
player.rect.centerx = WIDTH / 2
player.rect.bottom = HEIGHT - 10
player.hp = 100
player.defense = 300
all_sprites.add(player)
def new_enemy():
global enemy_time, boss_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 >= max(1100 - level * 100, 500):
enemy = Enemy(color)
all_sprites.add(enemy)
enemies.add(enemy)
enemy_time = now_enemy_time
if boss_time:
enemy = Enemy(random.choice(['blue', 'green']))
all_sprites.add(enemy)
enemies.add(enemy)
boss_time = False
def bomb():
for b in enemy_bullets:
b.kill()
for e in enemies:
bom = Explosion(game_window, e.rect.x, e.rect.y)
bom.explosion()
e.hp -= 2000
if e.hp <= 0:
e.kill()
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 background_music():
pygame.mixer.music.load(os.path.join('sound', 'bgm.mp3'))
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
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 restart(surface):
global running, state1, state2, new_buff, level, score, life_number, bomb_number, enemy_time, bullet_buff, \
bullet_buff_time
surface.fill(BLACK)
all_sprites.empty()
enemies.empty()
player_bullets.empty()
enemy_bullets.empty()
running = True
state1 = True
state2 = False
new_buff = False
level = 0
score = 0
life_number = 3
bomb_number = 3
enemy_time = 0
bullet_buff_time = 0
main()
def end_interface():
draw_text(game_window, 'GAME OVER', WIDTH / 2, 300, RED, 50)
draw_text(game_window, 'SCORE: ' + str(score), WIDTH / 2, 400, RED, 50)
draw_text(game_window, '按 b 键重新开始游戏', WIDTH / 2, 500, RED, 20)
def blood_bar(surface, hp, total_hp, x, y, bar_length, bar_width):
hp_max = max(hp, 0)
blood_bar_fill = pygame.Rect(x, y, hp_max / total_hp * bar_length, bar_width)
blood_bar_outline = pygame.Rect(x, y, bar_length, bar_width)
if hp_max / total_hp >= 0.4:
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, bullet_buff_time, bomb_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:
if hits[hit][0].color == 'blue' or hits[hit][0].color == 'green':
bom = Explosion(game_window, hits[hit][0].rect.x, hits[hit][0].rect.y, size='big')
else:
bom = Explosion(game_window, hits[hit][0].rect.x, hits[hit][0].rect.y, size='small')
bom.explosion()
hits[hit][0].kill()
bomb_sound.play()
score += hits[hit][0].score
level = score // 5000 + 1
hits = pygame.sprite.spritecollide(player, enemy_bullets, True, pygame.sprite.collide_mask)
for hit in hits:
if player.defense >= 0:
player.defense -= hit.damage
else:
player.hp -= hit.damage
if player.hp <= 0:
bom = Explosion(game_window, player.rect.x, player.rect.y)
bom.explosion()
player.kill()
new_player(player)
life_number -= 1
hits = pygame.sprite.spritecollide(player, enemies, False, pygame.sprite.collide_mask)
for hit in hits:
if hit.defense >= 0:
hit.defense -= player.damage
else:
hit.hp -= player.damage
if hit.hp <= 0:
if hit.color == 'blue' or hit.color == 'green':
bom = Explosion(game_window, hit.rect.x, hit.rect.y, size='big')
else:
bom = Explosion(game_window, hit.rect.x, hit.rect.y, size='small')
bom.explosion()
hit.kill()
bomb_sound.play()
score += hit.score
if player.defense >= 0:
player.defense -= hit.damage
else:
player.hp -= hit.damage
if player.hp <= 0:
bom = Explosion(game_window, player.rect.x, player.rect.y)
bom.explosion()
player.kill()
new_player(player)
life_number -= 1
hits = pygame.sprite.spritecollide(player, buff_group, True)
for hit in hits:
if hit.buff_type == 'bullet_buff':
bullet_buff_time = time.time()
if hit.buff_type == 'bomb_buff' and bomb_number < 3:
bomb_number += 1
if hit.buff_type == 'new_life' and life_number < 5:
life_number += 1
if hit.buff_type == 'defence_buff' and player.defense <= 3000:
player.defense += 3000
player.total_hp = player.hp + player.defense
def control():
global running, state1, state2, level, new_buff, bomb_number, boss_time
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.USEREVENT + 1:
new_buff = True
if event.type == pygame.USEREVENT + 2:
boss_time = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
state1, state2 = state2, state1
if event.key == pygame.K_r and life_number <= 0:
restart(game_window)
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
if event.key == pygame.K_b and life_number > 0 and bomb_number > 0:
bomb()
bomb_number -= 1
def main():
background = BackGround(game_window)
player = Player()
background_music()
while running:
control()
background.background_move()
if life_number > 0:
if level == 0:
start_interface(game_window)
if level == 1:
blood_bar(game_window, player.hp + player.defense, player.total_hp, 10, 20, 150, 10)
mini_icon(game_window)
new_enemy()
buff_produce()
all_sprites.add(player)
all_sprites.draw(game_window)
all_sprites.update()
collision_detection(player)
draw_text(game_window, 'SCORE: ' + str(score), WIDTH / 2, 10, RED, 25)
draw_text(game_window, '第' + str(level) + '关', WIDTH / 2, 300, RED, 30)
if level >= 2:
blood_bar(game_window, player.hp + player.defense, player.total_hp, 10, 20, 150, 10)
mini_icon(game_window)
new_enemy()
buff_produce()
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, '第' + str(level) + '关', 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()