Prosta fizyka przeciągania, inne działanie podczas ruchu w lewo lub w prawo [duplikat]

Nov 24 2020

Mój kod działa inaczej dla prędkości ujemnych niż dodatnich

Próbuję zaimplementować fizykę platformówki, gracz ma prędkość w kierunku X, prędkość jest zwiększana lub zmniejszana, gdy użytkownik naciśnie odpowiednio „A” lub „D”, lub ustawiana na 0, gdy gracz zderzy się ze ścianą.

Aby zasymulować tarcie o podłoże, prędkość X gracza jest mnożona przez „self.drag” (pływak mniejszy niż 1)

Spodziewałem się, że ten kod zmniejszy prędkość X graczy, z czasem zmniejszając ją pomijalnie blisko 0, bez faktycznego odwracania prędkości (tak jak odejmowanie wartości), zatrzymałoby to niekontrolowane przesuwanie się gracza, gdy użytkownik nie narzuca poleceń ruchu .

Działa to zgodnie z przeznaczeniem podczas ruchu w prawo, jednak podczas ruchu w lewo zachowuje się inaczej, podczas ruchu w lewo gracz wydaje się przez chwilę unosić w powietrzu, zanim się zatrzyma.

Oto kod, który pobiera dane wejściowe gracza, wewnątrz klasy odtwarzacza, uruchamia każdą klatkę:

dx = 0
if pygame.key.get_pressed()[pygame.K_a]:
        dx -= self.speed
if pygame.key.get_pressed()[pygame.K_d]:
        dx += self.speed

# to slow down horizontal movement
self.vx *= self.drag

# Add change in velocity to total velocity
self.vx += dx
self.vy += dy

Może koncepcja działa i źle ją zaimplementowałem? Istnieje kod kolizji, który może wpływać na prędkości w sposób, którego nie zauważyłem? Czy ten system działa inaczej dla prędkości dodatnich i ujemnych?

Dzięki! Każda pomoc jest bardzo ceniona

Odpowiedzi

1 Rabbid76 Nov 24 2020 at 04:59

Problem jest spowodowany tym, że pygame.Rectprzechowuje integralne współrzędne:

Wszystkie współrzędne obiektów Rect to liczby całkowite. […]

Składnik ułamkowy dxi dyjest tracony, gdy:

self.Rect.x += dx
self.Rect.y += dy

Musisz wykonywać obliczenia z dokładnością zmiennoprzecinkową. Dodaj atrybut xi ydo klasy. Zwiększ atrybuty movei zsynchronizuj Rectatrybut:

class Player:
    def __init__(self, color):
        self.Rect = pygame.Rect([50, 50], [30, 50])
        self.x = self.Rect.x
        self.y = slef.Rect.y
        # [...]

    def move(self, dx, dy, platforms):
        # Test for collisions with platforms

        # handle movement on the X axis
        self.x += dx
        self.Rect.x = round(self.x)
        for platform in platforms:
            if self.Rect.colliderect(platform.Rect):
                if dx > 0:
                    self.Rect.right = platform.Rect.left
                if dx < 0:
                    self.Rect.left = platform.Rect.right
                self.x = self.Rect.x
                # Reset velocity when collision with wall
                self.vx = 0

        # handle movement on the Y axis
        self.Rect.y += dy
        self.Rect.y = round(self.y)
        for platform in platforms:
            if self.Rect.colliderect(platform.Rect):
                if dy > 0:
                    self.Rect.bottom = platform.Rect.top
                if dy < 0:
                    self.Rect.top = platform.Rect.bottom
                self.y = self.Rect.y
                # Reset velocity when collision with floor or roof
                self.vy = 0

        # return correctly collided rect to draw()
        return self.Rect