如何在 pygame 中制作波浪计时器 [英] How to make a wave timer in pygame

查看:34
本文介绍了如何在 pygame 中制作波浪计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我对编程完全陌生(已经做了几个月)并决定尝试编写游戏代码.在这一点上,非常感谢 Chris Bradfield 在 pygame 编码方面的系列教程,它们绝对很棒!但是,现在我已经完成了教程并且需要自己工作,我遇到了一个问题.我正在制作一个自上而下的射击游戏并使其基于波浪.所以,当一波僵尸死亡时,我想展示一个倒计时直到下一波开始的计时器.我认为我在正确的道路上自动取款机,让我告诉你我在做什么.

def new(self)'''self.timer_flag = Falseself.x = threading.Thread(target=self.countdown, args=(TIME_BETWEEN_WAVES,))'''def 倒计时(自我,time_between_waves):self.wave_timer = time_between_waves对于我在范围内(TIME_BETWEEN_WAVES):而 self.timer_flag:self.wave_timer -=时间.sleep(1)定义更新(自我)'''self.countdown_has_run = False如果 len(self.mobs) == 0:self.timer_flag = True如果不是 self.countdown_has_run:self.countdown_has_run = Trueself.x.start()'''

现在,当 timer_flag 为 True 时,我也会绘制我的计时器,但它不会递减,所以我认为问题出在调用/启动线程倒计时函数的某个地方?

另外,这是我第一次在这里发帖,所以请让我知道如何更好地格式化等以便您能够提供帮助

解决方案

不要理会线程.无需让您的生活变得复杂.

通常,您使用

So, I'm totally new to programming (been doing it for a couple of months) and decided to try coding a game. On that note, a big thanks to Chris Bradfield for his series of tutorials in pygame coding, they are absolutely great! However, now that I'm done with the tutorials and need to work on my own, I've come across a problem. I'm making a top-down shooter and making it wave-based. So, when zombies in one wave die, I want to show a timer that counts down until the next wave begins. I THINK I'm down the right path atm, let me show you what I'm working with.

def new(self)
'''
    self.timer_flag = False
    self.x = threading.Thread(target=self.countdown, args=(TIME_BETWEEN_WAVES,))
'''

def countdown(self, time_between_waves):
    self.wave_timer = time_between_waves
    for i in range(TIME_BETWEEN_WAVES):
        while self.timer_flag:
            self.wave_timer -= 
            time.sleep(1)

def update(self)
'''
    self.countdown_has_run = False
    if len(self.mobs) == 0:
        self.timer_flag = True
        if not self.countdown_has_run:
            self.countdown_has_run = True
            self.x.start()
'''

Now, I also draw my timer when the timer_flag is True, but it doesn't decrement, so I assume the problem lies somewhere in calling/starting the threaded countdown function?

Also, it's my first time posting here, so please let me know what to do to format better etc for you to be able to help

解决方案

Don't bother with threads. No need to make your live complicated.

Usually, you use a Clock anyway in your game (if not, you should start using it) to limit the framerate, and to ensure that your world moves at a constant rante (if not, you should start doing it).

So if you want to trigger something in, say, 5 seconds, just create a variable that holds the value 5000, and substract the time it took to process your last frame (which is returned by Clock.tick):

clock = pygame.time.Clock()
dt = 0
timer = 5000
while True:
    ...
    timer -= dt
    if timer <= 0:
       do_something()
    dt = clock.tick(60)

I hacked together a simple example below. There, I use a simple class that is also a Sprite to draw the remaining time to the screen. When the timer runs out, it calls a function that creates a new wave of zombies.

In the main loop, I check if there's no timer running and no zombies, and if that's the case, a new timer is created.

Here's the code:

import pygame
import pygame.freetype
import random

# a dict that defines the controls
# w moves up, s moves down etc
CONTROLS = {
    pygame.K_w: ( 0, -1),
    pygame.K_s: ( 0,  1),
    pygame.K_a: (-1,  0),
    pygame.K_d: ( 1,  0)
}

# a function that handles the behaviour a sprite that
# should be controled with the keys defined in CONTROLS
def keyboard_controlled_b(player, events, dt):

    # let's see which keys are pressed, and create a 
    # movement vector from all pressed keys.
    move = pygame.Vector2()
    pressed = pygame.key.get_pressed()

    for vec in (CONTROLS[k] for k in CONTROLS if pressed[k]):
        move += vec

    if move.length():
        move.normalize_ip()

    move *= (player.speed * dt/10)

    # apply the movement vector to the position of the player sprite
    player.pos += move
    player.rect.center = player.pos

# a function that let's a sprite follow another one
# and kill it if they touch each other
def zombie_runs_to_target_b(target):
    def zombie_b(zombie, events, dt):

        if target.rect.colliderect(zombie.rect):
            zombie.kill()
            return

        move = target.pos - zombie.pos

        if move.length():
            move.normalize_ip()

        move *= (zombie.speed * dt/10)
        zombie.pos += move
        zombie.rect.center = zombie.pos

    return zombie_b

# a simple generic sprite class that displays a simple, colored rect
# and invokes the given behaviour
class Actor(pygame.sprite.Sprite):

    def __init__(self, color, pos, size, behavior, speed, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface(size)
        self.image.fill(color)
        self.rect = self.image.get_rect(center=pos)
        self.pos = pygame.Vector2(pos)
        self.behavior = behavior
        self.speed = speed

    def update(self, events, dt):
        self.behavior(self, events, dt)

# a sprite class that displays a timer
# when the timer runs out, a function is invoked
# and this sprite is killed
class WaveCounter(pygame.sprite.Sprite):

    font = None

    def __init__(self, time_until, action, *grps):
        super().__init__(grps)
        self.image = pygame.Surface((300, 50))
        self.image.fill((3,2,1))
        self.image.set_colorkey((3, 2, 1))
        self.rect = self.image.get_rect(topleft=(10, 10))

        if not WaveCounter.font:
            WaveCounter.font = pygame.freetype.SysFont(None, 32)

        WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {time_until}', (255, 255, 255))
        self.timer = time_until * 1000
        self.action = action

    def update(self, events, dt):
        self.timer -= dt

        self.image.fill((3,2,1))
        WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {int(self.timer / 1000) + 1}', (255, 255, 255))

        if self.timer <= 0:
            self.action()
            self.kill()

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 480))
    screen_rect = screen.get_rect()
    clock = pygame.time.Clock()
    dt = 0
    sprites_grp = pygame.sprite.Group()
    zombies_grp = pygame.sprite.Group()
    wave_tm_grp = pygame.sprite.GroupSingle()

    # the player is controlled with the keyboard
    player = Actor(pygame.Color('dodgerblue'), 
                   screen_rect.center, 
                   (32, 32), 
                   keyboard_controlled_b, 
                   5, 
                   sprites_grp)

    # this function should be invoked once the timer runs out
    def create_new_wave_func():
        # let's create a bunch of zombies that follow the player
        for _ in range(15):
            x = random.randint(0, screen_rect.width)
            y = random.randint(-100, 0)
            Actor((random.randint(180, 255), 0, 0), 
                  (x, y), 
                  (26, 26), 
                  zombie_runs_to_target_b(player), 
                  random.randint(2, 4), 
                  sprites_grp, zombies_grp)

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return

        # no timer, no zombies => create new timer
        if len(wave_tm_grp) == 0 and len(zombies_grp) == 0:
            WaveCounter(5, create_new_wave_func, sprites_grp, wave_tm_grp)

        sprites_grp.update(events, dt)

        screen.fill((80, 80, 80))
        sprites_grp.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

这篇关于如何在 pygame 中制作波浪计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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