This commit is contained in:
parent
1eadba9854
commit
a94fd61cc8
|
@ -0,0 +1,35 @@
|
|||
import pygame
|
||||
from pygame.sprite import Sprite
|
||||
|
||||
class Alien(Sprite):
|
||||
"""表示单个外星人的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen):
|
||||
"""初始化外星人并设置其初始位置"""
|
||||
super().__init__()
|
||||
self.screen = screen
|
||||
self.ai_settings = ai_settings
|
||||
|
||||
# 加载外星人图像,并设置其rect属性
|
||||
self.image = pygame.image.load('images/alien.bmp')
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
# 每个外星人初始都在屏幕左上角,设置为其宽高以进行留白
|
||||
self.rect.x = self.rect.width
|
||||
self.rect.y = self.rect.height * 2
|
||||
|
||||
self.x = float(self.rect.x)
|
||||
|
||||
|
||||
def update(self):
|
||||
"""向左或向右右移动外星人"""
|
||||
self.x += self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction
|
||||
self.rect.x = self.x
|
||||
|
||||
|
||||
def check_edges(self):
|
||||
screen_rect = self.screen.get_rect()
|
||||
if self.rect.right >= screen_rect.right:
|
||||
return True
|
||||
elif self.rect.left <= screen_rect.left:
|
||||
return True
|
|
@ -0,0 +1,33 @@
|
|||
import pygame
|
||||
from pygame.sprite import Sprite
|
||||
|
||||
class AlienBullet(Sprite):
|
||||
"""一个对外星人发射的子弹进行管理的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen, alien):
|
||||
"""在飞船所处的位置创建一个子弹对象"""
|
||||
super().__init__()
|
||||
self.screen = screen
|
||||
|
||||
# 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
|
||||
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
|
||||
self.rect.centerx = alien.rect.centerx
|
||||
self.rect.top = alien.rect.bottom
|
||||
|
||||
# 存储用小数表示的子弹位置
|
||||
self.y = float(self.rect.y)
|
||||
|
||||
# 设置子弹颜色及速度(从ai_settings中读取)
|
||||
self.color = ai_settings.alien_bullet_color
|
||||
self.speed_factor = ai_settings.bullet_speed_factor
|
||||
|
||||
|
||||
def update(self):
|
||||
"""向下移动子弹"""
|
||||
self.y += self.speed_factor
|
||||
self.rect.y = self.y
|
||||
|
||||
|
||||
def draw_alien_bullet(self):
|
||||
"""在屏幕上绘制子弹"""
|
||||
pygame.draw.rect(self.screen, self.color, self.rect)
|
|
@ -0,0 +1,52 @@
|
|||
import pygame
|
||||
import game_functions as gf
|
||||
from settings import Settings
|
||||
from ship import Ship
|
||||
from pygame.sprite import Group
|
||||
from game_stats import GameStats
|
||||
from button import Button
|
||||
from scoreboard import Scoreboard
|
||||
from playername_inputbox import PlayernameInputbox
|
||||
|
||||
|
||||
def run_game():
|
||||
# 初始化游戏并创建一个屏幕对象
|
||||
pygame.init()
|
||||
ai_settings = Settings()
|
||||
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
|
||||
pygame.display.set_caption("Alien Invasion")
|
||||
|
||||
# 创建一艘飞船, 一个子弹编组和一个外星人编组
|
||||
ship = Ship(ai_settings, screen)
|
||||
bullets = Group()
|
||||
aliens = Group()
|
||||
alien_bullets = Group()
|
||||
super_bullets = Group()
|
||||
|
||||
# 创建外星人群
|
||||
gf.create_fleet(ai_settings, screen, ship, aliens)
|
||||
|
||||
# 创建一个用于游戏统计信息的示例,并创建记分牌
|
||||
stats = GameStats(ai_settings)
|
||||
scoreboard = Scoreboard(ai_settings, screen, stats)
|
||||
|
||||
# 创建开始游戏按钮
|
||||
play_button = Button(ai_settings, screen, "Play")
|
||||
|
||||
# 创建玩家名字文本输入框
|
||||
playername_inputbox = PlayernameInputbox(screen)
|
||||
|
||||
# 开始游戏的主循环
|
||||
while True:
|
||||
gf.check_events(ai_settings, screen, ship, bullets, aliens, stats, play_button, scoreboard, alien_bullets, super_bullets, playername_inputbox)
|
||||
|
||||
if stats.game_active:
|
||||
ship.update()
|
||||
gf.update_bullets(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, super_bullets)
|
||||
gf.update_aliens(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||||
gf.update_aliens_fire_bullet(ai_settings, screen, ship, bullets, aliens, stats, scoreboard, alien_bullets, super_bullets)
|
||||
|
||||
gf.update_screen(ai_settings, screen, ship, bullets, aliens, stats, play_button, scoreboard, alien_bullets, super_bullets, playername_inputbox)
|
||||
|
||||
|
||||
run_game()
|
|
@ -0,0 +1,33 @@
|
|||
import pygame
|
||||
from pygame.sprite import Sprite
|
||||
|
||||
class Bullet(Sprite):
|
||||
"""一个对飞船发射的子弹进行管理的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen, ship):
|
||||
"""在飞船所处的位置创建一个子弹对象"""
|
||||
super().__init__()
|
||||
self.screen = screen
|
||||
|
||||
# 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
|
||||
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height)
|
||||
self.rect.centerx = ship.rect.centerx
|
||||
self.rect.bottom = ship.rect.top
|
||||
|
||||
# 存储用小数表示的子弹位置
|
||||
self.y = float(self.rect.y)
|
||||
|
||||
# 设置子弹颜色及速度(从ai_settings中读取)
|
||||
self.color = ai_settings.bullet_color
|
||||
self.speed_factor = ai_settings.bullet_speed_factor
|
||||
|
||||
|
||||
def update(self):
|
||||
"""向上移动子弹"""
|
||||
self.y -= self.speed_factor
|
||||
self.rect.y = self.y
|
||||
|
||||
|
||||
def draw_bullet(self):
|
||||
"""在屏幕上绘制子弹"""
|
||||
pygame.draw.rect(self.screen, self.color, self.rect)
|
|
@ -0,0 +1,37 @@
|
|||
import pygame.font
|
||||
|
||||
class Button():
|
||||
"""一个用于创建矩形按钮的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen, msg):
|
||||
"""初始化按钮的属性"""
|
||||
self.screen = screen
|
||||
self.screen_rect = screen.get_rect()
|
||||
|
||||
# 设置按钮的尺寸和其他属性
|
||||
self.width = 200
|
||||
self.height = 50
|
||||
self.button_color = (0, 255, 0)
|
||||
self.text_color = (255, 255, 255)
|
||||
self.font = pygame.font.SysFont('Calibri, Arial', 48)
|
||||
|
||||
# 创建按钮的rect对象,并使其在屏幕上居中
|
||||
self.rect = pygame.Rect(0, 0, self.width, self.height)
|
||||
self.rect.center = self.screen_rect.center
|
||||
self.rect.y += 120
|
||||
|
||||
# 按钮标签
|
||||
self.prep_msg(msg)
|
||||
|
||||
|
||||
def prep_msg(self, msg):
|
||||
"""将msg渲染成图像,并使其在按钮上居中"""
|
||||
self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
|
||||
self.msg_image_rect = self.msg_image.get_rect()
|
||||
self.msg_image_rect.center = self.rect.center
|
||||
|
||||
|
||||
def draw_button(self):
|
||||
"""绘制一个用颜色填充的按钮,并绘制文本"""
|
||||
self.screen.fill(self.button_color, self.rect)
|
||||
self.screen.blit(self.msg_image, self.msg_image_rect)
|
|
@ -0,0 +1,409 @@
|
|||
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()
|
|
@ -0,0 +1,25 @@
|
|||
import json
|
||||
|
||||
class GameStats():
|
||||
"""跟踪游戏的统计信息"""
|
||||
|
||||
def __init__(self, ai_settings):
|
||||
"""初始化统计信息"""
|
||||
self.ai_settings = ai_settings
|
||||
self.game_active = False
|
||||
|
||||
self.reset_stats()
|
||||
|
||||
|
||||
def reset_stats(self):
|
||||
"""初始化在游戏运行期间可能变化的信息"""
|
||||
self.ships_left = self.ai_settings.ship_limit
|
||||
self.score = 0
|
||||
self.level = 1
|
||||
self.power = 0
|
||||
|
||||
# 提取历史得分信息
|
||||
scorefilename = 'scores.json'
|
||||
with open(scorefilename) as f:
|
||||
self.scores_data = json.load(f)
|
||||
self.high_score = int(self.scores_data[0]['score'])
|
|
@ -0,0 +1,56 @@
|
|||
import pygame
|
||||
|
||||
class PlayernameInputbox:
|
||||
def __init__(self, screen):
|
||||
"""初始化文本框的属性"""
|
||||
self.screen = screen
|
||||
self.screen_rect = screen.get_rect()
|
||||
|
||||
# 设置按钮的尺寸和其他属性
|
||||
self.width = 200
|
||||
self.height = 50
|
||||
self.box_color = (255, 255, 255)
|
||||
self.text_color = (20, 20, 20)
|
||||
self.font = pygame.font.SysFont("Calibri, Arial", 38)
|
||||
|
||||
# 创建按钮的rect对象,并使其在屏幕上居中
|
||||
self.rect = pygame.Rect(0, 0, self.width, self.height)
|
||||
self.rect.center = self.screen_rect.center
|
||||
self.rect.y += 40
|
||||
|
||||
self.text = "Your Name"
|
||||
self.login = False
|
||||
|
||||
|
||||
def draw_inputbox(self):
|
||||
"""将输入文本渲染为图像,并显示"""
|
||||
self.text_image = self.font.render(self.text, True, self.text_color, self.box_color)
|
||||
self.text_image_rect = self.text_image.get_rect()
|
||||
self.text_image_rect.center = self.rect.center
|
||||
|
||||
self.screen.fill(self.box_color, self.rect)
|
||||
self.screen.blit(self.text_image, self.text_image_rect)
|
||||
|
||||
|
||||
def key_down(self, event):
|
||||
"""输入新文本"""
|
||||
unicode = event.unicode
|
||||
key = event.key
|
||||
|
||||
if key == 8:
|
||||
# 退位键
|
||||
self.text = self.text[:-1]
|
||||
return
|
||||
if key == 301:
|
||||
# 切换大小写键
|
||||
return
|
||||
if key == 13:
|
||||
# 回车键
|
||||
return
|
||||
|
||||
if unicode != "":
|
||||
char = unicode
|
||||
else:
|
||||
char = chr(key)
|
||||
|
||||
self.text += char
|
|
@ -0,0 +1,96 @@
|
|||
import pygame.font
|
||||
from pygame.sprite import Group
|
||||
from ship import Ship
|
||||
|
||||
class Scoreboard():
|
||||
"""显示得分信息的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen, stats):
|
||||
"""初始化相关参数"""
|
||||
self.ai_settings = ai_settings
|
||||
self.screen = screen
|
||||
self.screen_rect = screen.get_rect()
|
||||
self.stats = stats
|
||||
|
||||
# 字体设置
|
||||
self.text_color = (230, 230, 230)
|
||||
self.font = pygame.font.SysFont("Calibri, Arial", 28)
|
||||
|
||||
# 准备得分图像、等级及剩余飞船图像
|
||||
self.prep_images()
|
||||
|
||||
|
||||
def show_score(self):
|
||||
"""在屏幕上显示得分、历史记录、等级、大招数"""
|
||||
self.screen.blit(self.score_image, self.score_rect)
|
||||
self.screen.blit(self.high_score_image, self.high_score_rect)
|
||||
self.screen.blit(self.level_image, self.level_rect)
|
||||
self.screen.blit(self.power_image, self.power_rect)
|
||||
|
||||
|
||||
def prep_images(self):
|
||||
"""准备各个图像(得分,历史记录,等级,剩余飞船)"""
|
||||
self.prep_score()
|
||||
self.prep_high_score()
|
||||
self.prep_level()
|
||||
self.prep_ships()
|
||||
self.prep_power()
|
||||
|
||||
|
||||
def prep_score(self):
|
||||
"""将得分渲染为图像"""
|
||||
rounded_score = round(self.stats.score, -1)
|
||||
score_str = "{:,}".format(rounded_score)
|
||||
self.score_image = self.font.render(score_str, True, self.text_color, self.ai_settings.bg_color)
|
||||
|
||||
# 将得分放在屏幕右上角
|
||||
self.score_rect = self.score_image.get_rect()
|
||||
self.score_rect.top = 20
|
||||
self.score_rect.right = self.screen_rect.right - 20
|
||||
|
||||
|
||||
def prep_high_score(self):
|
||||
"""将历史记录渲染为图像"""
|
||||
rounded_high_score = round(self.stats.high_score, -1)
|
||||
high_score_str = "Record: " + "{:,}".format(rounded_high_score)
|
||||
self.high_score_image = self.font.render(high_score_str, True, self.text_color, self.ai_settings.bg_color)
|
||||
|
||||
# 将历史记录放在屏幕左下角
|
||||
self.high_score_rect = self.high_score_image.get_rect()
|
||||
self.high_score_rect.bottom = self.screen_rect.bottom - 10
|
||||
self.high_score_rect.left = self.screen_rect.left + 10
|
||||
|
||||
|
||||
def prep_level(self):
|
||||
"""将等级渲染为图像"""
|
||||
level_str = "Level: " + str(self.stats.level)
|
||||
self.level_image = self.font.render(level_str, True, self.text_color, self.ai_settings.bg_color)
|
||||
|
||||
# 将等级放在得分下面
|
||||
self.level_rect = self.level_image.get_rect()
|
||||
self.level_rect.top = self.score_rect.bottom
|
||||
self.level_rect.right = self.screen_rect.right - 20
|
||||
|
||||
|
||||
def prep_ships(self):
|
||||
"""显示剩余飞船"""
|
||||
self.ships = Group()
|
||||
for ship_number in range(self.stats.ships_left):
|
||||
ship = Ship(self.ai_settings, self.screen)
|
||||
ship.image = pygame.transform.scale(ship.image,(25, 27))
|
||||
ship.rect = ship.image.get_rect()
|
||||
ship.rect.x = ship.rect.width * ship_number + 10
|
||||
ship.rect.y = 10
|
||||
self.ships.add(ship)
|
||||
|
||||
|
||||
def prep_power(self):
|
||||
"""将大招渲染为图像"""
|
||||
power_num = int(self.stats.power / self.ai_settings.points_of_power)
|
||||
power_str = "Power: " + str(power_num)
|
||||
self.power_image = self.font.render(power_str, True, self.text_color, self.ai_settings.bg_color)
|
||||
|
||||
# 将大招数放在屏幕右下
|
||||
self.power_rect = self.power_image.get_rect()
|
||||
self.power_rect.bottom = self.screen_rect.bottom - 10
|
||||
self.power_rect.right = self.screen_rect.right - 10
|
|
@ -0,0 +1 @@
|
|||
[{"player": "666", "score": 425805}, {"player": "cwj", "score": 21874}, {"player": "Your Name", "score": 4850}, {"player": "Your Name", "score": 4700}, {"player": "Your Name", "score": 2900}, {"player": "Your Name", "score": 1350}, {"player": "Your Name", "score": 1250}]
|
|
@ -0,0 +1,73 @@
|
|||
import pygame
|
||||
|
||||
class Settings():
|
||||
"""储存《外星人入侵》所有设置的类"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化游戏的设置"""
|
||||
# 屏幕设置
|
||||
self.screen_width = 1200
|
||||
self.screen_height = 800
|
||||
self.bg_color = (0, 0, 0)
|
||||
self.lb_bg_color = (10, 10, 10)
|
||||
self.lb_text_color = (230, 230, 230)
|
||||
|
||||
# 飞船设置
|
||||
self.ship_limit = 3
|
||||
|
||||
# 子弹设置
|
||||
self.bullet_width = 3
|
||||
self.bullet_height = 15
|
||||
self.bullet_color = (180, 180, 180)
|
||||
self.bullets_allowed = 5
|
||||
|
||||
# 超级子弹设置
|
||||
self.super_bullet_color = (0, 255, 0)
|
||||
self.super_bullet_width = 6
|
||||
self.super_bullet_height = 150
|
||||
self.points_of_power = 1000
|
||||
|
||||
# 外星人设置
|
||||
self.fleet_drop_speed = 10
|
||||
self.alien_bullet_color = (220, 220, 0)
|
||||
|
||||
# 游戏加快节奏参数
|
||||
self.speedup_scale = 1.1
|
||||
|
||||
# 击中外星人得分点数的提高速度
|
||||
self.score_scale = 1.2
|
||||
|
||||
# 音效设置
|
||||
self.bullet_sound = pygame.mixer.Sound("sounds/bullet.wav")
|
||||
self.super_bullet_sound = pygame.mixer.Sound("sounds/super_bullet.wav")
|
||||
self.ship_hit_sound = pygame.mixer.Sound("sounds/ship_hit.wav")
|
||||
self.start_new_level_sound = pygame.mixer.Sound("sounds/start_new_level.wav")
|
||||
self.super_mode_sound = pygame.mixer.Sound("sounds/super_mode.wav")
|
||||
self.gameover_sound = pygame.mixer.Sound("sounds/gameover.wav")
|
||||
self.recordbroken_sound = pygame.mixer.Sound("sounds/recordbroken.wav")
|
||||
|
||||
# 初始化游戏动态设置
|
||||
self.initialize_dynamic_settings()
|
||||
|
||||
|
||||
def initialize_dynamic_settings(self):
|
||||
"""初始化动态参数"""
|
||||
self.ship_speed_factor = 1.5
|
||||
self.bullet_speed_factor = 3
|
||||
self.alien_speed_factor = 1
|
||||
self.super_bullet_speed_factor = 30
|
||||
|
||||
# 1表示右移,-1表示左移
|
||||
self.fleet_direction = 1
|
||||
|
||||
# 记分
|
||||
self.alien_points = 50
|
||||
|
||||
|
||||
def increase_speed(self):
|
||||
"""提高速度设置"""
|
||||
self.ship_speed_factor *= self.speedup_scale
|
||||
self.bullet_speed_factor *= self.speedup_scale
|
||||
self.alien_speed_factor *= self.speedup_scale
|
||||
|
||||
self.alien_points = int(self.alien_points * self.score_scale)
|
|
@ -0,0 +1,50 @@
|
|||
import pygame
|
||||
from pygame.sprite import Sprite
|
||||
|
||||
class Ship(Sprite):
|
||||
|
||||
def __init__(self, ai_settings, screen):
|
||||
"""初始化飞船并设置其初始位置"""
|
||||
super().__init__()
|
||||
self.ai_settings = ai_settings
|
||||
self.screen = screen
|
||||
|
||||
# 加载飞船图像并获得其外接矩形
|
||||
self.image = pygame.image.load('images/ship.bmp')
|
||||
self.rect = self.image.get_rect()
|
||||
self.screen_rect = screen.get_rect()
|
||||
|
||||
# 将飞船放在屏幕底部中央
|
||||
self.rect.centerx = self.screen_rect.centerx
|
||||
self.rect.bottom = self.screen_rect.bottom
|
||||
|
||||
# 在飞船的属性center中储存小数值
|
||||
self.center = float(self.rect.centerx)
|
||||
|
||||
# 移动标志
|
||||
self.moving_right = False
|
||||
self.moving_left = False
|
||||
|
||||
# 无敌标志
|
||||
self.super_mode = False
|
||||
|
||||
def update(self):
|
||||
"""根据移动标志调整飞船位置"""
|
||||
if self.moving_right and self.rect.right < self.screen_rect.right:
|
||||
self.center += self.ai_settings.ship_speed_factor
|
||||
if self.moving_left and self.rect.left > self.screen_rect.left:
|
||||
self.center -= self.ai_settings.ship_speed_factor
|
||||
|
||||
self.rect.centerx = self.center
|
||||
|
||||
|
||||
def blitme(self):
|
||||
"""在指定位置绘制飞船"""
|
||||
self.screen.blit(self.image, self.rect)
|
||||
|
||||
if self.super_mode:
|
||||
# 无敌模式,绘制金色边框
|
||||
pygame.draw.rect(self.screen, (200, 200, 0),(self.rect), 2)
|
||||
|
||||
def center_ship(self):
|
||||
self.rect.centerx = self.screen_rect.centerx
|
|
@ -0,0 +1,16 @@
|
|||
import pygame
|
||||
from bullet import Bullet
|
||||
|
||||
|
||||
class SuperBullet(Bullet):
|
||||
"""一个对飞船发射的超级子弹进行管理的类"""
|
||||
|
||||
def __init__(self, ai_settings, screen, ship):
|
||||
"""在飞船所处的位置创建一个子弹对象"""
|
||||
super().__init__(ai_settings, screen, ship)
|
||||
|
||||
# 设置超级子弹宽高,颜色及速度
|
||||
self.rect.width = ai_settings.super_bullet_width
|
||||
self.rect.height = ai_settings.super_bullet_height
|
||||
self.color = ai_settings.super_bullet_color
|
||||
self.speed_factor = ai_settings.super_bullet_speed_factor
|
|
@ -0,0 +1,28 @@
|
|||
配置:
|
||||
|
||||
pygame版本 1.9.4
|
||||
python版本 3.6.0
|
||||
主文件为alien_invasion.py
|
||||
---------------------------------
|
||||
|
||||
游戏指南:
|
||||
|
||||
鼠标点击白色“Your Name”输入框,输入你的名字
|
||||
点击“play”开始游戏
|
||||
|
||||
操作:
|
||||
|
||||
方向左右键控制移动
|
||||
空格键发射子弹
|
||||
|
||||
每消灭一个敌人会获得一定积分(右上角显示),随Level提高游戏难度会加大,
|
||||
相应的击中奖励积分会增加,每累计一定积分可获得一点能量值。
|
||||
|
||||
右下角的Power值表示剩余能量值,有两种可选用途(每次均消耗1点能量):
|
||||
1. 按方向上键,获得5秒无敌状态,不会被敌人子弹击中
|
||||
2. 按左Alt键,发射超级子弹,比普通子弹更大,且命中一个敌人后不会
|
||||
立刻消失,使用得当可消灭整列4个敌人
|
||||
|
||||
|
||||
游戏结束会显示5秒排行榜Top10, 期间不可操作,过后可再次点击Play重新开始
|
||||
游戏。(没有注销系统,游戏期间无法更改用户名)
|
Loading…
Reference in New Issue