pygame-如何在没有时间的情况下缓慢更新HP bar.sleep()

时间:2018-12-03 04:46:15

标签: python multithreading time pygame

我正在pygame中创建游戏,我想实时降低玩家的HP。为此,我知道我不能使用time.sleep(),因为它冻结了整个游戏。我曾尝试在threading.Thread上使用pygame.MOUSEBUTTONDOWN对播放器造成一定程度的损害,但没有奏效。请记住,这是我第一次使用线程。

我的代码:

#-*- 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再次移动

对不起,如果它很愚蠢,但我确实在尝试和学习。预先感谢!

1 个答案:

答案 0 :(得分:1)

您根本不需要线程。不要让您的生活变得不必要的复杂。

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

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

1)制作一个变量,每帧增加一次,当它达到60时,您知道已经过去了1秒(这很简单,但是不可靠,因为您依赖于恒定的帧频)

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

3)创建一个变量并在其中存储时间戳。时间戳记可以是系统时间,也可以是其他时间,例如游戏开始以来的滴答声数量(例如,使用pygame的pygame.time.get_ticks。然后,每帧将其与当前系统时间或滴答声进行比较,以计算多少时间)通过

我稍微更新了您的代码。注意我如何将不同的关注点分离到代码的不同部分:

  • 播放器类仅关心自身(位置,移动,马力),而不关心整个屏幕的管理方式
  • 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)