微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

试图阻止玩家穿过瓷砖 Pygame

如何解决试图阻止玩家穿过瓷砖 Pygame

我一直在研究 Pygame 中的碰撞问题,问题是当玩家移动瓷砖顶部的土地时,它们会立即被转移到左侧或右侧。我将如何做到让玩家降落在平台顶部而不会向左或向右移动?在下面的代码中,////// 行之间似乎发生了碰撞问题。

import pygame

pygame.init()
pygame.mixer.init()

clock = pygame.time.Clock()
running = True

# game properties
WIDTH = 800
HEIGHT = 600
FPS = 60

# colors
BLACK = (0,0)
BLUE = (0,255,255)
GREEN = (0,0)

# physics
GraviTY = 0.3
ACCEL = 1
FRICTION = -0.12

window = pygame.display.set_mode((WIDTH,HEIGHT))

# Platform properties
SMALL = (100,50)
MEDIUM = (20000,200)
GROUND = (100000,100)

vec = pygame.math.Vector2

class Sonic(pygame.sprite.Sprite):
    
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50,50))
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2,HEIGHT - 51)
        self.pos = vec(WIDTH / 2,HEIGHT - 51)
        self.vel = vec(0,0)
        self.acc = vec(0,0)
        self.last_update = 0
        self.time_passed = 0
        

    def update(self):
        self.acc = vec(0,GraviTY)
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.acc.x = -ACCEL - 2
        if keys[pygame.K_RIGHT]:
            self.acc.x = ACCEL
        if keys[pygame.K_UP]:
            self.acc.y = -ACCEL
                    
       
       # friction check
        self.acc.x += self.vel.x * FRICTION
        if self.vel.x < -2:
            self.vel.x = -2

       # equations of motion
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc

        self.rect.midbottom = self.pos
            
class Ground(pygame.sprite.Sprite):

    def __init__(self,x,y,plat):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((GROUND))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        


class Platform(pygame.sprite.Sprite):

    def __init__(self,plat):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((plat))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x 
        self.rect.y = y

# player sprites
s = Sonic()

# floor sprites
ground = Ground(0,HEIGHT - 50,GROUND)
floor = pygame.sprite.Group()
floor.add(ground)


# platform sprites

platforms = [Platform(WIDTH - 200,HEIGHT - 100,SMALL)]

plats = pygame.sprite.Group()


for i in platforms:
    plats.add(i)
    

# all sprites
sprites = pygame.sprite.Group()
sprites.add(s)
sprites.add(plats)
sprites.add(ground)


while running:
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # update
    sprites.update()
    


    if s.vel.y > 0:
        collisions = pygame.sprite.spritecollide(s,floor,False)

        if collisions:
            for collision in collisions:
                if s.pos.y > collision.rect.top: 
                    s.pos.y = collision.rect.top
                    s.rect.bottom = s.pos.y
                    s.vel.y = 0 

    """
    where the collision issue seems to be happening (CODE BELOW)
    """
////////////////////////////////////////////////////////////////////////////////////////////////////////
    if s.vel.x > 0:
        hits = pygame.sprite.spritecollide(s,plats,False)
        if hits:
            for hit in hits:
                if s.pos.x > hit.rect.left:
                    s.pos.x = (hit.rect.left - (s.rect.width / 2) - 1) 
                    s.rect.right = s.pos.x
                    s.vel.x = 0
    if s.vel.x < 0:
        hits = pygame.sprite.spritecollide(s,False)
        if hits:
            for hit in hits:
                if s.pos.x < hit.rect.right:
                    s.pos.x = (hit.rect.right + (s.rect.width / 2) + 1)
                    s.rect.left = s.pos.x
                    s.vel.x = 0
    """
    when player lands on a tile they are blitted to either side of the tile (how do I fix this?)
    """
    
    if s.vel.y > 0:
        hits = pygame.sprite.spritecollide(s,False)
        if hits:
            for hit in hits:
                if s.pos.y > hit.rect.top:
                    s.pos.x = (hit.rect.top - (s.rect.width / 2) + 1)
                    s.rect.bottom = s.pos.y
                    s.vel.x = 0

    
////////////////////////////////////////////////////////////////////////////////////////////////////////


    # draw
    window.fill(BLACK)

    sprites.draw(window)
    
    

    # double buffering 
    pygame.display.flip()

解决方法

结合起来可以解决您的问题的几件事: 首先,在您标记为可能存在问题的区域内,

    if s.vel.y > 0:
        hits = pygame.sprite.spritecollide(s,plats,False)
        if hits:
            for hit in hits:
                if s.pos.y > hit.rect.top:
                    s.pos.x = (hit.rect.top - (s.rect.width / 2) + 1)
                    s.rect.bottom = s.pos.y
                    s.vel.x = 0

也应该切换:

    if s.vel.y > 0:
        hits = pygame.sprite.spritecollide(s,False)
        if hits:
            for hit in hits:
                if s.pos.y > hit.rect.top:
                    s.pos.y = (hit.rect.top - (s.rect.width / 2) + 1)
                    s.rect.bottom = s.pos.y 
                    s.vel.y = 0

此外,我不确定 pygame 是如何处理其坐标的,但对于重置 s.pos 值,我发现 s.pos.y = (hit.rect.top) + 1 效果更好。

第二,它把立方体射到一边的原因也是因为在玩家精灵落在立方体上之后,如果玩家精灵与立方体齐平,它也会与边重叠(并因此相交),这会触发 x 次命中。有很多方法可以解决这个问题,但是所有方法(至少我知道的方法)都有自己的陷阱需要注意,但至少现在你知道为什么会这样了。

祝你好运,重力很糟糕。

根据评论编辑: 我想优先考虑这一点,因为我在这个领域的工作充其量是最少的,您应该查找官方资源以获得最佳帮助。话虽如此,当我自己遇到这个问题时,我将系统从检查所有交叉点(顶部、侧面和底部)切换为一次只检查一个,通过 else if,因为如果玩家与顶部相交,那么他们应该'不与同一块的边相交。这在一定程度上会起作用,但是如果玩家跳入方块的一侧会产生一个错误,因为此时玩家将同时与侧面和顶部相交,使用 else-if 结构会导致玩家传送到顶部,这不是您想要的。

为了解决这个问题,你可以在 if-else 中进行第二次检查,确定是否应该根据玩家的 y 坐标传送玩家,这应该有助于改进它。问题是这会导致一只兔子修复漏洞,管理起来很痛苦(根据经验)。但是......它确实有效。

同样,我建议您查找有关该主题的教程以获得更合适的游戏设计。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。