Sign in to follow this  
orcfan32

2d Collision on the LEFT side of a sprite

Recommended Posts

Hi, I'm using a simple 32x32 tile system for a sidescroller (C++). I've figured out how to work the collision on the bottom, right, and top of a sprite, however the left side is confusing me. When I go to a wall on the sprite's left side, I get stuck there and can't move. The only way to fix it is to put the sprite's position to the right 32 pixels, but obviously there's a problem with not being able to go all the way to the wall. My code is pretty straightforward. I'm taking the sprite and checking ahead, not before moving, which is probably a bad thing. The way I'm calling the player's actions is like this:
pc.SendKeys(gamekeys);
pc.DoVelocity();
pc.DoPhysics(lvl);
pc.DrawTo(screen);
Neither the SendKeys or DrawTo code matters. My DoVelocity and DoPhysics is messed up somehow. Below I'm checking to see if the tile is able to be collided with by taking the players draw x and draw y from a float and dividing it by 32 in a way that the result is an integer. This way I can detect the player's coordinates on the map. Then I add an offset. Since the sprite's height is 64, I will add 2 after dividing to an int to detect what the tile below the sprite is. Note that this works fine for the other directions.
void DoVelocity()
	{
		if (evelx > emaxvel)     // I prefixed everything with e in this
			evelx = emaxvel; // class, don't mind it. vel = velocity.
		else if (evelx < (emaxvel - (emaxvel * 2)))
			evelx = (emaxvel - (emaxvel * 2));

		edrawx += evelx;
		edrawy += evely;

		if (evelx > 0); // Messy and inefficient, don't mind.
			evelx -= .3;
		if (evelx < 0);
			evelx += .3;
	};

	void DoPhysics(Level lvl)
	{
		if (lvl.GetLevelData(edrawx/32, edrawy/32+2) == '0') //GetLevelData takes x and y coords and returns what is on that square in the
		{ // multidimensional array. This if block detects the floor.
			edrawy = edrawy/32*32;
			evely = 0;
			jumping = false;
		}
		else
		{
			evely += .2;
		}

		if (lvl.GetLevelData(edrawx/32+1, edrawy/32) == '0') // Right of player
		{
			edrawx = edrawx/32*32;
			evelx = 0;
		}
		if (lvl.GetLevelData(edrawx/32+1, edrawy/32+1) == '0') // Same, just by the player's feet, not face.
		{
			edrawx = edrawx/32*32;
			evelx = 0;
			
		}

		if (lvl.GetLevelData(edrawx/32-1, edrawy/32) == '0') // Detection of left, bugged. I can't move when I touch a wall on my left.
		{
			edrawx = edrawx/32*32;
			evelx = 0;
		}
		if (lvl.GetLevelData(edrawx/32-1, edrawy/32+1) == '0') // Left at player's feet.
		{
			edrawx = edrawx/32*32;
			evelx = 0;
		}

		if (lvl.GetLevelData(edrawx/32, edrawy/32-1) == '0') // Top.
		{
			edrawy = edrawy/32*32;
			evely += .1;
		}
	};
I have an idea why it won't work on the left, but I can't seem to explain it well enough. It's like since the very left of the sprite is too close to the wall, if we reset to edrawx/32*32, it gets into an infinite set evelx to 0. Can someone kindly shed some light on this? Any help is appreciated.

Share this post


Link to post
Share on other sites
Hmm...

I wonder if it's not that the player doesn't get a chance to leave the conditions under which their x-velocity is set to 0, although why it doesn't affect the other directions I'm not sure, unless you're making the changes for movement to the left in a way that allows the player to leave the block besides an obstacle before the code that checks their location is executed, and not doing so for movement to the right...?

Have you tried changing your conditions such that evelx is only set to 0 when its current value takes it in the direction of the obstacle? In other words, if positive evelx is movement to the right, then the left condition would be something along the lines of:

if(evelx < 0 && lvl.GetLevelData(edrawx/32-1, edrawy/32) == '0')
{
edrawx = edrawx/32*32;
evelx = 0;
}

In the case of obstacles on the right, for consistency's sake (and, perhaps, safety's), you would have a similar condition that evelx > 0.

After all, why restrict movement away from an obstacle?

Share this post


Link to post
Share on other sites
Quote:
Original post by Thaumaturgealthough why it doesn't affect the other directions I'm not sure


The origin of the sprite in the case of the left wall is always against the left wall. When I say edrawx = edrawx/32*32, it's still setting it's position at the same wall and therefore doing it over and over again.

Your check to make sure that the evelx was < 0 works, to an extent. Since the origin of the sprite is still at the left wall, I can press left and it will go through the wall (this being done from DoVelocity). It would be a bit of a hack to get this to work it seems, I could make an invisible block behind the one that the player SHOULD collide with, and use the edrawx = edrawx/32*32+32.

Would it work better if I combine the Velocity and Physics functions into one function, or even just forget about velocity?

Share this post


Link to post
Share on other sites
It might well be a good idea to merge movement and physics - movement is, after all, a subset of physics, I would say.

Perhaps a better idea than either of ours is to simply check, before updating the player's position, whether a given movement is going to result in a collision - if the movement would result in the player being in (or passing through) a wall (or other obstacle), move them only as far as just before the edge of the wall.

To do this, construct a line from the player's current position to the position that they would occupy without any obstacles in the way, and then test to see whether that line passes through any obstacles tiles, and if so, where.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this