410 lines
16 KiB
Python
410 lines
16 KiB
Python
import sys
|
||
import pygame
|
||
import random
|
||
import operator
|
||
import json
|
||
from bullet import Bullet
|
||
from super_bullet import SuperBullet
|
||
from alien import Alien
|
||
from alien_bullet import AlienBullet
|
||
from time import sleep
|
||
from threading import Timer
|
||
|
||
|
||
"""
|
||
用户操作响应
|
||
"""
|
||
|
||
def check_events(ai_settings, screen, ship, bullets, aliens, stats, play_button, scoreboard, alien_bullets, super_bullets, playername_inputbox):
|
||
"""响应按键和鼠标事件"""
|
||
for event in pygame.event.get():
|
||
if event.type == pygame.QUIT:
|
||
sys.exit()
|
||
elif event.type == pygame.KEYDOWN:
|
||
check_keydown_events(event, ai_settings, screen, ship, bullets, stats, scoreboard, super_bullets, playername_inputbox)
|
||
elif event.type == pygame.KEYUP:
|
||
check_keyup_events(event, ship)
|
||
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||
mouse_x, mouse_y = pygame.mouse.get_pos()
|
||
check_playername_input(playername_inputbox, stats, mouse_x, mouse_y)
|
||
check_play_button(ai_settings, screen, ship, bullets, aliens, stats, play_button, mouse_x, mouse_y, scoreboard, alien_bullets, super_bullets, playername_inputbox)
|
||
|
||
|
||
def check_keydown_events(event, ai_settings, screen, ship, bullets, stats, scoreboard, super_bullets, playername_inputbox):
|
||
"""响应按键按下"""
|
||
if event.key == pygame.K_RIGHT:
|
||
ship.moving_right = True
|
||
elif event.key == pygame.K_LEFT:
|
||
ship.moving_left = True
|
||
elif event.key == pygame.K_SPACE:
|
||
if stats.game_active:
|
||
fire_bullet(ai_settings, screen, ship, bullets)
|
||
elif event.key == pygame.K_UP:
|
||
if stats.game_active:
|
||
activate_super_mode(ai_settings, ship, stats, scoreboard)
|
||
elif event.key == pygame.K_LALT:
|
||
if stats.game_active:
|
||
fire_super_bullet(ai_settings, screen, ship, stats, super_bullets)
|
||
elif event.key == pygame.K_q:
|
||
sys.exit()
|
||
else:
|
||
if playername_inputbox.login == False:
|
||
playername_inputbox.key_down(event)
|
||
|
||
def check_keyup_events(event, ship):
|
||
"""响应按键松开"""
|
||
if event.key == pygame.K_RIGHT:
|
||
ship.moving_right = False
|
||
elif event.key == pygame.K_LEFT:
|
||
ship.moving_left = False
|
||
|
||
|
||
def check_playername_input(playername_inputbox, stats, mouse_x, mouse_y):
|
||
"""检查用户点击玩家名称输入框,若点击,则清空文本"""
|
||
if playername_inputbox.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active:
|
||
playername_inputbox.text = ''
|
||
|
||
def check_play_button(ai_settings, screen, ship, bullets, aliens, stats, play_button, mouse_x, mouse_y, scoreboard, alien_bullets, super_bullets, playername_inputbox):
|
||
"""检查开始游戏按钮是否被按下,并响应"""
|
||
if play_button.rect.collidepoint(mouse_x, mouse_y) and not stats.game_active:
|
||
# 隐藏光标
|
||
pygame.mouse.set_visible(False)
|
||
# 重置游戏参数
|
||
ai_settings.initialize_dynamic_settings()
|
||
stats.reset_stats()
|
||
# 重置记分牌
|
||
scoreboard.prep_images()
|
||
# 设置状态为激活
|
||
stats.game_active = True
|
||
# 清屏并创建新的一群外星人
|
||
clear_and_create_fleet(ai_settings, screen, ship, bullets, aliens, alien_bullets, super_bullets)
|
||
if playername_inputbox.login == False:
|
||
stats.player = playername_inputbox.text
|
||
playername_inputbox.login = True
|
||
|
||
|
||
def fire_super_bullet(ai_settings, screen, ship, stats, super_bullets):
|
||
if stats.power >= ai_settings.points_of_power:
|
||
ai_settings.super_bullet_sound.play()
|
||
new_super_bullet = SuperBullet(ai_settings, screen, ship)
|
||
super_bullets.add(new_super_bullet)
|
||
stats.power -= ai_settings.points_of_power
|
||
|
||
|
||
def fire_bullet(ai_settings, screen, ship, bullets):
|
||
if len(bullets) < ai_settings.bullets_allowed:
|
||
ai_settings.bullet_sound.play()
|
||
new_bullet = Bullet(ai_settings, screen, ship)
|
||
bullets.add(new_bullet)
|
||
|
||
|
||
def activate_super_mode(ai_settings, ship, stats, scoreboard):
|
||
"""响应进入无敌模式"""
|
||
if stats.power >= ai_settings.points_of_power:
|
||
if ship.super_mode == False:
|
||
ai_settings.super_mode_sound.play()
|
||
ship.super_mode = True
|
||
stats.power -= ai_settings.points_of_power
|
||
scoreboard.prep_power()
|
||
Timer(5, quit_super_mode, args=[ship]).start()
|
||
|
||
def quit_super_mode(ship):
|
||
ship.super_mode = False
|
||
|
||
|
||
"""
|
||
子弹参数更新(包括超级子弹)
|
||
"""
|
||
|
||
def update_bullets(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets):
|
||
"""更新子弹位置并检查碰撞"""
|
||
# 更新子弹位置
|
||
bullets.update()
|
||
super_bullets.update()
|
||
# 删除已超出范围的子弹
|
||
for bullet in bullets.copy():
|
||
if bullet.rect.bottom <= 0:
|
||
bullets.remove(bullet)
|
||
for super_bullet in super_bullets.copy():
|
||
if super_bullet.rect.bottom <= 0:
|
||
super_bullets.remove(super_bullet)
|
||
|
||
check_bullet_alien_collision(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets)
|
||
|
||
|
||
def check_bullet_alien_collision(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets):
|
||
"""响应子弹击中外星人"""
|
||
# 检查是否有子弹击中外星人,若有,删除对应的子弹与外星人
|
||
collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
|
||
super_collisions = pygame.sprite.groupcollide(super_bullets, aliens, False, True)
|
||
|
||
if collisions:
|
||
for aliens in collisions.values():
|
||
stats.score += ai_settings.alien_points * len(aliens)
|
||
stats.power += ai_settings.alien_points * len(aliens)
|
||
scoreboard.prep_score()
|
||
scoreboard.prep_power()
|
||
# 检查是否打破历史记录
|
||
check_high_score(stats, scoreboard)
|
||
|
||
if super_collisions:
|
||
for aliens in super_collisions.values():
|
||
stats.score += ai_settings.alien_points * len(aliens)
|
||
stats.power += ai_settings.alien_points * len(aliens)
|
||
scoreboard.prep_score()
|
||
scoreboard.prep_power()
|
||
# 检查是否打破历史记录
|
||
check_high_score(stats, scoreboard)
|
||
|
||
if len(aliens) == 0:
|
||
# 外星人被消灭干净,开启新等级
|
||
start_new_level(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets)
|
||
|
||
|
||
def start_new_level(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets):
|
||
"""响应外星人被消灭干净"""
|
||
ai_settings.start_new_level_sound.play()
|
||
bullets.empty()
|
||
super_bullets.empty()
|
||
ai_settings.increase_speed()
|
||
create_fleet(ai_settings, screen, ship, aliens)
|
||
stats.level += 1
|
||
scoreboard.prep_level()
|
||
|
||
|
||
def check_high_score(stats, scoreboard):
|
||
"""响应打破历史记录"""
|
||
if stats.score > stats.high_score:
|
||
stats.high_score = stats.score
|
||
scoreboard.prep_high_score()
|
||
|
||
|
||
"""
|
||
外星人参数更新
|
||
"""
|
||
|
||
def update_aliens(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets):
|
||
"""更新所有外星人的位置"""
|
||
check_fleet_edges(ai_settings, aliens)
|
||
aliens.update()
|
||
|
||
# 检测外星人和飞船的碰撞
|
||
if pygame.sprite.spritecollideany(ship, aliens):
|
||
ship_hit(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||
|
||
check_aliens_bottom(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||
|
||
|
||
def check_fleet_edges(ai_settings, aliens):
|
||
"""有外星人到达屏幕边缘时采取相应措施"""
|
||
for alien in aliens.sprites():
|
||
if alien.check_edges():
|
||
change_fleet_direction(ai_settings, aliens)
|
||
break
|
||
|
||
def change_fleet_direction(ai_settings, aliens):
|
||
"""将外星人整体下移一行并改变移动方向"""
|
||
for alien in aliens.sprites():
|
||
alien.rect.y += ai_settings.fleet_drop_speed
|
||
ai_settings.fleet_direction *= -1
|
||
|
||
|
||
def check_aliens_bottom(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets):
|
||
"""检查是否有外星人撞到屏幕底端"""
|
||
screen_rect = screen.get_rect()
|
||
for alien in aliens.sprites():
|
||
if alien.rect.bottom >= screen_rect.bottom:
|
||
# 像飞船与外星人相撞一样处理
|
||
ship_hit(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||
break
|
||
|
||
def ship_hit(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets):
|
||
"""响应飞船与外星人碰撞"""
|
||
if stats.ships_left > 0:
|
||
"""仍有剩余飞船,游戏继续"""
|
||
ai_settings.ship_hit_sound.play()
|
||
# 将剩余飞船数减一
|
||
stats.ships_left -= 1
|
||
# 清空外星人和子弹列表并创建一批新外星人
|
||
clear_and_create_fleet(ai_settings, screen, ship, bullets, aliens, alien_bullets, super_bullets)
|
||
# 更新剩余飞船数
|
||
scoreboard.prep_ships()
|
||
|
||
else:
|
||
"""游戏结束"""
|
||
if stats.score == stats.high_score:
|
||
ai_settings.recordbroken_sound.play()
|
||
else:
|
||
ai_settings.gameover_sound.play()
|
||
stats.game_active = False
|
||
pygame.mouse.set_visible(True)
|
||
|
||
# 记录此次玩家得分
|
||
new_score = { 'player': stats.player, 'score': stats.score }
|
||
stats.scores_data.append(new_score)
|
||
stats.scores_data.sort(key=lambda x:x["score"], reverse=True)
|
||
with open('scores.json', 'w') as f:
|
||
json.dump(stats.scores_data, f)
|
||
|
||
# 打印历史得分排行榜Top10
|
||
if len(stats.scores_data) >= 10:
|
||
leaderboard_height = 340
|
||
else:
|
||
leaderboard_height = len(stats.scores_data) * 30 + 40
|
||
|
||
leaderboard_rect = pygame.Rect(450, 180, 300, leaderboard_height)
|
||
screen.fill(ai_settings.lb_bg_color, leaderboard_rect)
|
||
|
||
# 表头
|
||
leaderboard_font = pygame.font.SysFont("Calibri, Arial", 28)
|
||
rank_image_rect = draw_leaderboard(ai_settings.lb_text_color, ai_settings.lb_bg_color, screen, 'Rank', leaderboard_font, 500, 200)
|
||
player_image_rect = draw_leaderboard(ai_settings.lb_text_color, ai_settings.lb_bg_color, screen, 'Player', leaderboard_font, 600, 200)
|
||
score_image_rect = draw_leaderboard(ai_settings.lb_text_color, ai_settings.lb_bg_color, screen, 'Score', leaderboard_font, 700, 200)
|
||
|
||
rank = 0
|
||
for player_score in stats.scores_data:
|
||
"""逐个显示玩家得分"""
|
||
rank += 1
|
||
if rank > 10:
|
||
break
|
||
rank_text = str(rank)
|
||
player_text = str(player_score["player"])
|
||
score_text = str(player_score["score"])
|
||
y_postion = rank_image_rect.centery + 30 * rank
|
||
font = leaderboard_font
|
||
text_color = ai_settings.lb_text_color
|
||
bg_color = ai_settings.lb_bg_color
|
||
if player_score == new_score:
|
||
"""当前用户的信息,样式不同"""
|
||
general_font = pygame.font.SysFont("Calibri, Arial", 32, True)
|
||
text_color = (255, 255, 0)
|
||
|
||
draw_leaderboard(text_color, bg_color, screen, rank_text, font, rank_image_rect.centerx, y_postion)
|
||
draw_leaderboard(text_color, bg_color, screen, player_text, font, player_image_rect.centerx, y_postion)
|
||
draw_leaderboard(text_color, bg_color, screen, score_text, font, score_image_rect.centerx, y_postion)
|
||
|
||
pygame.display.flip()
|
||
sleep(5)
|
||
|
||
sleep(0.5)
|
||
|
||
|
||
def draw_leaderboard(text_color ,bg_color, screen, text, font, x, y):
|
||
"""绘制排行榜的某一项"""
|
||
image = font.render(text, True, text_color, bg_color)
|
||
image_rect = image.get_rect()
|
||
image_rect.centerx = x
|
||
image_rect.centery = y
|
||
screen.blit(image, image_rect)
|
||
return image_rect
|
||
|
||
|
||
def clear_and_create_fleet(ai_settings, screen, ship, bullets, aliens, alien_bullets, super_bullets):
|
||
"""清空外星人和子弹列表并创建一批新外星人"""
|
||
# 清空外星人和子弹列表
|
||
bullets.empty()
|
||
super_bullets.empty()
|
||
aliens.empty()
|
||
alien_bullets.empty()
|
||
|
||
# 创建一批新的外星人,并将飞船放到屏幕底部中央
|
||
create_fleet(ai_settings, screen, ship, aliens)
|
||
ship.center_ship()
|
||
|
||
|
||
def create_fleet(ai_settings, screen, ship, aliens):
|
||
"""创建外星人群"""
|
||
alien = Alien(ai_settings, screen)
|
||
number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
|
||
number_rows = get_number_rows(ai_settings, alien.rect.height, ship.rect.height)
|
||
for row_number in range(number_rows):
|
||
for alien_number in range(number_aliens_x):
|
||
create_alien(ai_settings, screen, aliens, alien_number, row_number)
|
||
|
||
def get_number_aliens_x(ai_settings, alien_width):
|
||
"""计算一行可容纳多少外星人"""
|
||
available_space_x = ai_settings.screen_width - 2 * alien_width
|
||
number_aliens_x = int(available_space_x / (2 * alien_width))
|
||
return number_aliens_x
|
||
|
||
def get_number_rows(ai_settings, alien_height, ship_height):
|
||
"""计算可容纳多少行外星人"""
|
||
available_space_y = ai_settings.screen_height - 6 * alien_height - ship_height
|
||
number_rows = int(available_space_y / (2 * alien_height))
|
||
return number_rows
|
||
|
||
def create_alien(ai_settings, screen, aliens, alien_number, row_number):
|
||
"""创建一个外星人并把它加入当前行"""
|
||
alien = Alien(ai_settings, screen)
|
||
alien_width = alien.rect.width
|
||
alien_height = alien.rect.height
|
||
alien.x = alien_width + 2 * alien_width * alien_number
|
||
alien.rect.x = alien.x
|
||
alien.rect.y = alien_height + 2 * alien_height * row_number
|
||
aliens.add(alien)
|
||
|
||
|
||
"""
|
||
外星人子弹更新
|
||
"""
|
||
|
||
def update_aliens_fire_bullet(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets):
|
||
"""更新外星人发射的子弹"""
|
||
for alien in aliens.sprites():
|
||
flag_is_last_line = True
|
||
for alien_next in aliens.sprites():
|
||
if (alien.rect.y + alien.rect.height * 2 == alien_next.rect.y
|
||
and alien.rect.x == alien_next.rect.x):
|
||
flag_is_last_line = False
|
||
break
|
||
if flag_is_last_line:
|
||
"""外星人有一定的概率发射子弹"""
|
||
if random.randint(0,3000) < 1:
|
||
new_alien_bullet = AlienBullet(ai_settings, screen, alien)
|
||
alien_bullets.add(new_alien_bullet)
|
||
|
||
check_alien_bullet_ship_collision(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||
alien_bullets.update()
|
||
|
||
|
||
def check_alien_bullet_ship_collision(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets):
|
||
"""响应外星人子弹击中飞船"""
|
||
for alien_bullet in alien_bullets.sprites():
|
||
if alien_bullet.rect.colliderect(ship.rect) and not ship.super_mode:
|
||
ship_hit(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||
break
|
||
|
||
|
||
"""
|
||
屏幕更新
|
||
"""
|
||
|
||
def update_screen(ai_settings, screen, ship, bullets, aliens, stats, play_button, scoreboard, alien_bullets, super_bullets, playername_inputbox):
|
||
"""更新屏幕上的图像,并切换到新屏幕"""
|
||
# 重绘屏幕
|
||
screen.fill(ai_settings.bg_color)
|
||
if playername_inputbox.login == False:
|
||
playername_inputbox.draw_inputbox()
|
||
|
||
# 绘制全部子弹
|
||
for bullet in bullets.sprites():
|
||
bullet.draw_bullet()
|
||
for alien_bullet in alien_bullets.sprites():
|
||
alien_bullet.draw_alien_bullet()
|
||
for super_bullet in super_bullets.sprites():
|
||
super_bullet.draw_bullet()
|
||
# 绘制玩家飞船
|
||
ship.blitme()
|
||
# 绘制全部外星人
|
||
aliens.draw(screen)
|
||
scoreboard.ships.draw(screen)
|
||
# 显示得分
|
||
scoreboard.show_score()
|
||
|
||
# 如果游戏处于非活动状态,就显示Play按钮
|
||
if stats.game_active == False:
|
||
play_button.draw_button()
|
||
|
||
# 让最近绘制的屏幕可见
|
||
pygame.display.flip()
|