Sign in to follow this  
Kimimaru

Tile Engine Trouble

Recommended Posts

Hello everyone! I have a tile engine that functions well, but right now it functions purely based off of an object's location. What I'm attempting to do is take the object's collision box into account so things look and function better (for example, touching a tile that blocks you with the right side of your sprite actually blocks you instead of letting you walk until it touches your location on the left of your sprite).

 

I got it to work for blocking objects, but unfortunately it breaks when you're already on top of a higher tile. An object will be on top of a tile and fall if the tile its location is at a lower height. The reason is I get the current tile an object is on, which takes solely the object's location into account and returns the tile based on that location. Right now all of my object locations are at the top-left of the sprites.

 

So in other words, I want to modify my current tile method so that it properly gets the current tile the object is at and doesn't allow the object to fall until its sprite is completely off the tile. These two functionalities seem to conflict, which is where I'm stumped on. Does anyone have any suggestions? Any help would be greatly appreciated!

Share this post


Link to post
Share on other sites

I'm not sure I fully understand, but it sounds like you're making a side-scrolling game, right?

 

Regardless of whether that's true or not, you need to test more than just one point (more than just the top-left corner).

Basically, given two rectangles (not just points) you figure out if they are overlapping.

 

Here's a mock-up of how to do so:

bool Rect::Overlaps(const Rect &other)
{
	//LeftEdge = (x)
	//RightEdge = (x + width)
	//TopEdge = (y)
	//BottomEdge = (y + height)
	
	if(this->RightEdge < other.LeftEdge)
		return false;
	if(this->LeftEdge > other.RightEdge)
		return false;
	if(this->BottomEdge < other.TopEdge)
		return false;
	if(this->TopEdge > other.BottomEdge)
		return false;
	
	return true;
}

Share this post


Link to post
Share on other sites

Thanks for the answer! Yes, my game is side-scrolling.

 

Sorry for not being clear enough; I'll elaborate:

 

I am aware that I need to check for more than just one point. My problem deals with getting the tile you're currently on while allowing you to fall off of higher ground only once your entire character is off. Right now the current tile your character is on is defined by that single point. However, defining the current tile your character is on when taking the character's entire collision box into account isn't as simple. For instance, if my character was standing in between two tiles, how would I determine exactly which tile the character is on? The single point works because there is only one location to check, so there's no conflict.

 

In short, how can I accurately get which tile the character is on when factoring in the character's collision box?

Share this post


Link to post
Share on other sites

Assuming that sprites move freely in two dimensions, there is no such thing as "the tile you're currently on"; the number of tiles that a sprite can touch and treat as obstacles is at least three for small sprites that don't move and unlimited for moving sprites.

 

The right abstraction is processing collisions one by one as they happen, constraining sprite positions so that nothing penetrates solid objects. For example, suppose a platformer character is in free fall: when his rectangle collides with a solid tile rectangle, he bounces (vertical edges collision) or stops and stands (horizontal edges collision) as many times as necessary. Sprite position is the only useful information, and the tile grid is only an opportunity for cheaper broadphase collision detection than in the case of arbitrarily located solid rectangles.

Share this post


Link to post
Share on other sites

My game is "2.5D," so there is a dimension of height that exists independently of the X and Y positions.

 

How my tile engine works is when you move, it checks if your height is greater than or equal to the height of the next tile you're going to move to, whether it's in the X or Y direction. If that's true then you can move there, otherwise the tile will block you. If your height happens to be greater than that tile's height, then once you move onto it it'll check your height and the tile's height and make you fall until your height is equal to its height. This method has been working perfectly fine for me ever since I implemented it and I already have object collisions working as well.

 

What's happening right now is I'm incorporating my character's entire collision box when moving onto tiles. This part I got working. The only problem I have is when moving onto a tile that has less height than the one you're on. Since the current tile you're on checks only your character's position, it moves you off of the higher tile too early instead of waiting for your entire character sprite to get off.

Edited by Kimimaru

Share this post


Link to post
Share on other sites

You need to take into account all of the tiles your character is currently on.

 

If your character is smaller or equal to 1 tile sized, that means 4 tiles.

 

Then you check all of them to decide what to do.

 

 

You can still use the character-is-a-point method for some features, such as finding what tile the character primarily is on (such as wether you are standing on a button. Unless you want to be able to stand on 4 adjacent buttons at once), but for this particular thing you need to use a more advanced one.

 

If your current setup makes this difficult, you just need to redesign it.

Share this post


Link to post
Share on other sites

The only problem I have is when moving onto a tile that has less height than the one you're on. Since the current tile you're on checks only your character's position, it moves you off of the higher tile too early instead of waiting for your entire character sprite to get off.

 

So. when testing for falling, you'll need to get your character's rect for his feet.

I'd say:

feetRect.x = topLeftCorner.x;
feetRect.width = normalWidth;
feetRect.height = 10px; //Subjective. Tweak until it feels right for the dimensions of your sprites.
feetRect.y = (topLeftCorner.y + normalHeight) - feetRect.height;

You'll basically want to get a bounding box like this:

 

ejf0.png

 

Then you get the bounding box for the top surface area of your tile.

 

And you don't let the character fall until those two boxes (the tile surface box, and the sprite's feet box) are no longer colliding.

 

[b][Edit:][/b] And as Waterlimon says, you have to check against the rects of each tile surrounding the player.

Edited by Servant of the Lord

Share this post


Link to post
Share on other sites

Hey everyone, just posting an update:

 

I got this working! I used your character's feet bounding box and checked for all the tiles it collides with, then found the highest tile height out of all those tiles. This is the height you'd fall to if you were jumping or falling from a higher surface. Thanks to everyone for the help!

Share this post


Link to post
Share on other sites

Heres a useful class (written in Python, however it can be easily adapted to other languages):

class EasyRect(object):
	def __init__(self, top=0, left=0, bottom=0, right=0):
		self.top = top
		self.left = left
		self.bottom = bottom
		self.right = right
	def collides(self, other_rect):
		if (self.right > other_rect.left and self.right < other_rect.right) or (self.right > other_rect.right and self.left < other_rect.right):
			if self.bottom > other_rect.top and self.bottom < other_rect.bottom:
				return True
			if self.bottom > other_rect.bottom and self.top < other_rect.bottom:
				return True
		return False

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