Trouble with tile collision

23 views
Skip to first unread message

Kenneth D'Amica

unread,
Oct 21, 2012, 5:13:29 PM10/21/12
to gummw...@googlegroups.com
Hi, 

I'm trying to use Gummworld2 for some basic tile collision, and I'm running into some problems. I modified your make_tiles to give me a random map with two colors, with a boolean "solid" to be tested. Code is below, but basically I wanted to use Intersect_Indices to get the cells that the player's new position falls into, test to see whether they're solid, and reject the move if any are. It seems to sort of work, except that all the solid tiles have a buffer around them, which I'm pretty sure is because of the fact that get_cell returns more than one sprite, which is not what I'd expected.

Any suggestions? I tried to find a simple way to do this, but nothing popped out at me. Adding a separate object for every wall seemed like it would be unnecessarily slow.

Below is the update method for my player class, which was based on the Thing class from example 24. 

Thanks for your help.

Kenny

==================================================

    def update(self, dt, move_x, move_y):
        clearx, cleary = True, True
        new_pos_x = self.position + Vec2d((move_x,0))
        for c in State.world.intersect_indices(pygame.Rect(new_pos_x[0], new_pos_x[1], self.width, self.height)):
            for s in State.map.layers[0].objects.get_cell(c):
                if s.solid:
                    clearx = False
                    break
        new_pos_y = self.position + Vec2d((move_x if clearx else 0,move_y))
        for c in State.world.intersect_indices(pygame.Rect(new_pos_y[0], new_pos_y[1], self.width, self.height)):
            for s in State.map.layers[0].objects.get_cell(c):
                if s.solid:
                    cleary = False
                    break
        self.position = self.position + ((move_x if clearx else 0, move_y if cleary else 0))

B W

unread,
Oct 22, 2012, 1:21:41 AM10/22/12
to gummw...@googlegroups.com
Hi, Kenny.

I am sorry you're having some trouble with this. At a glance it looks like your method should work, but it really needs to be put in context in order to tell. I might be able to help if you can provide a simple test case that I can run.

For example, a window-sized map with a single "solid" cell (filled rect shape), and a player object (skeleton rect shape) that moves to collide with the solid cell. That should be enough for me to investigate what could be going wrong with the collision detection.

The spatial hash a corner case in which the hit box has the same dimensions as the cell: such a case will result in multiple cells colliding with the hit box. In the absence of enough info I'm going to float a guess, so forgive me if I'm wrong... Since it appears your method is utilizing a cell as a grid object, and possibly your player object's hit box is the same size, this may be your issue.

If so, try instead to use the cells as containers and your obstacles would be sprites whose collision rects, as well as the player's, are one pixel less than the cell size. Then your detection would be: get the cell containing player at the new position; iterate over the sprites (obstacles) contained in the cell; if any collide, reject the move.

Hope that makes sense. If not, send some code I can run that demonstrates the problem, I'll have a look and we'll regroup.

Cheers,

bw

Kenneth D'Amica

unread,
Oct 22, 2012, 10:27:36 PM10/22/12
to gummw...@googlegroups.com
Hi BW, 

Thanks for getting back to me so quickly. I tried making the rect within the sprite a little smaller, but it is still a bit messed up. I'm pretty stumped about what I'm doing wrong, and suspect I may be missing something fundamental.

I've attached my code. 

Thanks again for your help.

Kenny
map_test_1.py

B W

unread,
Oct 23, 2012, 12:16:50 AM10/23/12
to gummw...@googlegroups.com
It seems to be a subtle problem having to do with Player.position versus Player.rect. If you do math on the rect directly you have to take care to do it in the same manner as in Player.position. Otherwise your test may pass (or fail) and then when you update position, rect can get a different value and you'll permit a move that should not be allowed. Note that Player.position rounds the values before applying them to the rect.

I skirted this issue by applying the deltas, one at a time, to player.position and backing out the delta if a collision occurred.

Check the attached program w/ an alternate Player.update() and an additional small amount of visual code. Hope it is what you wanted to achieve. If not we'll keep at it. :)

Cheers, Kenny.

bw
map_test_1.py

B W

unread,
Oct 23, 2012, 12:34:43 AM10/23/12
to gummw...@googlegroups.com
Hi, Kenny.

I forgot to mention something I noticed early on. And this is what I think you meant by an apparent buffer around the cell?

In these lines:

        new_pos_x = self.position + Vec2d((move_x,0))
        for c in State.world.intersect_indices(pygame.Rect(new_pos_x[0], new_pos_x[1], self.width, self.height)):

Note that self.position is the center of the rect. This caused your hit box to be off by half the size of the Player object. I think this explains what you were witnessing.

I then noticed the subtler issue while playing with what seemed a properly calculated rect, but was still off when coming at obstacle, especially from the bottom where I saw the player get stuck in the obstacle.

bw

Kenneth D'Amica

unread,
Oct 23, 2012, 8:55:00 PM10/23/12
to gummw...@googlegroups.com
Yes, this is perfect! I guess I am so conditioned to think of everything starting at the top-left corner that I overlooked how player.position refers to the center. Thanks so much for your help!

One question: What's the purpose of collecting the cells in player.irects?

B W

unread,
Oct 23, 2012, 9:49:44 PM10/23/12
to gummw...@googlegroups.com
Glad I was able to help.

I added irects so I could see the collisions when they happen. It serves no other purpose and can be removed.

bw
Reply all
Reply to author
Forward
0 new messages