python - pygame - 如何在没有 time.sleep() 的情况下缓慢更新 HP 条

标签 python multithreading time pygame

我正在 pygame 中创建一个游戏,我想实时缓慢地降低玩家的 HP。为此,我知道我不能使用 time.sleep() ,因为它会卡住整个游戏。我尝试在 pygame.MOUSEBUTTONDOWN 上使用 threading.Thread 对玩家造成一定程度的伤害,但没有成功。请记住,这是我第一次使用线程。

我的代码:

#-*- coding-utf8 -*-
import pygame
import threading
import time
import os

os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()

SIZE = (1200, 600)
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()

class Player:
    def __init__(self):
        self.HP = 100
        self.HP_BAR = pygame.Rect(10, 10, self.HP * 3, 10)

        self.X = 100
        self.Y = 100
        self.WIDTH = 50
        self.HEIGHT = 100
        self.COLOR = (255,255,0)
        self.PLAYER = pygame.Rect(self.X, self.Y, self.WIDTH, self.HEIGHT)

    def move(self):
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_w]: self.Y -= 1
        if pressed[pygame.K_s]: self.Y += 1
        if pressed[pygame.K_a]: self.X -= 1
        if pressed[pygame.K_d]: self.X += 1

        self.PLAYER = pygame.Rect(self.X, self.Y, self.WIDTH, self.HEIGHT)

    def draw(self):
        # clear screen
        screen.fill((0,0,0))

        # draw HP bar
        self.HP_BAR = pygame.Rect(10, 10, self.HP * 3, 10)
        pygame.draw.rect(screen, (50,0,0), self.HP_BAR)

        # draw player
        pygame.draw.rect(screen, self.COLOR, self.PLAYER)

        pygame.display.flip()

    def remove_HP(self, value):
        for x in range(value):
            self.HP -= 1
            self.draw()
            # time.sleep(0.1)

p1 = Player()

while True:  

    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            exit()

        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            td2 = threading.Thread(target = p1.remove_HP(20), name = "td2")
            td2.daemon = True
            td2.start()

    p1.move()
    p1.draw()

    clock.tick(60)

我使用线程错误吗?我想同时执行 p1.remove_HP()p1.move(),但程序的作用是:

用户在按下 [A] 的同时进行点击

1°:p1.move()

2°:p1 停止移动

3°:p1.remove_HP()

4°:p1 再次移动

抱歉,如果这很愚蠢,但我真的在努力和学习。提前致谢!

最佳答案

你根本不需要线程。不要让你的生活变得过于复杂。

您只需要对游戏的运行方式有不同的思考。它循环运行;在你的情况下,它以 60 fps 运行。

因此,如果您想随着时间的推移做任何事情,您有不同的选择:

1)创建一个变量,每帧增加它,一旦达到 60,您就知道 1 秒过去了(简单,但不可靠,因为您依赖于恒定的帧速率)

2) 使用事件。在 pygame 中,您可以创建可以手动或定期触发的自定义事件,并在主循环中处理它们,例如 pygame 的内置事件(适用于简单的用例,但您可以创建的事件数量有限)

3) 创建一个变量并在其中存储时间戳。时间戳可以是系统时间或其他时间,例如自游戏开始以来的刻度数(使用例如 pygame 的 pygame.time.get_ticks )。然后,每一帧都会将其与当前系统时间或刻度线来计算已经过去了多少时间

我稍微更新了你的代码。请注意我如何将不同的关注点分成代码的不同部分:

  • 玩家类只关心自身(位置、移动、hp),而不关心整个屏幕的管理方式
  • GUI类只关心绘制GUI
  • 主循环不关心屏幕上的内容

我只是将每一帧的马力降低一点(这基本上是我上面列出的选项 1 的一种形式);这是解决您的问题的一个足够好的方法。

#-*- coding-utf8 -*-
import pygame
import threading
import time
import os

os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()

SIZE = (1200, 600)
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()

class GUI(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((1200, 600))
        self.image.set_colorkey((12,34,56))
        self.image.fill((12,34,56))
        self.rect = self.image.get_rect()
        self.player = None

    def update(self):
        self.image.fill((12,34,56))
        if self.player:
            pygame.draw.rect(self.image, (50, 0, 0), pygame.Rect(10, 10, self.player.hp * 3, 10))

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()

        self.image = pygame.Surface((50, 100))
        self.image.fill((255,255,0))
        self.rect = self.image.get_rect(topleft=(100, 100))

        self.hp = 100

    def update(self):
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_w]: self.rect.move_ip( 0, -1)
        if pressed[pygame.K_s]: self.rect.move_ip( 0,  1)
        if pressed[pygame.K_a]: self.rect.move_ip(-1,  0)
        if pressed[pygame.K_d]: self.rect.move_ip( 1,  0)

        self.hp -= 0.05

p1 = Player()
gui = GUI()
gui.player = p1
sprites = pygame.sprite.Group(p1, gui)

while True:  

    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            exit()

    screen.fill((0,0,0))
    sprites.update()
    sprites.draw(screen)
    pygame.display.flip()
    clock.tick(60)

关于python - pygame - 如何在没有 time.sleep() 的情况下缓慢更新 HP 条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53587615/

相关文章:

python setup.py test 使用 pytest 时无法精细测试

python - 使用webclient.Agent时connectionLost可能出现哪些异常?

swift - 具有不相关托管对象上下文的 Google 地点选择器的 CoreData 线程问题

java - Java中多生产者单消费者的软件设计

perl - 将旧的 Unix 日期转换为 Perl 并进行比较

c++ - 如果时刻恰好在冬季结束时(非夏令时),日期/时间转换问题

python - 在 webdriver 和请求之间复制 cookie 时出错

ios - 如果未设置变量,则等待设置变量

php - 检查两次是否重叠

Python 2.7、Appengine 数据存储和 Unicode