Python新手晋级路 2023-01-02 16:30 采纳率: 58.3%
浏览 39
已结题

自主扩展游戏《外星人入侵》时遇到的问题

扩展了技能(一技能:高能子弹,即子弹与外星人碰撞一次后仍能使用而不消失,按住“1”键即可使用;二技能:超能子弹,即子弹宽度由3变为300,按住“2”键即可使用;被动技能:清屏,即外星人到达屏幕底部时,清空所有剩余外星人,被动技能仍有使用限制)并限制了其使用次数。技能在使用与数量检测方面均正常。随即为让玩家知道使用次数有或还剩多少,显示数量的位置及开始游戏前界面如图(为了能让飞船大体上不被遮挡,字号调的小,位置在下方两侧)。

img

遇到的问题是,原计划是每使用一次,可使用次数减1(技能数量检测方面就需要这样,所以这一步没问题),然后立即在界面中刷新一次可用次数并显示。可实际上直到技能次数用完技能不可用时,显示的还是技能数量的初始值,过程中没见任何变化。觉得应该是代码写的有地方有问题,但用了很长时间也没找出怎样达到目的的方法,便请各位帮忙解答。非常谢谢回答的各位!
以下是与问题有关的代码文件。

主程序:外星人入侵

import sys
import pygame
# 引用所需的其它模块
from time import sleep  # 时间控制模块(time模块),sleep:使之暂停

# 引用与游戏成分或元素相关的类
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
from game_stats import GameStats
from button import Button
from scoreboard import Scoreboard

from use_skill import Use_skill


class AlienInvasion:
    def __init__(self):
        pygame.init()  # 表明初始化的是与游戏元素相关的设置
        # 初始化背景设置:
        self.settings = Settings()  # 先调用游戏设置
        """屏幕设置:pygame.display.set_mode((表示屏幕宽高的元组))"""
        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)  # screen的对象是一个surface,用于显示游戏元素
        # 以上行代码意义:屏幕从原点(0, 0)开始布置,直至全屏【pygame.FULLSCREEN】
        # 使用屏幕的rect属性width和height来更新对象settings
        self.settings.screen_width = self.screen.get_rect().width
        self.settings.screen_height = self.screen.get_rect().height

        pygame.display.set_caption('外星人入侵')  # 显示标题为:外星人入侵(Alien Invasion)
        # 初始化游戏元素:
        self.ship = Ship(self)  # 调用飞船设置
        self.bullets = pygame.sprite.Group()  # 调用子弹设置,同时调用sprite.Group()对其进行批量管理
        self.aliens = pygame.sprite.Group()  # 调用外星人设置,同时调用sprite.Group()对其进行批量管理
        self._create_fleet()  # 创建一批新的外星人
        self.stats = GameStats(self)  # 调用游戏信息统计系统
        self.sb = Scoreboard(self)
        self.play_button = Button(self, 'Play')  # 调用(开始)按钮

        self.use_skill = Use_skill(self)

    def run_game(self):
        """控制并运行游戏的方法"""
        while True:
            self._check_events()  # 监视键盘和鼠标事件,并执行相关活动代码

            if self.stats.game_active:
                self.ship.update()  # 执行相关代码,让飞船可移动
                self._update_bullet()  # 执行相关代码,使子弹出现后绘制更新
                self._update_aliens()  # 执行相关代码,使外星人数量与位置时刻发生着变化
            self._update_screen()  # 执行相关代码,使背景与飞船绘制更新

            # 让子弹完全到达屏幕外面时消失(删除)
            """循环检查子弹是否完全到达屏幕外面"""
            for bullet in self.bullets.copy():  # 方法copy():建立副本。注意:不能从for循环遍历的列表或元组中删除元素,只能删其副本
                if bullet.rect.bottom <= 0:  # 当子弹底部到达屏幕顶部时
                    self.bullets.remove(bullet)  # 将其从编组中删除

    def _check_events(self):
        """单独用来响应按键和鼠标及事件的方法"""
        for event in pygame.event.get():  # 循环监视事件
            # 以下两行代码之所以必要存在,是因为要使其右上角的“X”键生效
            if event.type == pygame.QUIT:  # 如果事件类型为“退出”
                # 【练习】为防止每次重启游戏最高分都被重置,刻意保存数据:
                self.sb.save_high_score(self.stats.high_score)

                sys.exit()  # 则退出程序

            elif event.type == pygame.KEYDOWN:  # 如果监视到有键按下(“有键按下”为事件类型)
                self._check_keydown_events(event)  # 调用按键按下方法
            elif event.type == pygame.KEYUP:  # 如果监视到有键有键弹起(“有键弹起”为事件类型)
                self._check_keyup_events(event)  # 调用按键弹起方法

            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_pos = pygame.mouse.get_pos()
                self._check_play_button(mouse_pos)

    def start_game(self):
        self.stats.reset_stats()
        self.stats.game_active = True
        self.sb.prep_score()
        self.sb.prep_level()
        self.sb.prep_ships()

        self.use_skill.prep_skill()

        self.aliens.empty()
        self.bullets.empty()

        self._create_fleet()
        self.ship.center_ship()

    def _check_play_button(self, mouse_pos):
        button_clicked = self.play_button.rect.collidepoint(mouse_pos)
        if button_clicked and not self.stats.game_active:
            self.settings.initialize_dynamic_settings()

            self.start_game()

            pygame.mouse.set_visible(False)

    def _check_keydown_events(self, event):
        """单独用来监视按下按键名称的方法"""
        if event.key == pygame.K_RIGHT:  # 如果监视到的按下按键为右方向键
            self.ship.moving_right = True  # (允许)飞船向右移动
        elif event.key == pygame.K_LEFT:  # 如果监视到的按下按键为左方向键
            self.ship.moving_left = True  # (允许)飞船向左移动
        elif event.key == pygame.K_SPACE:  # 如果监视到的按下按键为空格键
            self._fire_bullet()  # 飞船开火

        elif event.key == pygame.K_q:  # 如果监视到的按下按键为“q”键
            # 【练习】为防止每次重启游戏最高分都被重置,刻意保存数据:
            self.sb.save_high_score(self.stats.high_score)

            sys.exit()  # 退出程序

        # 【练习】按P键开始新游戏:
        elif event.key == pygame.K_p:
            self.start_game()

            pygame.mouse.set_visible(False)
        # 按下键允许使用技能:
        elif event.key == pygame.K_1:
            self.skill1_time()
        elif event.key == pygame.K_2:
            self.skill2_time()

    def _check_keyup_events(self, event):
        """单独用来监视弹起按键名称的方法"""
        if event.key == pygame.K_RIGHT:  # 如果监视到的弹起按键为右方向键
            self.ship.moving_right = False  # 飞船停止向右移动(不允许飞船向右移动)
        elif event.key == pygame.K_LEFT:  # 如果监视到的弹起按键为左方向键
            self.ship.moving_left = False  # 飞船停止向左移动(不允许飞船向左移动)
        # 按键弹起禁止使用技能:
        elif event.key == pygame.K_1:
            self.use_skill.use_skill1 = False

            self.use_skill.prep_skill1()

        elif event.key == pygame.K_2:
            self.use_skill.use_skill2 = False

            self.use_skill.prep_skill2()

    def super_bullets(self):
        if self.use_skill.use_skill2:
            self.settings.bullet_width = 300
        else:
            self.settings.bullet_width = 3

    def skill1_time(self):
        if self.stats.skill1_number <= 0:
            self.use_skill.use_skill1 = False
        else:
            self.use_skill.use_skill1 = True
            self.stats.skill1_number -= 1

    def skill2_time(self):
        if self.stats.skill2_number <= 0:
            self.use_skill.use_skill2 = False
        else:
            self.use_skill.use_skill2 = True
            self.stats.skill2_number -= 1

    def _update_screen(self):
        """更新屏幕上的图像,并切换到新屏幕"""
        self.screen.fill(self.settings.bg_color)
        """每次循环都重再绘制飞船"""
        self.ship.blitme()
        """绘制外星人"""
        self.aliens.draw(self.screen)  # 方法draw()接受一个参数,这个参数指定了要将编组中的元素绘制到哪个surface(即为self.screen)上
        """绘制所得分"""
        self.sb.show_score()

        self.use_skill.show()

        """调用二技能:超能子弹"""
        self.super_bullets()  # 对二技能实时检测,符合条件时将普通子弹转化为超能子弹
        """如果游戏处于非活动状态,就绘制play按钮"""
        if not self.stats.game_active:
            self.play_button.draw_button()

            # 【练习】为防止每次重启游戏最高分都被重置, 刻意保存并读取后显示
            self.sb.read_high_score()
            self.sb.prep_high_score()

            pygame.display.flip()

    def _fire_bullet(self):
        """发射子弹"""
        if len(self.bullets) < self.settings.bullet_allowed:  # 这里是为了检查子弹数量是否到达限定数量。若未到达时
            new_bullet = Bullet(self)  # (继续)创建一个新子弹
            self.bullets.add(new_bullet)  # 并加入到其编组中

    def _update_bullet(self):
        """更新屏幕上显示的子弹"""
        self.bullets.update()  # 调用子弹元素中的使其位置发生变化的方法update()

        for bullet in self.bullets.sprites():  # 对子弹调用sprites()编组管理方法,以不断的
            bullet.draw_bullet()  # 在屏幕上绘制出子弹
        pygame.display.flip()  # 让最近的相关绘制(这里是子弹)可见

        self._check_bullet_alien_collision()  # 响应子弹和外星人的碰撞并执行相关代码

    def _check_bullet_alien_collision(self):
        """单独响应子弹和外星人的碰撞""
        """"sprite中groupcollide【汉语:编组碰撞】()方法:检查两个其编组是否有重叠部分,若有是否删除"""
        """用法:groupcollide(编组1, 编组2, 编组1是否删除, 编组2是否删除)"""
        collisions = {}
        if not self.use_skill.use_skill1:
            collisions_1 = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True)
            for key, value in collisions_1.items():
                collisions[key] = value
        else:
            collisions_0 = pygame.sprite.groupcollide(self.bullets, self.aliens, False, True)
            for key, value in collisions_0.items():
                collisions[key] = value

        if collisions:
            for aliens in collisions.values():
                self.stats.score += self.settings.alien_points * len(aliens)
            self.sb.prep_score()

            self.sb.check_high_score()

        if not self.aliens:
            self.bullets.empty()
            self._create_fleet()

            self.settings.increase_speed()

            self.stats.level += 1
            self.sb.prep_level()

    def _create_fleet(self):
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        available_space_x = self.settings.screen_width - (2 * alien_width)
        number_alien_x = available_space_x // (2 * alien_width)
        ship_height = self.ship.rect.height
        available_space_y = self.settings.screen_height - (3 * alien_height) - ship_height
        number_rows = available_space_y // (2 * alien_height)
        for row_number in range(number_rows):
            for alien_number in range(number_alien_x):
                self._create_alien(alien_number, row_number)

    def _create_alien(self, alien_number, row_number):
        alien = Alien(self)
        alien_width, alien_height = alien.rect.size
        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
        self.aliens.add(alien)

    def _check_fleet_edges(self):
        for alien in self.aliens.sprites():
            if alien.check_edges():
                self._check_fleet_direction()
                break

    def _check_fleet_direction(self):
        for alien in self.aliens.sprites():
            alien.rect.y += self.settings.fleet_drop_speed
        self.settings.fleet_direction *= -1

    def _update_aliens(self):
        self._check_fleet_edges()
        self.aliens.update()

        if pygame.sprite.spritecollideany(self.ship, self.aliens):
            self._ship_hit()
        self._check_aliens_bottom()

    def _check_aliens_bottom(self):
        screen_rect = self.screen.get_rect()
        for alien in self.aliens.sprites():
            if alien.rect.bottom >= screen_rect.bottom:
                if self.stats.skill0_number >= 0:
                    self.aliens.empty()  # 这是被动技能表现
                    self.stats.skill0_number -= 1

                    self.use_skill.prep_skill0()

                else:
                    self._ship_hit()  # 如果被动技能用完,则响应飞船碰撞
                break

    def _ship_hit(self):
        if self.stats.ship_live > 0:
            self.stats.ship_live -= 1
            self.sb.prep_ships()

            self.aliens.empty()
            self.bullets.empty()

            self._create_fleet()
            self.ship.center_ship()

            sleep(1.0)
        else:
            self.stats.game_active = False

            pygame.mouse.set_visible(True)


# 让程序运行:
if __name__ == '__main__':
    ai = AlienInvasion()  # 运行的程序
    ai.run_game()  # 循环运行

Use_skill.py>>>

import pygame.font

from settings import Settings
from game_stats import GameStats

from scoreboard import Scoreboard


class Use_skill:
    def __init__(self, ai_game):
        self.sb = Scoreboard(ai_game)
        self.skill1_image = None
        self.skill1_rect = None
        self.skill2_image = None
        self.skill2_rect = None
        self.skill0_image = None
        self.skill0_rect = None

        self.ai_game = ai_game
        self.settings = Settings()
        self.stats = GameStats(self)
        self.screen = self.ai_game.screen
        self.screen_rect = self.screen.get_rect()
        self.use_skill1 = False
        self.use_skill2 = False

        self.text_color = (30, 30, 30)
        self.text1 = f'One skill:{self.stats.skill1_number}'
        self.text2 = f'Two skill:{self.stats.skill2_number}'
        self.text0 = f'Passive skill:{self.stats.skill0_number}'

        self.font = pygame.font.SysFont(None, 24)

        self.prep_skill()

    def prep_skill1(self):
        skill1 = self.text1
        self.skill1_image = self.font.render(skill1, True, self.text_color, self.settings.bg_color)
        self.skill1_rect = self.skill1_image.get_rect()
        self.skill1_rect.left = self.screen_rect.left + 10
        self.skill1_rect.bottom = self.screen_rect.bottom

    def prep_skill2(self):
        skill2 = self.text2
        self.skill2_image = self.font.render(skill2, True, self.text_color, self.settings.bg_color)
        self.skill2_rect = self.skill2_image.get_rect()
        self.skill2_rect.left = self.screen_rect.left + self.skill1_rect.right + 20
        self.skill2_rect.bottom = self.screen_rect.bottom

    def prep_skill0(self):
        skill0 = self.text0
        self.skill0_image = self.font.render(skill0, True, self.text_color, self.settings.bg_color)
        self.skill0_rect = self.skill0_image.get_rect()
        self.skill0_rect.right = self.screen_rect.right - 20
        self.skill0_rect.bottom = self.screen_rect.bottom

    def prep_skill(self):
        self.prep_skill1()
        self.prep_skill2()
        self.prep_skill0()

    def show(self):
        self.screen.blit(self.skill1_image, self.skill1_rect)
        self.screen.blit(self.skill2_image, self.skill2_rect)
        self.screen.blit(self.skill0_image, self.skill0_rect)

game_stats.py>>>

class GameStats:
    def __init__(self, ai_game):

        self.skill0_number = None
        self.skill1_number = None
        self.skill2_number = None
        self.level = None  # 个人认为无效操作
        self.score = None  # 个人认为无效操作
        self.ship_live = None  # 个人认为无效操作

        self.settings = ai_game.settings
        self.reset_stats()
        self.game_active = False  # 让游戏一开始处于非活动状态,以使play按钮有效

        self.high_score = 0

    def reset_stats(self):
        self.ship_live = self.settings.ship_limit

        self.score = 0
        self.level = 1

        self.skill1_number = 10
        self.skill2_number = 8
        self.skill0_number = 5
  • 写回答

2条回答 默认 最新

  • 请叫我问哥 Python领域新星创作者 2023-01-02 18:08
    关注

    这三行在数字变化后,并没有更新,所以每次刷新调用的还是最初的text1、text2、text0

            self.text1 = f'One skill:{self.stats.skill1_number}'
            self.text2 = f'Two skill:{self.stats.skill2_number}'
            self.text0 = f'Passive skill:{self.stats.skill0_number}'
    
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 1月13日
  • 创建了问题 1月2日

悬赏问题

  • ¥15 matlab数据降噪处理,提高数据的可信度,确保峰值信号的不损失?
  • ¥15 怎么看我在bios每次修改的日志
  • ¥15 python+mysql图书管理系统
  • ¥15 Questasim Error: (vcom-13)
  • ¥15 船舶旋回实验matlab
  • ¥30 SQL 数组,游标,递归覆盖原值
  • ¥15 为什么我的数据接收的那么慢呀有没有完整的 hal 库并 代码呀有的话能不能发我一份并且我用 printf 函数显示处理之后的数据,用 debug 就不能运行了呢
  • ¥20 gitlab 中文路径,无法下载
  • ¥15 用动态规划算法均分纸牌
  • ¥30 udp socket,bind 0.0.0.0 ,如何自动选取用户访问的服务器IP来回复数据