SuperRam/game_functions.py

410 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()