Player-Objekt bewegt sich ein paar Pixel hoch und runter und ich verstehe nicht warum :(

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Benutzeravatar
weitnow
User
Beiträge: 17
Registriert: Dienstag 8. September 2015, 15:36

Hallo zusammen, ich hoffe jemand kann mir eine Erklärung für folgendes Phänomen geben. Ich folge einem Tutorial im Internet und bin bei Part 3 angelangt (hier der Link zum Tutorial: https://www.youtube.com/watch?v=pN9pBx5ln40.

Das Problem ist, dass mein Player-Objekt nach Kollision mit dem Platform-Objekt jeweils ein paar Pixel auf und runter wackelt. Ich habe einen Verdacht warum, verstehe es aber ehrlich gesagt dennoch nicht. Im Sourcecode (siehe weiter unten) wird in der main.py die Methode run ausgeführt. Dadurch wird meiner Meinung nach zuerst der Player im Spiel (siehe Methode update in der Player-Klasse in der Datei sprites.py) mit self.acc = vec(0, 0.5) in der Y-Achse nach unten verschoben (Schwerkraft). Dann wird in der Methode update in der Game-Klasse in der Datei main.py geprüft, ob der Player mit einer Platform kollidiert. Falls ja, dann wird die Position der Y-Achse des Players = Höhe der Platform gesetzt und die Player Y-Velocity auf 0. Dennoch springt mein Player jeweils ein paar Pixel auf und ab auf der Platform. Es macht denn anschein, als würde zuerst die Schwerkraft (0.5) ausgeführt, der Player taucht in die Platform ein Stück weit ein und wird dann wieder auf die Höhe der Platform gesetzt. Aber ich verstehe nicht warum, weil der draw-Befehl von Python erfolgt doch erst, nachdem der Player durch die Methode update in der Game-Klasse auf Pos Y = Höhe der Platform gesetzt wurde. Kann mir jemand helfen?

main.py

Code: Alles auswählen

# Jumpy! - platform game

import pygame as pg
import random
from settings import *
from sprites import *

class Game:
    def __init__(self):
        # initialize game windows, etc
        pg.init()
        pg.mixer.init()
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        self.running = True

    def new(self):
        # start a new game
        self.all_sprites = pg.sprite.Group()
        self.platforms = pg.sprite.Group()
        self.player = Player()
        self.all_sprites.add(self.player)
        p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
        self.all_sprites.add(p1)
        self.platforms.add(p1)
        p2 = Platform(WIDTH / 2 - 50, HEIGHT * 3/4, 100, 20)
        self.all_sprites.add(p2)
        self.platforms.add(p2)
        self.run()

    def run(self):
        # Game Loop
        # keep loop runing at the right speed
        self.playing = True
        while self.playing:
            self.clock.tick(FPS)
            self.events()
            self.update()
            self.draw()


    def update(self):
        # Game Loop - Update
        self.all_sprites.update()
        # Collision check
        hits = pg.sprite.spritecollide(self.player, self.platforms, False)
        if hits:
            self.player.pos.y = hits[0].rect.top
            self.player.vel.y = 0
            


    def events(self):
        # Game Loop - events
        for event in pg.event.get():
            # check for clsoing windows
            if event.type == pg.QUIT:
                if self.playing:
                    self.playing = False
                self.running = False

    def draw(self):
        # Game Loop - draw
        #Draw / render
        self.screen.fill(BLACK)
        self.all_sprites.draw(self.screen)
        # *after* drawing everything, flip the display
        pg.display.flip()

    def show_start_screen(self):
        # game splash/start screen
        pass

    def show_go_screen(self):
        # game over/continue
        pass

g = Game()
g.show_start_screen()
while g.running:
    g.new()
    g.show_go_screen()

pg.quit()
sprites.py

Code: Alles auswählen

# Sprite classes for platform game
import pygame as pg
from settings import *
vec = pg.math.Vector2

class Player(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.Surface((30, 40))
        self.image.fill(YELLOW)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2, HEIGHT / 2)
        self.pos = vec(WIDTH / 2, HEIGHT / 2)
        self.vel = vec(0, 0)
        self.acc = vec(0, 0)


    def update(self):
        self.acc = vec(0, 0.5)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.acc.x = -PLAYER_ACC
        if keys[pg.K_RIGHT]:
            self.acc.x = PLAYER_ACC

        # apply friction
        self.acc.x += self.vel.x * PLAYER_FRICTION
        # equations of motion
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc
        # wrap around the sides of the screen
        if self.pos.x > WIDTH:
            self.pos.x = 0
        if self.pos.x < 0:
            self.pos.x = WIDTH

        self.rect.midbottom = self.pos

class Platform(pg.sprite.Sprite):
    def __init__(self, x, y, w, h):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.Surface((w, h))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
Settings.py

Code: Alles auswählen

# game options/settings
TITLE = "Jumpy!"
WIDTH = 480
HEIGHT = 600
FPS = 60

# Player properties
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12


# define colors
WHITE = (255,255,255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
Zuletzt geändert von Anonymous am Mittwoch 17. August 2016, 09:20, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Benutzeravatar
weitnow
User
Beiträge: 17
Registriert: Dienstag 8. September 2015, 15:36

PS: Ich habe noch herausgefunden, dass wenn ich in der Methode update der Klasse Game in der der Datei main.py den Code:

Code: Alles auswählen

if hits:
	self.player.py.y = hits[0].rect.top
durch

Code: Alles auswählen

if hits:
	self.player.py.y = hits[0].rect.top + 1
ersetze, dann alles ok ist. Aber ich verstehe nicht warum.
BlackJack

@weitnow: Wenn die oberste Pixelzeile der Plattform *gleich* der untersten Pixelzeile des Spielers ist, dann kollidieren die *offensichtlich* immer noch. Du willst doch den Spieler *auf* die Plattform setzen und nicht eine Pixelzeile *in* die Plattform.

Edit: Ich denke wenn man `pos` weglässt und das `rect` vom Spieler nimmt (und `hits` in `platforms` umbenennt), wäre es verständlicher: ``self.player.rect.bottom = platforms[0].rect.top + 1``
Benutzeravatar
weitnow
User
Beiträge: 17
Registriert: Dienstag 8. September 2015, 15:36

Lieber Blackjack

Wow, wie immer bist du rasend schnell mit einer Antwort. Danke vielmals.

Betreffend meinem Problem...ich bin mir nicht sicher, ob ich dich richtig verstehe...

In Pygame beginnt die Y-Ache ja oben am Bildschirm mit 0 und erhöht sich gegen unten.

Wenn die Platform also zum Beispiel auf der Y-Ache auf Höhe 450 ist under der Player auf Y-Ache Höhe 300, fällt der
Player nach unten. Wenn er dann auf Höhe 450 mit der Platform kollidiert, dann wird seine Höhe auf die gleiche Höhe wie die Platform gesetzt.
Wenn ich den Player nicht in die Platform, sondern auf die Platform setzten möchte, dann müsste ich im Code schreiben:

self.player.rect.bottom = platforms[0].rect.top - 1 (MINUS, nicht PLUS).

Das Problem ist aber, dass sich mein Player nach Kollision mit der Platform hin und her bewegt (ein paar wenige Pixel und ganz schnell) und ich weiss nicht warum dass, das passiert. Wenn ich self.player.rect.bottom = platform[0].rect.top + 1 (PLUS) schreibe, dann setzte ich den Player 1 Pixel in die Platform. Wenn ich das mache, dann habe ich den unschönen Effekt des zitternden, sich ein par Pixel hin und her bewegenden Player nicht). Aber ich verstehe nicht warum, dass das so ist.
BlackJack

@weitnow: Ups. :oops:

Ich wollte es gerade mal selbst ausprobieren, aber das `pygame.math`-Modul gibt es offiziell noch gar nicht, und eine Entwicklerversion von Pygame wollte ich mir jetzt nicht installieren.
Benutzeravatar
weitnow
User
Beiträge: 17
Registriert: Dienstag 8. September 2015, 15:36

Hey Blackjack

Dennoch danke für deine Bemühungen...du hast mir schon ein paar mal sehr hilfreiche Antworten gegeben....wollte nur sagen, dass das sehr geschätzt wird.

Betreffend meinem Problem....ich habe jetzt noch gesehen, dass derjenige, welcher dieses Tutorial geschrieben hat, einen Kommentar erfasst hat, dass die komische Oszillation (also das sehr schnell auf und ab bewegen um ein paar Pixel) des Players etwas mit einer Rundungsdifferenz zu tun hat. Leider ist er nicht näher darauf eingegangen. Ich lass jetzt einfach einmal meinen Code wie erst ist und mach mit dem Tutorial mal weiter...ev. kommt die Lösung ja noch :D

Liebe Grüsse
Antworten