简体   繁体   English

我的pygame平台游戏中的碰撞系统几乎是完美的

[英]Collision system in my pygame platformer is almost perfect

I'm trying to find a way to make perfect collision in my platformer game for school. 我正在尝试找到一种在学校的平台游戏中实现完美碰撞的方法。 Most of it works but there is a slight problem. 大部分都可以,但是有一个小问题。 When I stand on a platform above ground level and move left or right off of it, the player continues to float in midair at the same height of the platform that I got off of. 当我站在高于地面的平台上并向左或向右移动时,玩家会继续漂浮在半空中,与我所离开平台的高度相同。 This can be fixed by jumping and the collision reverts to normal. 可以通过跳跃解决此问题,并且碰撞恢复正常。 I am using a state system to track if the player is standing or not by having a folder of possible player states and switching between them. 我正在使用状态系统,通过拥有可能的玩家状态的文件夹并在它们之间进行切换来跟踪玩家是否站立。 This is set to "Falling" by default because the player starts in midair when the game runs. 默认情况下,此设置为“掉落”,因为当游戏运行时,玩家从空中开始。 The code for the game is divided into three separate files below (main.py, obj.py and settings.py). 游戏代码在下面分为三个独立的文件(main.py,obj.py和settings.py)。 Please tell me how I can fix this glitch. 请告诉我如何解决此故障。

Main.py Main.py

import pygame
import random
from settings import *
from obj import *

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

pygame.display.set_caption(TITLE)
screen = pygame.display.set_mode([WIDTH,HEIGHT])

clock = pygame.time.Clock()

me = Player()
all_sprites.add(me)

platforms = []

pf = Wall(20,40,500,480, 0)
pf2 = Wall(WIDTH,40, 400,500, 0)
platforms.append(pf)
platforms.append(pf2)

for i in platforms:
    wall_sprites.add(i)

running = True

while running:
    clock.tick(FPS)

    all_sprites.update()
    wall_sprites.update()

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

    screen.fill(GREY)
    all_sprites.draw(screen)
    wall_sprites.draw(screen)
    pygame.display.update()

pygame.quit()

obj.py obj.py

import pygame
import math
from settings import *

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((40,40))
        self.image.fill(BLACK)
        self.rect = self.image.get_rect()
        self.rect.x = WIDTH / 2
        self.rect.y = 70
        self.vx = 0
        self.vy = 0
        self.SW = False  # Can you screen wrap?
        self.player_states = ["Standing","Falling"]
        self.state = self.player_states[1]

    def update(self):
        self.vx = 0  # X speed set to 0 if no input is received
        if self.state == self.player_states[1]:
            self.vy += GRAVITY  # Gravity only added while falling
        else:
            self.vy = 0

        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.vx = -SPEED
        if keys[pygame.K_RIGHT]:
            self.vx = SPEED
        if keys[pygame.K_SPACE] and self.state == self.player_states[0]:
            self.vy -= JUMP_SPEED
            self.state = self.player_states[1]        

        self.rect.left += self.vx  # X and Y positions are updated
        self.collide(self.vx, 0, wall_sprites)  # Collision is checked. Second param is 0 b/c we aren't checking for vertical collision here
        self.rect.top += self.vy
        self.collide(0, self.vy, wall_sprites)


        if self.SW:
            if self.rect.left > WIDTH:
                self.rect.right = 0
            if self.rect.right < 0:
                self.rect.left = WIDTH

            if self.rect.top > HEIGHT:
                self.rect.bottom = 0
            if self.rect.bottom < 0:
                self.rect.top = HEIGHT

    def collide(self, xDif, yDif, platform_list):
        for i in platform_list:                      # Shuffle through list of platforms
            if pygame.sprite.collide_rect(self, i):  # If there is a collision between the player and a platform...
                if xDif > 0:                         # And our x (horizontal) speed is greater than 0...
                    self.rect.right = i.rect.left    # That means that we are moving right, 
                if xDif < 0:                         # So our right bounding box becomes equal to the left bounding box of all platforms and we don't collide    
                    self.rect.left = i.rect.right
                if yDif > 0:
                    self.rect.bottom = i.rect.top
                    self.state = self.player_states[0] 
                if yDif < 0:
                    self.rect.top = i.rect.bottom


class Wall(pygame.sprite.Sprite):  # Collision is added for platforms just in case that they are moving. If they move to you, they push you
    def __init__(self, width, height, xpos, ypos, speed):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((width,height))
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()
        self.rect.centerx = xpos
        self.rect.centery = ypos
        self.speed = speed

    def update(self):
        self.rect.left += self.speed
        self.collide(self.speed, all_sprites)  # Collision only for platforms moving left and right. Not up and down yet

    def collide(self, xDif, player_list): 
        for i in player_list:                      
            if pygame.sprite.collide_rect(self, i):

                if xDif > 0:                         # If the platform is moving right... (has positive speed)
                    i.rect.left += self.speed        # Platform pushes player
                    self.rect.right = i.rect.left    # Player sticks to the wall and is pushed

                if xDif < 0:
                    i.rect.right -= self.speed
                    self.rect.left = i.rect.right

settings.py settings.py

import pygame

FPS = 60
WIDTH = 800
HEIGHT = 600
TITLE = "Perfect collision"

GREY = (150,150,150)
BLACK = (0,0,0)
BLUE = (0,0,255)

SPEED = 5
JUMP_SPEED = 9
GRAVITY = 0.3

all_sprites = pygame.sprite.Group()
wall_sprites = pygame.sprite.Group()

Just add the GRAVITY to self.vy in every frame and set self.vy to 0 when the sprite touches the ground: 只需在每帧中将GRAVITY添加到self.vy中,并在精灵接触地面时将self.vy设置为0:

def update(self):
    self.vx = 0
    self.vy += GRAVITY

def collide(self, xDif, yDif, platform_list):
    for i in platform_list:
        if pygame.sprite.collide_rect(self, i):
            # Code omitted.

            if yDif > 0:
                self.rect.bottom = i.rect.top
                self.state = self.player_states[0]
                self.vy = 0  # Set vy to 0 if the sprite touches the ground.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM