单文件实现alien_invasion项目

第一步:合并代码,直接合并后测试可以直接运行,代码一共有405行
第二步:删除重复的import语句
pygame.font不需要单独引入
settings、game_stats、button、scoreboard、ship、alien类直接在文件中定义,不需要再引入
game_factions类中的函数直接在文件中定义,不需要引入,删除并修改函数调用时的名称(去掉别名gf)
代码还有381行,测试运行无问题
第三步:调整下类的顺序
第四步:分析精简代码
增加变量screen_rect,作为参数传递,减少self.screen=screen和self.screen_rect=self.screen.get_rect()的使用
代码还有378行,测试运行没有问题
第五步:函数部分
按照程序运行的逻辑顺序调整函数,减少函数名和函数的调用,减少函数的嵌套
第六步:减少不必要的计算函数,外星人每行个数为9,行数为4,不再需要传递ship参数
第七步:不变的值直接使用值,减少变量个数

完成后代码在300行以内,所有功能不变。
完结。

附上所有代码

import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
import sys
from time import sleep

class Settings():
    def initialize_dynamic_settings(self):    # 动态设置,等级提升后会相应提升数值
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        self.fleet_direction = 1    # 1表示向右,-1表示向左
        self.alien_points = 50

    def increase_speed(self):
        self.ship_speed_factor *= 1.1
        self.bullet_speed_factor *= 1.1
        self.alien_speed_factor *= 1.1
        self.alien_points = int(self.alien_points * 1.5)

class GameStats():
    def __init__(self):
        self.reset_stats()
        self.game_active = False
        self.high_score = 0
    
    def reset_stats(self):
        self.ships_left = 3
        self.score = 0
        self.level = 1

class Button():
    def __init__(self,msg,screen_rect):
        self.rect = pygame.Rect(0,0,200,50)
        self.rect.center = screen_rect.center
        self.prep_msg(msg)
    
    def prep_msg(self,msg):
        self.msg_image = pygame.font.SysFont(None,48).render(msg,True,(255,255,255),(0,255,0))
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center

    def draw_button(self,screen):
        screen.fill((0,255,0),self.rect)    # 显示矩形
        screen.blit(self.msg_image,self.msg_image_rect)    # 显示文字Play

class Scoreboard():
    def __init__(self,ai_settings,stats,screen_rect,screen):
        self.ai_settings = ai_settings
        self.stats = stats

        self.prep_score()    # 当前分数
        self.prep_high_score(screen_rect)    # 最高分数
        self.prep_level()    # 当前等级
        self.prep_ships(screen,screen_rect)    # 剩余飞船数量

    def prep_score(self):
        rounded_score = int(round(self.stats.score,-1))    # -1表示小数点左侧前一位四舍五入
        score_str = "{:,}".format(rounded_score)    # 千位分隔符
        self.score_image = pygame.font.SysFont(None,48).render(score_str,True,(30,30,30),(230,230,230))
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = 1180
        self.score_rect.top = 20
    
    def prep_high_score(self,screen_rect):
        high_score = int(round(self.stats.high_score,-1))
        high_score_str = "{:,}".format(high_score)
        self.high_score_image =pygame.font.SysFont(None,48).render(high_score_str,True,(30,30,30),(230,230,230))
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.centerx = screen_rect.centerx
        self.high_score_rect.top = 20

    def prep_level(self):
        self.level_image = pygame.font.SysFont(None,48).render(str(self.stats.level),True,(30,30,30),(230,230,230))
        self.level_rect = self.level_image.get_rect()
        self.level_rect.right = 1180
        self.level_rect.top = self.score_rect.bottom + 10

    def prep_ships(self,screen,screen_rect):
        self.ships = Group()
        for ship_number in range(self.stats.ships_left):    # 以图片数量表示剩余飞船个数
            ship = Ship(screen,self.ai_settings,screen_rect)
            ship.rect.x = 10 + ship_number * ship.rect.width
            ship.rect.y = 10
            self.ships.add(ship)

    def show_score(self,screen):
        screen.blit(self.score_image,self.score_rect)
        screen.blit(self.high_score_image,self.high_score_rect)
        screen.blit(self.level_image,self.level_rect)
        self.ships.draw(screen)

class Ship(Sprite):
    def __init__(self,screen,ai_settings,screen_rect):
        super().__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        self.image = pygame.image.load("images/ship.bmp")
        self.rect = self.image.get_rect()
        self.rect.centerx = screen_rect.centerx
        self.rect.bottom = screen_rect.bottom
        self.center = float(self.rect.centerx)

        self.moving_right = False
        self.moving_left = False

    def update(self):
        if self.moving_right and self.rect.right < 1200:
            self.center += self.ai_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:
            self.center -= self.ai_settings.ship_speed_factor

        self.rect.centerx = self.center

    def blitme(self):
        self.screen.blit(self.image,self.rect)
    
    def center_ship(self,screen_rect):
        self.center = screen_rect.centerx

class Bullet(Sprite):
    def __init__(self,ai_settings,ship):
        super().__init__()
        self.rect = pygame.Rect(0,0,3,15)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        self.y = float(self.rect.y)
        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,screen):
        pygame.draw.rect(screen,(60,60,60),self.rect)

class Alien(Sprite):
    def __init__(self,ai_settings):
        super().__init__()
        self.ai_settings = ai_settings

        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
        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_events(ship,ai_settings,bullets,play_button,stats,aliens,sb,screen_rect,screen):    # 事件循环
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            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 len(bullets) < 3:    # 开火,发射子弹并加入编组
                    new_bullet = Bullet(ai_settings,ship)
                    bullets.add(new_bullet)
            elif event.key == pygame.K_q:
                sys.exit()
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = False
            elif event.key == pygame.K_LEFT:
                ship.moving_left = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(play_button,mouse_x,mouse_y,stats,aliens,bullets,ai_settings,ship,sb,screen_rect,screen)

def check_play_button(play_button,mouse_x,mouse_y,stats,aliens,bullets,ai_settings,ship,sb,screen_rect,screen):
    button_clicked = play_button.rect.collidepoint(mouse_x,mouse_y)
    if button_clicked and not stats.game_active:    # 点击Play按钮
        ai_settings.initialize_dynamic_settings()
        pygame.mouse.set_visible(False)    # 游戏中隐藏鼠标
        stats.reset_stats()
        stats.game_active = True

        sb.prep_score()
        sb.prep_high_score(screen_rect)
        sb.prep_level()
        sb.prep_ships(screen,screen_rect)

        aliens.empty()
        bullets.empty()

        create_fleet(ai_settings,aliens)
        ship.center_ship(screen_rect)
    
def update_bullets(bullets,aliens,ai_settings,stats,sb,screen_rect):
    bullets.update()    # 更新子弹位置
    for bullet in bullets.copy():    # 检测到达屏幕顶部的子弹并将其删除
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    
    collisions = pygame.sprite.groupcollide(bullets,aliens,False,True)    # 子弹和外星人碰撞检测
    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_points * len(aliens)
            sb.prep_score()

        if stats.score > stats.high_score:    # 检查最高得分
            stats.high_score = stats.score
            sb.prep_high_score(screen_rect)

    if len(aliens) == 0:
        bullets.empty()
        ai_settings.increase_speed()
        stats.level += 1
        sb.prep_level()
        create_fleet(ai_settings,aliens)

def create_fleet(ai_settings,aliens):    # 创建外星人群
    for row_number in range(4):
        for alien_number in range(9):
            alien = Alien(ai_settings)
            alien_width = alien.rect.width
            alien.x = alien_width + 2 * alien_width * alien_number
            alien.rect.x = alien.x
            alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number
            aliens.add(alien)

def ship_hit(stats,aliens,bullets,ship,ai_settings,sb,screen,screen_rect):    # 飞船碰撞后重置游戏
    if stats.ships_left > 0:
        stats.ships_left -= 1
        sb.prep_ships(screen,screen_rect)
        aliens.empty()
        bullets.empty()
        create_fleet(ai_settings,aliens)
        ship.center_ship(screen_rect)
        sleep(0.5)
    else:
        stats.game_active = False
        pygame.mouse.set_visible(True)

def update_aliens(aliens,ai_settings,ship,stats,bullets,screen_rect,sb,screen):
    for alien in aliens.sprites():    # 到达屏幕边缘时,向下移动,并改变移动方向
        if alien.rect.right >= 1200 or alien.rect.left <= 0:
            for alien in aliens.sprites():
                alien.rect.y += 10
            ai_settings.fleet_direction *= -1
            break
    
    aliens.update()

    if pygame.sprite.spritecollideany(ship,aliens):    # 飞船与外星人碰撞检测
        ship_hit(stats,aliens,bullets,ship,ai_settings,sb,screen,screen_rect)
    
    for alien in aliens.sprites():
        if alien.rect.bottom >= screen_rect.bottom:
            ship_hit(stats,aliens,bullets,ship,ai_settings,sb,screen,screen_rect)
            break

def run_game():
    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((1200,800))
    screen_rect = screen.get_rect()
    pygame.display.set_caption("Alien Invasion")
    
    stats = GameStats()
    play_button = Button("Play",screen_rect)
    sb = Scoreboard(ai_settings,stats,screen_rect,screen)
    ship = Ship(screen,ai_settings,screen_rect)
    bullets = Group()
    aliens = Group()

    create_fleet(ai_settings,aliens)

    while True:
        screen.fill((230,230,230))
       
        check_events(ship,ai_settings,bullets,play_button,stats,aliens,sb,screen_rect,screen)
        
        if stats.game_active:
            ship.update()
            update_bullets(bullets,aliens,ai_settings,stats,sb,screen_rect)
            update_aliens(aliens,ai_settings,ship,stats,bullets,screen_rect,sb,screen)
                
        for bullet in bullets.sprites():
            bullet.draw_bullet(screen)

        ship.blitme()
        aliens.draw(screen)
        sb.show_score(screen)

        if not stats.game_active:
            play_button.draw_button(screen)
       
        pygame.display.flip()

run_game()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逆旅匆匆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值