Python rectangle collision handling with pygame

2019-06-28 07:50发布

问题:

I've been doing extensive research on this topic for the past few days and I can't seem to find an answer for my exact problem.

So, I have a simple game set up where I have the player at 0, 0 with a width of 10x10

    player= pygame.Rect(0, 0, 10, 10)

and aside from that, the player has a velocity of x: 0, y: 10, which will make him fall (y is positive because the origin of the screen is at the top left.)

and I have a tile at 0, 100, as shown:

    dirt= pygame.Rect(0, 100, 10, 10)

so, how can I handle collision, I already know I can detect it with Rect.colliderect(Rect).

I've tried a few ways, but encountered some problems:

I can't cut the player's velocity to 0 when he hits something and then move him back until he's just touching the object because that still causes the problem of walking, when he walks, I apply +10 velocity on x, but unfortunately, the game still processes that he is falling and colliding and moving sideways, so it just moves him back to where he started.

I'm a beginner, so a simple answer would be appreciated, and I would like to not have to use any third party modules other that pygame if I didn't have to.

Update:

Here is some of the rough test code I have tried:

    def sim(obj, time, world):
        time= time / 1000
        obj.physProp['vel']= (obj.physProp['vel'][0] + (accel[0] * time), obj.physProp['vel'][1] + (accel[1] * time))
        if obj.physProp['vel'][1] > terminalY:
            obj.physProp['vel']= (obj.physProp['vel'][0], terminalY)
        obj.pos= (obj.pos[0] + (obj.physProp['vel'][0] * time) + ((accel[0] / 2) * (time ** 2)), obj.pos[1] + (obj.physProp['vel'][1] * time) + ((accel[1] / 2) * (time ** 2)))

        for ID in world:
            if obj.getRect().colliderect(world[ID].getRect()) == True:
                pass

        return (obj.pos, obj.physProp['vel'])

回答1:

The Pygame API invites you to write all your game subjects in an Object oriented way - so that your falling character will have all the "methods" and "attributes" to properly respond to things on the scenario - like hitting something.

So, if your character is defined for something as simple as:

class Char(object):
    # these start as class attributes, 
    # but whenever they are assigned to with a "self.var = bla" in
    # a method, an instance attribute starts existing
    x, y = 0,0
    vx, vy = 0,0

    def update(self):
        self.x += self.vx
        self.y += self.vy

And your external code, upon detecting a collision, could do just this:

def mainloop():
   while True:
       ...
       obj.update()
       if obj.getRect().colliderect(world[ID].getRect()): # don't do "== True" in `if's - it is just silly
             # take character back to the precious position
             obj.x -= obj.vx
             obj.y -= obj.vy
             # zero out velocities to make it stop:
             obj.vx = obj.vy = 0

And so on - you will soon perceive thinking of your game "things" as "objects" as they are used in programing make the code flows quite naturally - as soon as you get the way this works, look at Pygame's sprite module - which allows you to automate a lot of checks, and updates without having to explicitly write for loops for each check



回答2:

Split up x/y movement.

Move x, check if colliding, if so, move back and set xspeed to 0.

Move y, check if colliding, if so, move back and set yspeed to 0.

It does mean two collisions checks per step but it's super smooth. :)