【问题标题】:How do I fix my collision code in pygame?如何在 pygame 中修复我的碰撞代码?
【发布时间】:2018-03-26 00:11:38
【问题描述】:

这是我的直接问题:如何使用我的代码在 pygame 中进行碰撞?

过去几天我一直在尝试在我的游戏中添加碰撞,但无济于事。即使遵循类似线程上提供的其他答案,我所做的每一次尝试都没有按预期工作。在我当前的实现中,玩家只是简单地从矩形反弹到另一边。我可以看到检测到碰撞,但结果与预期不符。我只是希望我的球员不要跑过平台并站在上面,否则如果他们撞到他的头,他就会摔倒。下面是我当前的碰撞检测工作的代码。

import pygame as pg
from settings import Music_Mixer, loadCustomFont, States, screen, GROUND_HEIGHT
from time import sleep

"""This section contains entity states which are separate from game and menu states."""
class Player(pg.sprite.Sprite):
    def __init__(self, x, y):
        pg.sprite.Sprite.__init__(self)
        self.health = 100
        self.speed = 1
        self.screen = screen

        self.pos_x = x
        self.pos_y = y

        self.running = False
        self.is_jumping = False

        self.velocity = 15
        self.mass = 3

        #List of pictures for animations.
        stick_still = pg.image.load('Images/Animations/PlayerRun/Stickman_stand_still.png').convert_alpha()
        stick_still_2 = pg.image.load('Images/Animations/PlayerRun/Stickman_stand_still_2.png').convert_alpha()

        #Right running pictures.
        stick_run_1_right = pg.image.load('Images/Animations/PlayerRun/Stickman_run_1.png').convert_alpha()
        stick_run_2_right = pg.image.load('Images/Animations/PlayerRun/Stickman_run_2.png').convert_alpha()
        stick_run_3_right = pg.image.load('Images/Animations/PlayerRun/Stickman_run_3.png').convert_alpha()
        stick_run_4_right = pg.image.load('Images/Animations/PlayerRun/Stickman_run_4.png').convert_alpha()
        stick_run_5_right = pg.image.load('Images/Animations/PlayerRun/Stickman_run_4.png').convert_alpha()

        #Left running pictures.
        stick_run_1_left = pg.image.load('Images/Animations/PlayerRun/Stickman_run_1_left.png').convert_alpha()
        stick_run_2_left = pg.image.load('Images/Animations/PlayerRun/Stickman_run_2_left.png').convert_alpha()
        stick_run_3_left = pg.image.load('Images/Animations/PlayerRun/Stickman_run_3_left.png').convert_alpha()
        stick_run_4_left = pg.image.load('Images/Animations/PlayerRun/Stickman_run_4_left.png').convert_alpha()
        stick_run_5_left = pg.image.load('Images/Animations/PlayerRun/Stickman_run_4_left.png').convert_alpha()

        #Lists for animation movement.
        self.STICKMAN_IDLE = [stick_still]
        self.STICKMAN_RUN_RIGHT = [stick_run_1_right, stick_run_2_right, stick_run_5_right, stick_run_3_right, stick_run_4_right]
        self.STICKMAN_RUN_LEFT = [stick_run_1_left, stick_run_2_left, stick_run_5_left, stick_run_3_left, stick_run_4_left]


        self.images = self.STICKMAN_IDLE
        self.image = self.images[0]

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

        self.anim_index = 0
        self.anim_timer = 0
        self.ms = 0

    #Moves the player and begins the animation phase.
    def move_player(self, speed, dt):
        self.pressed = pg.key.get_pressed()

        if self.pressed[pg.K_a]:
            self.running = True
            if self.running:
                    self.pos_x -= 5  # Move left.
                    self.ms = 0.07
                    self.images = self.STICKMAN_RUN_LEFT  # Change the animation.
        if self.pressed[pg.K_d]:
            self.running = True
            if self.running:
                    self.pos_x += 5  # Move right.
                    self.ms = 0.07
                    self.images = self.STICKMAN_RUN_RIGHT  # Change the animation.
        if not self.pressed[pg.K_d] and not self.pressed[pg.K_a]:
            self.images = self.STICKMAN_IDLE  # Change the animation.
            self.ms = 0.07
        if self.pressed[pg.K_w]:
            self.is_jumping = True

        # Update the rect because it's used to blit the image.
        self.rect.center = self.pos_x, self.pos_y

    #Makes the player jump.
    def jumping(self, dt):
        if self.is_jumping:
            #Calculate force. 
            F = (0.5 * self.mass * (self.velocity))

            #Change position.
            self.pos_y = self.pos_y - F

            #Change velocity.
            self.velocity = self.velocity - 1

            if self.pos_y == GROUND_HEIGHT:
                self.pos_y = GROUND_HEIGHT
                self.is_jumping = False
                self.velocity = 15

    #Checks for collision.
    def is_collided_with(self, l):
        for wall in l:
            if self.rect.colliderect(wall.rect):
                if self.rect.right > wall.rect.left:
                    self.rect.right = wall.rect.left

                if self.rect.left < wall.rect.right:
                    self.rect.left = wall.rect.right

                if self.rect.bottom < wall.rect.top:
                    self.rect.bottom = wall.rect.top

                if self.rect.top > wall.rect.bottom:
                    self.rect.top = wall.rect.bottom

    #Animates the running movement of the player.
    def runAnim(self, dt):
        # Add the delta time to the anim_timer and increment the
        # index after 70 ms.
        self.anim_timer += dt

        if self.anim_timer > self.ms:
            self.anim_timer = 0  # Reset the timer.
            self.anim_index += 1  # Increment the index.
            self.anim_index %= len(self.images)  # Modulo to cycle the index.
            self.image = self.images[self.anim_index]  # And switch the image.

    #draws the player to the screen.
    def draw_entity(self):
        screen.blit(self.image, self.rect)

#Creates platforms that the user can jump onto.
class Platform(pg.sprite.Sprite):
    def __init__(self, x, y):
        pg.sprite.Sprite.__init__(self)
        self.pos_x = x
        self.pos_y = y

        self.moving = False

        self.image = None
        self.rect = pg.Rect(x, y, 150, 20)

    #draws the platform to the screen.
    def draw_plat(self):
        pg.draw.rect(screen, (0,0,0), self.rect)

【问题讨论】:

    标签: python-3.x pygame collision-detection


    【解决方案1】:

    您的问题在于您试图找出与物体的哪一侧发生碰撞。问题是您当前的支票不是相互排斥的。如果您正在(从任何一侧)穿透一个对象,您通常会触发此函数中的所有检查:

    def is_collided_with(self, l):
        for wall in l:
            if self.rect.colliderect(wall.rect):
                if self.rect.right > wall.rect.left:
                    self.rect.right = wall.rect.left
    
                if self.rect.left < wall.rect.right:
                    self.rect.left = wall.rect.right
    
                if self.rect.bottom < wall.rect.top:
                    self.rect.bottom = wall.rect.top
    
                if self.rect.top > wall.rect.bottom:
                    self.rect.top = wall.rect.bottom
    

    最终的结果是,你总是在你接触的任何墙壁的下方和左侧。

    您需要以其他方式检查碰撞的方向。一种常见的方法是跟踪您正在移动的方向,并使用它来确定您与对象的哪一侧发生了碰撞(因为如果您正在与一个不移动的对象发生碰撞,那么您只能从你自己的运动)。不幸的是,你似乎没有为你的角色保持速度,所以这对你的游戏来说可能不是那么简单。但是请注意,如果您希望您的角色有一些“惯性”并且在开始和停止按键时需要一些时间来加速和减速,您可能需要添加一个速度属性,所以也许您可以添加它现在(还没有添加加速的东西),只需将它用于碰撞响应逻辑。

    无论如何,这里有一些代码你可以适应任何你想用来告诉你移动方向的方法(我只是输入函数调用来抽象出测试,你可能可以编写一个内联测试,例如@987654322 @ 或其他):

    def is_collided_with(self, l):
        for wall in l:
            if self.rect.colliderect(wall.rect):
                if self.is_moving_right():      # replace this with a velocity check or something
                    self.rect.right = wall.rect.left
                elif self.is_moving_left():     # and here
                    self.rect.left = wall.rect.right
    
                if self.is_moving_down:         # and here
                    self.rect.bottom = wall.rect.top
                elif self.is_moving_up():       # and here too
                    self.rect.top = wall.rect.bottom
    

    当您沿对角线移动时发生碰撞时,此代码可能仍不能完全满足您的要求,但对于沿单轴发生的碰撞,它应该可以完美运行。您可能希望将运动分成两部分,一个是水平的,一个是垂直的,并在它们之间进行额外的碰撞测试,以避免需要解决对角线碰撞。

    对角线碰撞非常复杂,因为您无法判断您是否只是在对角线移动时与另一个物体面对面碰撞,或者您是否真的从一个角落到另一个角落。您可能需要进行一些涉及您的相对位置和速度的更复杂的计算,以查看最初发生碰撞的确切位置(因此您可以决定如何解决碰撞)。

    碰撞响应可能有很多微妙之处,不同风格的游戏有不同的常规解决方案。如果您的游戏是平台游戏,您应该为该游戏风格寻找特定的解决方案,因为其他游戏风格的更通用解决方案可能不足以满足您的需求。例如,在平台游戏中,知道您的角色是否站在地面上而不是跌倒或跳跃通常很重要,这在您处理垂直碰撞时需要一些额外的步骤。

    【讨论】:

    • 太棒了!!!谢谢您的答复。我回家后会测试一下。关于速度,我唯一的速度变量是 pos_x 和 pos_y ,它们沿着轴移动玩家。我还使用速度作为变量来衡量我的球员跳跃的力量。
    • 即使为 x 和 y 轴添加了速度变量,我仍然遇到问题。玩家撞到墙并相撞,但 5 秒后他只是跑过墙。
    【解决方案2】:

    在我看来,最好的碰撞方式是不使用坐标。 Pygame 会自动检查两个精灵是否碰撞。我不确定您到底想对碰撞做什么,但是此链接将引导您完成操作,并提供有关如何解决您的确切问题的视频示例。链接如下: http://programarcadegames.com/index.php?chapter=introduction_to_sprites&lang=en#section_13

    【讨论】:

      【解决方案3】:

      请参阅https://pygame.org/docs/ref/sprite.html#pygame.sprite.collide_rect。它将帮助您更好地理解它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多