[Python] collision detection en verplaatsingssnelheid

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Anoniem: 82654

Topicstarter
Ik probeer voor het eerst een spel te maken in python / pyglet, maar heb een probleem met de collision detection.

De code werkt wel, maar enkel als ik de walkspeed op 1 pixel per gameloop zet.
Als ik de walkspeed op bvb 5 pixels / gameloop zet, dan gaat de collision functie het volgende doen:
voorbeeldsituatie:
code:
1
2
3
muur.x2 = 40
player.x1 = 44
player.x2 = 84

De player rectangle bevindt zich dus 4 pixels rechts van de muur.
Nu ga ik als player naar links met 5px/gameloop
Dan gaat de collision detectie het volgende doen:
(player.x1 - 5px) < muur.x2 => dus collisie gededecteerd, waardoor de speler niet tot precies 1 pixels tegen de muur kan. (omwillen van die walkspeed van 5 pixels)

in mijn game loop doe ik het volgende:

code:
1
2
3
4
5
6
7
def update(dt):
    player.handle_pos()
    print(player.posX)
    player.collides_with(tile)
    
    for obj in objects:
        obj.update(dt)

De player handlepos functie:
(Player heeft x en posX (posX = voor de berekeningen, x = om de image coordinaten up te daten)

code:
1
2
3
4
5
6
7
8
9
10
11
12
def handle_pos(self):
        if self.key_handler[key.LEFT]:
            self.posX -= 1
                
        if self.key_handler[key.RIGHT]:         
            self.posX += 1

        if self.key_handler[key.UP]:
            self.posY += 1
                
        if self.key_handler[key.DOWN]:
            self.posY -= 1

Nadat de collision functie uitgevoerd werd wordt de player.update opgeroepen
(self.moveLeft, self.moveRight, .. zijn booleans die ingesteld worden in de collision functie, daar wordt dus bepaald in welke richting je verder mag lopen)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def update(self, dt):
        if self.key_handler[key.LEFT]:
            if self.moveLeft:
                self.image = anim_left
                self.x = self.posX
            else:
                self.posX = self.x
                
        if self.key_handler[key.RIGHT]:         
            if self.moveRight:
                self.image = anim_right
                self.x = self.posX
            else:
                self.posX = self.x
                
        if self.key_handler[key.UP]:
            if self.moveUp:
                self.image = anim_up
                self.y = self.posY
            else:
                self.posY = self.y
                
        if self.key_handler[key.DOWN]:
            if (self.moveDown):
                self.image = anim_down
                self.y = self.posY
            else:
                self.posY = self.y

Acties:
  • 0 Henk 'm!

  • SoulWar1
  • Registratie: Augustus 2004
  • Laatst online: 13-07 23:54
Misschien niet de mooiste oplossing, maar kun je de gewenste positie van de player niet aanpassen / afronden in je collision detection functie? Dus als er een collision is dan player.posX = muur.x.

Know Thyself


Acties:
  • 0 Henk 'm!

Anoniem: 82654

Topicstarter
Dat kan ik wel doen, maar dan zit ik met een "snap to grid" achtig probleem, die erg zichtbaar zal worden bij een hogere snelheid

(dat de player opeens tegen de rand springt ipv er naar toe te gaan)

Acties:
  • 0 Henk 'm!

  • SoulWar1
  • Registratie: Augustus 2004
  • Laatst online: 13-07 23:54
Dat is met een verplaatsing van bijv 10 pixels per loop (1 frame dat gerenderd wordt) volgens mij niet te voorkomen. Wat je dan zou kunnen doen is werken met een snelheidswaarde van bijv 10 ipv met harde pixels te rekenen. Als je dan 60 frames (updates) per seconde hebt is de verplaatsing player.x + (snelheid / fps).

Know Thyself


Acties:
  • 0 Henk 'm!

  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Ik zou de snelheid niet meten in "pixels/frame". Dat levert ook vreemde dingen op als je een snellere computer hebt of het spel op een andere resolutie speelt. Ik zou de "physics" loskoppelen van de weergave op je scherm (rendering).

Druk snelheid bijvoorbeeld uit in m/s. Je kies een schaal voor je speelveld en character, ook in meters. Dan kan je op een veel natuurlijkere manier rekenen.

Bij je frameopbouw moet je volgens mij dus eerst de physics berekenen en daarna de rendering.
Physics:
Je moet eerst het tijdstip en locatie van character van je vorige frame weten. Bij je nieuwe frame bepaal je wat het huidige tijdstip is, en dan kan je met de snelheid en richting uitrekenen waar je in het nieuwe frame zou terechtkomen. En dan kijken of er een collision is. Dit kan allemaal in meters en meters/seconde (dit is je physics).
Rendering:
Pas daarna moet je een vertaling van real-life eenheden naar pixels (rendering) doen. Je moet dan dus weten hoeveel pixels je veld hoog en breed is (afhankelijk van window size of full screen resolutie), en je weet ook hoeveel logische "meters" je veld hoog en breed is. Dus je kunt eenvoudig meters naar pixels omrekenen, door te kijken naar hoeveel pixels/meter je mee van doen hebt.

Dan speelt het probleem helemaal niet. Of iemand exact tegen een muur kan lopen, hangt af van de framerate en de snelheid, soms zal het wel lukken en soms niet. Maar dat is op zich niet vreemd. De daadwerkelijke berekeningen worden niet zo gek veel ingewikkelder, maar de structuur van je programma wel duidelijker, en het gedrag logischer, denk ik.

Acties:
  • 0 Henk 'm!

Anoniem: 82654

Topicstarter
bedankt! ik zal dit eens proberen om te zetten in code

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je moet een lijn trekken van je oude positie naar je gewenste nieuwe positie, vervolgens de eerste intersectie/collision op die lijn vinden, en dan een resolve doen, i.e. in jouw geval waarschijnlijk de speler iets voor de muur zetten. Sowieso krijg je ander problemen met een muur van [1,2], je speler op 0, en die dan 5 stapjes naar rechts gaat, dwars door de muur.
Pagina: 1