Система столкновений в моем Pygame Platformer практически идеальна - PullRequest
0 голосов
/ 25 сентября 2018

Я пытаюсь найти способ совершить идеальное столкновение в моей платформерской игре для школы.Большинство из них работает, но есть небольшая проблема.Когда я стою на платформе выше уровня земли и двигаюсь влево или вправо от нее, игрок продолжает плавать в воздухе на той же высоте платформы, с которой я поднялся.Это можно исправить, прыгнув, и столкновение возвращается к нормальному.Я использую систему состояний, чтобы отслеживать, стоит ли игрок или нет, имея папку возможных состояний игрока и переключаясь между ними.По умолчанию это значение «Падение», потому что игрок запускается в воздухе, когда начинается игра.Код для игры разделен на три отдельных файла ниже (main.py, obj.py и settings.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

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

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()

1 Ответ

0 голосов
/ 25 сентября 2018

Просто добавьте 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...