2.5D implementation

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
paramecij
Prole
Posts: 2
Joined: Thu Jan 06, 2011 12:18 am

2.5D implementation

Post by paramecij »

Hi, i'm looking for ideas & suggestions on what would be the best way to implement something like this in LUA:

Image

..mainly how to do sprite ordering & collisions in a situation as depicted above :brows:
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: 2.5D implementation

Post by Jasoco »

Sprite Z ordering is easy. You just sort the objects table by its Y value.

If I made the game, and believe me, I've wanted to make something like the old Konami side-scrolling TMNT/Simpsons arcade games, every character and object on screen would be an actor or scenery. In my Adventure game project I use this method. All enemies, scenery, dropped items and the player, etc, are dumped into a table each frame, and that table is then sorted by its Y value using code like this:

Code: Select all

function sort(T) table.sort(T, function(a, b) return a.y < b.y end ) end
table.sort(T) where T is the table name of the table you put all your objects in. This will sort them in ascending order so they get drawn in the correct order. a.y < b.y is the key part here as it sorts the first one before the second one. If you reversed them you'd draw the objects in the wrong order.

Can't help you with the collisions. Well, I can. But it might be different in every game. There's an active thread with a collision function out there somewhere. This is the code I use for finding if two rectangles collide:

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	local tl, bl, tr, br = false, false, false, false
	if (x2 >= x1 and x2 <= (x1 + w1)) and (y2 >= y1 and y2 <= (y1 + h1)) then tl = true end
	if (x2+w2 >= x1 and x2+w2 <= (x1 + w1)) and (y2 >= y1 and y2 <= (y1 + h1)) then tr = true end
	if (x2 >= x1 and x2 <= (x1 + w1)) and (y2+h2 >= y1 and y2+h2 <= (y1 + h1)) then bl = true end
	if (x2+w2 >= x1 and x2+w2 <= (x1 + w1)) and (y2+h2 >= y1 and y2+h2 <= (y1 + h1)) then br = true end
	if (x1 >= x2 and x1 <= (x2 + w2)) and (y1 >= y2 and y1 <= (y2 + h2)) then tl = true end
	if (x1+w1 >= x2 and x1+w1 <= (x2 + w2)) and (y1 >= y2 and y1 <= (y2 + h2)) then tr = true end
	if (x1 >= x2 and x1 <= (x2 + w2)) and (y1+h1 >= y2 and y1+h1 <= (y2 + h2)) then bl = true end
	if (x1+w1 >= x2 and x1+w1 <= (x2 + w2)) and (y1+h1 >= y2 and y1+h1 <= (y2 + h2)) then br = true end
	if tl or tr or bl or br then return true else return false end
end
Yes, there might be a more compact way to do it, if so, let me know. As long as it takes the same parameters and returns the same values, I don't care what the function looks like.

Where x, y, w and h are the location and size of each rectangle. Where a rectangle would be a fist and an enemy. 1 would be the fist, 2 would be the enemy. And you would check against each enemy to see if your fist (Or foot) collided. Then take the appropriate action.

This function would also be used for picking up items by checking against every dropped item on screen to see if you walked over it.
User avatar
paramecij
Prole
Posts: 2
Joined: Thu Jan 06, 2011 12:18 am

Re: 2.5D implementation

Post by paramecij »

I've done this before in c++ in various ways (also with methods you described) but I'm completely new to LUA and LÖVE .. so I thought maybe there's a different angle on this that one can leverage using LUA :) .. while this approach works (and can be optimised) I never really liked it. I wonder how the old arcades did it, surely they didn't just sort everything and BB-check a lot every frame?

BUT in this particular case the "perspective" was/is giving me a little trouble, (XY plane representing the ground it appears like a skewed rectangle) mainly with the !$!=# STAIRS .. how would I sort and collide the player against the rail/stairs?
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: 2.5D implementation

Post by Jasoco »

Stairs are a bit harder. I would say it's basically just an extra Y offset depending on where along the stairs you are.

Is this a game you made or someone made? Is this a real game? Are you sure the stairs are accessible by the player? It might just be scenery. As that wouldn't require actual interaction.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: 2.5D implementation

Post by Robin »

Jasoco wrote:

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	local tl, bl, tr, br = false, false, false, false
	if (x2 >= x1 and x2 <= (x1 + w1)) and (y2 >= y1 and y2 <= (y1 + h1)) then tl = true end
	if (x2+w2 >= x1 and x2+w2 <= (x1 + w1)) and (y2 >= y1 and y2 <= (y1 + h1)) then tr = true end
	if (x2 >= x1 and x2 <= (x1 + w1)) and (y2+h2 >= y1 and y2+h2 <= (y1 + h1)) then bl = true end
	if (x2+w2 >= x1 and x2+w2 <= (x1 + w1)) and (y2+h2 >= y1 and y2+h2 <= (y1 + h1)) then br = true end
	if (x1 >= x2 and x1 <= (x2 + w2)) and (y1 >= y2 and y1 <= (y2 + h2)) then tl = true end
	if (x1+w1 >= x2 and x1+w1 <= (x2 + w2)) and (y1 >= y2 and y1 <= (y2 + h2)) then tr = true end
	if (x1 >= x2 and x1 <= (x2 + w2)) and (y1+h1 >= y2 and y1+h1 <= (y2 + h2)) then bl = true end
	if (x1+w1 >= x2 and x1+w1 <= (x2 + w2)) and (y1+h1 >= y2 and y1+h1 <= (y2 + h2)) then br = true end
	if tl or tr or bl or br then return true else return false end
end
Yes, there might be a more compact way to do it, if so, let me know. As long as it takes the same parameters and returns the same values, I don't care what the function looks like.
Hm. Lemme try.

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	return (((x2+w2 >= x1 and x2+w2 <= (x1 + w1)) or (x2 >= x1 and x2 <= (x1 + w1)))
		and ((y2 >= y1 and y2 <= (y1 + h1)) or (y2+h2 >= y1 and y2+h2 <= (y1 + h1)))
end
Warning: untested, and it can probably be made shorter.
Help us help you: attach a .love.
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: 2.5D implementation

Post by Jasoco »

Robin wrote:Hm. Lemme try.

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	return (((x2+w2 >= x1 and x2+w2 <= (x1 + w1)) or (x2 >= x1 and x2 <= (x1 + w1)))
		and ((y2 >= y1 and y2 <= (y1 + h1)) or (y2+h2 >= y1 and y2+h2 <= (y1 + h1))))
end
Warning: untested, and it can probably be made shorter.
Amazing. Aside from a missing closing parenthesis at the end, (Which I added above in the quote just in case someone wants to use the code it'll work right.) it works just as well. Thanks! I can't see how it could get any shorter without taking out all the spaces, replacing the two digit variables with single digit ones, removing unneeded parenthesis and putting it all on one line. Like this...

Code: Select all

function o(x,y,w,h,a,b,c,d) return (((a+c>=x and a+c<=x+w) or (a>=x and a<=x+w)) and ((b>=y and b<=y+h) or (b+d>=y and b+d<=y+h))) end
And it even works! Though it's pretty compact and should probably be used if you never plan on editing it again. The only way it could get smaller is if I could use & and | for and and or.[/size]
Edit: Wait, I spoke too soon. Yours doesn't always detect collisions. I had this same problem when I first wrote mine. I implemented yours and suddenly a lot of my collisions were being ignored. Enemy hits missing, item pickups un-picked-up. Hmm... Still, there must be a way. For now, mine works fine and dandy.

Edit more:
This works though. I wrote my original function when I was a n00b at Lua and didn't know all the cool tricks. I improved my own method to utilize the method you use:

Code: Select all

function overlap(x1,y1,w1,h1, x2,y2,w2,h2)
	return (x2 >= x1 and x2 <= x1+w1) and (y2 >= y1 and y2 <= y1+h1) or
		(x2+w2 >= x1 and x2+w2 <= x1+w1) and (y2 >= y1 and y2 <= y1+h1) or
		(x2 >= x1 and x2 <= x1+w1) and (y2+h2 >= y1 and y2+h2 <= y1+h1) or
		(x2+w2 >= x1 and x2+w2 <= x1+w1) and (y2+h2 >= y1 and y2+h2 <= y1+h1) or
		(x1 >= x2 and x1 <= x2+w2) and (y1 >= y2 and y1 <= y2+h2) or
		(x1+w1 >= x2 and x1+w1 <= x2+w2) and (y1 >= y2 and y1 <= y2+h2) or
		(x1 >= x2 and x1 <= x2+w2) and (y1+h1 >= y2 and y1+h1 <= y2+h2) or
		(x1+w1 >= x2 and x1+w1 <= x2+w2) and (y1+h1 >= y2 and y1+h1 <= y2+h2)
end
See, it has to check both object A to B as well as B to A else it misses half the time. As I mentioned above in the tiny text, it can't get much smaller unless I remove all the extraneous spaces and rename the function and local variables. Oh, and if Lua let me use & and | instead of "and" and "or". (Though Lua would probably do it && and ||.)
User avatar
ghostwriter
Prole
Posts: 38
Joined: Sat Dec 11, 2010 11:08 pm

Re: 2.5D implementation

Post by ghostwriter »

Jasoco wrote:Yes, there might be a more compact way to do it, if so, let me know. As long as it takes the same parameters and returns the same values, I don't care what the function looks like.
At the risk of hijacking paramecij's thread, i'll share my rectangle collision code:

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	if x1+w1 < x2 
	or x2+w2 < x1 
	or y1+h1 < y2
	or y2+h2 < y1 then 
		return false 
	end
	return true
end
As you can see, an easier question than "are these rectangles colliding" is "are these rectangles not colliding?"
Attachments
collide.love
(441 Bytes) Downloaded 186 times
User avatar
ghostwriter
Prole
Posts: 38
Joined: Sat Dec 11, 2010 11:08 pm

Re: 2.5D implementation

Post by ghostwriter »

To reply to paramecij's original question, I would recommend storing the full three dimensional x-y-z coordinates of each sprite. That way you can still use the sorting method suggested by Jasoco, as well as have things like stairs. For example, moving left and right would change the x position, moving towards or away from the screen would change the z position and moving vertically changes the Y position.

This way you could still simply sort by Z position for drawing, no matter how high something is on the Y axis. You'd just have to figure out how to draw everything in the correct position. You can see in the image below, even though the two characters are on the stairs, their z-position is closer than the z-position of the guy on the ground beside them.
zorder.png
zorder.png (21.2 KiB) Viewed 5369 times
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: 2.5D implementation

Post by Robin »

ghostwriter wrote:At the risk of hijacking paramecij's thread,
Oops.
ghostwriter wrote:i'll share my rectangle collision code:
Your version was exactly what I meant, I just couldn't remember what it was exactly, probably because of the Eldritch abomination that was the original (sorry, Jasoco).

Anyway, to make it even shorter:

Code: Select all

function overlap(x1,y1,w1,h1,x2,y2,w2,h2)
	return not (x1+w1 < x2  or x2+w2 < x1
	            or y1+h1 < y2 or y2+h2 < y1)
end
Help us help you: attach a .love.
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: 2.5D implementation

Post by Jasoco »

ghostwriter wrote:To reply to paramecij's original question, I would recommend storing the full three dimensional x-y-z coordinates of each sprite. That way you can still use the sorting method suggested by Jasoco, as well as have things like stairs. For example, moving left and right would change the x position, moving towards or away from the screen would change the z position and moving vertically changes the Y position.

This way you could still simply sort by Z position for drawing, no matter how high something is on the Y axis. You'd just have to figure out how to draw everything in the correct position. You can see in the image below, even though the two characters are on the stairs, their z-position is closer than the z-position of the guy on the ground beside them.
zorder.png
At the risk of being stupid and an idiot because it goes against every 3d game ever made, but I always prefer to refer to X and Y as being the floor and Z being the height of the room. It always seemed weird to have Z be north and south and Y being above and below. Just seems stupid and I blame iD Software even though they probably didn't come up with it, but I need a scapegoat to blame and they were the first to come to mind. i.e., the ground in that game would be X and Y and the Z would be the characters jumping or on stairs position above the ground level.

So basically, in my adventure game engine, X and Y are the left, right, up and down of my map and "elevation" is the Z coordinate for when placing scenery or having a flying enemy. Makes much more sense this way to me and doesn't require me to edit my project to replace all the Y's with Z's.

But other than that, I agree. That picture is exactly how it should be handled. I would like to make a game like this one day and this is the method I would use too. Though I'd also like to make an isometric adventure game one day too. I have abandoned projects for so many game types including an almost arcade perfect Pac-Man that I never got around to finishing because I ran out of ideas or hit a wall or got bored. My Adventure engine remains the one major project I've started and stuck with.

Also, Robin, your new code seems to work just as well too. Using it for now unless I hit the same bug I had before. Hopefully it works perfect because I like how much less space it takes.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 2 guests