pygame - 如何在没有 time.sleep() 的情况下缓慢更新 HP bar [英] pygame - how to update HP bar slowly without time.sleep()

查看:71
本文介绍了pygame - 如何在没有 time.sleep() 的情况下缓慢更新 HP bar的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm creating a game in pygame and I want to decrease the player's HP slowly yet in real time. For this, I know that I can't use time.sleep() because it freezes the whole game. I've tried using threading.Thread on pygame.MOUSEBUTTONDOWN to do an amount of damage to the player, but it did not work. Keep in mind that it is my first time using threads ever.

我的代码:

#-*- 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(),但是程序做的是:

Am I using threads wrong? I want to execute the p1.remove_HP() and p1.move() at the same time, but what the program does is:

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

1º:p1.move()

2º:p1 停止移动

3º:p1.remove_HP()

4º:p1 再次移动

对不起,如果它很愚蠢,但我真的在努力学习.提前致谢!

Sorry if it is stupid but I'm really trying and studying. Thanks in advance!

推荐答案

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

You don't need threads at all. Don't make your life more complicated than it has to be.

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

You just need a different thinking about how your game runs. It runs in a loop; in your case it runs at 60 fps.

所以如果你想随着时间的推移做任何事情,你有不同的选择:

So if you want to do anything over time, you have different options:

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

1) Make a variable, increase it every frame, and once it hits 60, you know 1 second passed (easy, but not reliable since you depend on a constant frame rate)

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

2) Use events. In pygame, you can create custom events that you can trigger manually or periodically, and handle them in your main loop like pygame's build in events (works good for simple use cases, but the amount of events you can create is limited)

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

3) Make a variable and store a time stamp in it. A time stamp can be the system time or something else, like the amount of ticks since your game started (using e.g. pygame's pygame.time.get_ticks. Then, every frame compare it to the current system time or ticks to calculate how much time has passed

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

I updated your code a little bit. Note how the I seperated the different concerns into different parts of the code:

  • player 类只关心自己(位置、移动、hp),而不关心整个屏幕是如何管理的
  • GUI 类只关心绘制 GUI
  • 主循环不关心屏幕上的内容

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

I just decrease the hp a tiny bit each frame (which is basically a form of option 1 I listed above); it's a good-enough approach to your problem.

#-*- 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)

这篇关于pygame - 如何在没有 time.sleep() 的情况下缓慢更新 HP bar的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆