【问题标题】:Delay between losing health失去健康之间的延迟
【发布时间】:2018-08-15 15:29:25
【问题描述】:

我最近在我的游戏中实施了一个健康系统(尽管是一个非常基本的系统),它的工作原理是,如果我的玩家与敌人发生碰撞,我就会失去健康。但是,我面临的问题是,只要我与敌人保持接触,我每秒就会失去 60 次生命值。

我真正想要的是:每次玩家与敌人碰撞时,它都会损失一大块生命值,但至少要等到一秒钟后才能再损失生命值。我试过使用 time.sleep ,但这似乎只是冻结了整个程序,而不仅仅是健康系统。这是我的代码;

主游戏

import pygame
from constants import *
from player import Player
from enemy import Enemy
import time


pygame.init()

screen = pygame.display.set_mode([500, 500])

pygame.display.set_caption('Labyrinth')

# Spawn player

player = Player(50, 50)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)


# Spawn enemy

enemy = Enemy(150, 150)
enemy_sprites = pygame.sprite.Group()
enemy_sprites.add(enemy)



clock = pygame.time.Clock()

done = False


# ----- Event Loop

while not done:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.changespeed(-3, 0)
            elif event.key == pygame.K_RIGHT:
                player.changespeed(3, 0)
            elif event.key == pygame.K_UP:
                player.changespeed(0, -3)
            elif event.key == pygame.K_DOWN:
                player.changespeed(0, 3)

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.changespeed(3, 0)
            elif event.key == pygame.K_RIGHT:
                player.changespeed(-3, 0)
            elif event.key == pygame.K_UP:
                player.changespeed(0, 3)
            elif event.key == pygame.K_DOWN:
                player.changespeed(0, -3)


# ----- Game Logic

    all_sprites_list.update()
    enemy_sprites.update(player)

    player_hit_list = pygame.sprite.spritecollide(player, enemy_sprites, False)

    for hit in player_hit_list:
       player.health -= 10
       time.sleep(1)
       if player.health <= 0:
           done = True



    screen.fill(WHITE)

    all_sprites_list.draw(screen)
    enemy_sprites.draw(screen)

    pygame.display.flip()

    clock.tick(60)

pygame.quit()

播放器类

from constants import *
import pygame

class Player(pygame.sprite.Sprite):


    def __init__(self, x, y):

        super().__init__()

        self.image = pygame.Surface([15, 15])
        self.image.fill(BLACK)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        self.health = 10


        self.change_x = 0
        self.change_y = 0

    def changespeed(self, x, y):
        self.change_x += x
        self.change_y += y

    def update(self):
        self.rect.x += self.change_x
        self.rect.y += self.change_y

敌人等级

from constants import *
import pygame

class Enemy(pygame.sprite.Sprite):


    def __init__(self, x, y):

        super().__init__()

        self.image = pygame.Surface([10, 10])
        self.image.fill(RED)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

(常量文件只定义了黑色、红色和白色)

任何帮助都将不胜感激!

【问题讨论】:

  • 这绝对是可行的(正如 Matthew Horst 的回答所示),但是您要解决的问题是每帧损失 10 hp 甚至 1 hp 是否太致命了?如果您只是使用浮点值来表示健康并且每帧损失 1/6 马力怎么办?无论如何,这绝对是一种不同的游戏体验,你可能有充分的理由想要这个;我只是想确保您知道这两种选择都很容易,因此您可以选择适合您游戏的任何一种,而不是您知道如何实施的任何一种。
  • 在我刚刚给出的示例中,我只是使用了一些占位符值。在我的最终产品中,我的目标是有一个健康栏,每次命中都会带走一半的心,并且你有 x 数量的心,就像在其他游戏中看到的一样,例如以撒的绑定等。我可以想象这是一个非常困难的游戏,如果玩家死得跟示例中一样快!
  • 当然可以,但你可以每 1/60 秒夺走 1/120 的心脏。您可以将其“四舍五入”到最近的半心进行展示。难度不会比每1秒夺走1/2颗心脏更糟糕。同样,两种设计都是合理的;您可以找到兼具这两种方式的街机(和复古)游戏,因此,如果您出于游戏设计的原因而不是看起来最容易实现的设计来选择您的设计,那就太好了。

标签: python pygame


【解决方案1】:

我不是游戏开发者,所以我不知道常见的模式或任何东西,但我有一些想法:

  1. 如果你设置一个invincible_until 时间在玩家身上,当他们第一次失去生命值时。您将其设置为超过now() 1 秒。然后你可以像你一样继续命中检查,但只有在新的now() 超出玩家的invincible_until 时才会实际减去更多的生命值。当然,当这种情况发生时,将invincible_until 再次重置为未来 1 秒。
  2. 如果您保存“命中时间”(即“命中”第一次发生的时间)会怎样。然后,虽然该命中仍然是真实的,但只有在“命中时间”超过 1 秒时才应用另一个生命值损失。当然,与此同时,重置“命中时间”。

正如@abarnert 指出的那样,我的代码并不是真正的“游戏”-y,我完全理解使用框架的这一点。但我将以我更熟悉使用日期时间和从面向对象的角度思考的方式编写示例。如果你愿意的话,你可以确定它是基于框架的。如果你想那样做,我想你会使用像 pygame 的 get_time() 这样使用毫秒的东西,再加一秒就是+ 1000

当然,您可能希望将“1 秒”之类的值放入常量中。

我只是在这里在线编写代码,我没有运行它,但我认为我的语法和逻辑是正确的。如果不是,请随时编辑,我认为这应该让您明白我的意思。

例如,#1 可能是这样的:

from datetime import datetime, timedelta

class Player(pygame.sprite.Sprite):

    def __init__(self, x, y):

        super().__init__()
        self.invincible_until = datetime.now()
        ...

    def _can_take_damage(self):
        if datetime.now() < self.invincible_until:
            return False

        return True

    def hit_check(self, damage):
        """Player is hit with potential damage of `damage`"""
        if self._can_take_damage():
            self.health -= damage
            self.invincible_until = datetime.now() + timedelta(seconds=1)

    def is_dead(self):
        return self.health <= 0

    def update(self):
        self.rect.x += self.change_x
        self.rect.y += self.change_y

然后在游戏逻辑中:

for hit in player_hit_list:
       player.hit_check(10)
       if player.is_dead():
           done = True

【讨论】:

  • 很好的解决方案。在老式街机游戏中,您可能会通过帧数而不是时间来执行此操作,而基于帧循环的 PyGame 游戏与老式游戏的设计相同。但是,另一方面,3GHz Core 处理器上的 Python 比 1MHz Z80 上的汇编拥有更多的资源,所以如果使用 datetime 对象更容易理解,为什么不呢?
  • 在纸面上这确实很有意义,但和你一样,我不是游戏开发者,随着我在游戏中添加更多元素,我一直在慢慢地学习 python 的碎片。你的答案可以更详细一点吗?我不熟悉使用计时,因此不知道如何将invincible_until 设置为比now() 晚1 秒,或者在发生这种情况后如何重置invincible_until
  • @Goose_ 用示例实现更新了帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
相关资源
最近更新 更多