My Sidescroller Engine starring our favorite Janitor "Eario"

Show off your games, demos and other (playable) creations.
User avatar
zac352
Party member
Posts: 496
Joined: Sat Aug 28, 2010 8:13 pm
Location: In your head.
Contact:

Re: I have broken the "Box2d-less side scroller" barrier...

Post by zac352 »

If I knew that none of you were capable of basic collision detection, I would've written a script for it.

But I did write a useful vector file:

Code: Select all

function vector(t)
	if type(t)=="number" then
		num=t
		t={}
		for i=1,num do
			t[i]=0
		end
	else
		num=math.min(4,math.max(#t,0))
	end
	local trans={
		['x']=1,
		['y']=2,
		['z']=3,
		['w']=4,
		['r']=1,
		['g']=2,
		['b']=3,
		['a']=4
	}
	local funcs={
		["scale"]=function(vec,n)
			local m=vec.magnitude/n
			return vec*m
		end,
		["grayscale"]=function(vec)
			v=vector(4)
			if #vec=="3" then
				v.a=255
			else
				v.a=vec.a
			end
			local n=(vec.r+vec.g+vec.b)/3
			v.r=a
			v.g=a
			g.b=a
			return v
		end,
		["average"]=function(vec)
			local n=0
			for i=1,#vec do
				n=n+vec[i]
			end
			return n/#vec
		end,
		["set"]=function(vec)
			if #vec==3 then
				love.graphics.setColor(vec[1],vec[2],vec[3])
			elseif #vec==4 then
				love.graphics.setColor(vec[1],vec[2],vec[3])
			end
		end,
		["tonumber"]=function(vec)
			local t={}
			for i=1,#vec do
				table.insert(t,vec[i])
			end
			if _VERSION=="Lua 5.1" then
				return unpack(t)
			elseif _VERSION=="Lua 5.2" then
				return table.unpack(t) --I don't like the change much.
			end
		end
	}
	local n=newproxy(true)
	local mt=getmetatable(n)
	local index={}
	for i=1,num do
		index[i]=t[i]
	end
	mt.__index=function(_,k)
		k=string.lower(k)
		if k=="magnitude" then
			local n=0
			for i=1,math.min(3,num) do
				n=n+index[i]^2
			end
			n=math.sqrt(n)
			return n
		elseif k=="class" then
			return "vector"..num
		elseif k=="n" then
			return num
		elseif k=="v" then
			return funcs.grayscale(n)
		else
			local tn=tonumber(k)
			if tn then
				return index[tn]
			elseif trans[k] then
				return index[trans[k]]
			elseif funcs[k] then
				return function(...)
					funcs[k](n,...)
				end
			elseif math[k] then
				return function(vec1,vec2)
					if type(vec2)=="number" then
						local v=vector(#vec1)
						for i=1,#v do
							v[i]=math[k](vec1[i],vec2)
						end
						return v
					else
						if #vec1~=#vec2 then
							return
						end
						local v=vector(#vec1)
						for i=1,#v do
							v[i]=math[k](vec1[i],vec2[i])
						end
						return v
					end
				end
			end
		end
	end
	mt.__newindex=function(_,k,v)
		k=string.lower(k)
		local tn=tonumber(k) or index[trans]
		if not tn then
			return nil
		end
		index[tn]=v
	end
	mt.__len=function(vec)
		return vec.n
	end
	mt.__tostring=function(vec)
		local s=""
		for i=1,#vec do
			s=s..vec[i]..", "
		end
		return string.sub(s,1,-3)
	end
	mt.__concat=mt.__tostring
	mt.__add=function(vec1,vec2)
		if #vec1~=#vec2 then
			return nil
		end
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=vec1[i]+vec2[i]
		end
	end
	mt.__unm=function(vec)
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=-vec[i]
		end
		return v
	end
	mt.__sub=function(vec1,vec2)
		if #vec1~=#vec2 then
			return nil
		end
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=vec1[i]-vec2[i]
		end
		return v
	end
	mt.__mul=function(vec1,vec2)
		if #vec1~=#vec2 then
			return nil
		end
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=vec1[i]*vec2[i]
		end
		return v
	end
	mt.__div=function(vec1,vec2)
		if #vec1~=#vec2 then
			return nil
		end
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=vec1[i]/vec2[i]
		end
		return v
	end
	mt.__pow=function(vec1,vec2)
		if #vec1~=#vec2 then
			return nil
		end
		local v=vector(#vec)
		for i=1,#vec do
			v[i]=vec1[i]^vec2[i]
		end
		return v
	end
	mt.__mod=function(vec1,vec2)
		if #vec1~=(type(vec2)=="number" and #vec1 or #vec2) then
			return nil
		end
		local v=vector(#vec1)
		for i=1,#vec1 do
			v[i]=vec1[i]%(type(vec2)=="number" and vec2 or vec2[i])
		end
		return v
	end
	mt.__eq=function(vec1,vec2)
		if #vec1~=#vec2 then return false end
		for i=1,#vec1 do
			if vec1[i]~=vec2[i] then
				return false
			end
		end
		return true
	end
	mt.__lt=function(vec1,vec2)
		if #vec1~=#vec2 then return false end
		for i=1,#vec1 do
			if vec1[i]>=vec2[i] then
				return false
			end
		end
		return true
	end
	mt.__le=function(vec1,vec2)
		if vec1==vec2 then return true end
		if vec1<vec2 then return true end
		return false
	end
	mt.__mode="v"
	return n
end
function vector2(x,y)
	return vector{x,y}
end
function vector3(x,y,z)
	return vector{x,y,z}
end
function vector4(x,y,z,w)
	return vector{x,y,z,w}
end
function colour3(r,g,b)
	return vector{r,g,b}
end
function colour4(r,g,b,a)
	return vector{r,g,b,a}
end
function set(t)
	if type(t)=="table" then
		return vector(t)
	end
end

Hello, I am not dead.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: I have broken the "Box2d-less side scroller" barrier...

Post by Jasoco »

What's that do?

Also, we can do collision detection. It's just that no one wanted to take the more difficult route of doing it correctly instead of resorting to using a Physics engine which isn't meant for most games.
User avatar
zac352
Party member
Posts: 496
Joined: Sat Aug 28, 2010 8:13 pm
Location: In your head.
Contact:

Re: I have broken the "Box2d-less side scroller" barrier...

Post by zac352 »

Jasoco wrote:What's that do?

Also, we can do collision detection. It's just that no one wanted to take the more difficult route of doing it correctly instead of resorting to using a Physics engine which isn't meant for most games.
I actually abandoned all attempts to use it after I crashed love's C++ runtime library. :P
Hello, I am not dead.
philnelson
Prole
Posts: 48
Joined: Sun Feb 01, 2009 3:32 am

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by philnelson »

Jasoco, once again I am in your debt.
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by kikito »

Disclaimer: I haven't read your code yet. If you are already doing this, please ignore this post.

I'm not a big fan of ray-traces because getting them to work correctly is kind of a pain. Lots of special cases.

I've found that a very fast and accurate way of detecting collisions with static terrain, if you are using tile-based maps, is using the tiles themselves. Adding a small amount of data to the tiles to indicate tangibility. Either 1 boolean (is_solid) or 4 booleans (1 per direction - solid_top, solid_bottom, solid_left, solid_right).

When checking collisions with the map, this makes ray-tracing nearly unnecessary. You just have to check for 4 tiles, but usually that can be reduced to 2 in some occasions (player size <= tile size and player velocity known)

The only thing you have to make sure is that nothing moves faster than 1 tile per time-step, like bartbes said. Giving everything a max velocity and making sure that physics_time_step < max_velocity / math.max(tile_w, tile_h). Or something along those lines.

But what about moving platforms, enemies, etc?

The tilemap-as-collision-model can be generalized. Instead of using the map level directly for making collisions, you build a "dynamic collision map" in memory. A dynamic representation of what parts of a map are traversable, what parts contain an enemy, etc. Moving platforms would just update the hard map dynamically (they would still require some extra checks for making collisions pixel-perfect, but that would still be easier to handle than ray-tracing).

Just my 2 cents





regards!
When I write def I mean function.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by Jasoco »

I'm not really sure what you mean by ray-tracing, but I am using the grid-based collision.

i.e. tile[player.x][player.y]

It's how I do all my tile-based games. Including my Adventure engine whose collision detection seems to be working much better than this one for some reason. Right now the only real bug in the collision is getting stuck on a ledge. Something I thought I was the only one to come across until I was playing Minecraft and noticed occasionally the same thing happened with that game too. But a lot more rare.

It seems to be a problem with it checking against both the top and one of the sides at once and it ends up tossing the player back and forth on the edge until you let go. If I can figure out what causes it, I can probably program in a catch for it.

There's also a bug where the player snaps to tiles when either hitting the side of the wall and there's a platform above or when landing on the ground.

I want this engine working as smooth as even the original SMB. Which I hold as the first real sidescrolling engine. I mean it can't be impossible. Just look at the vast amount of indie 2D platformers there are out there!
User avatar
qubodup
Inner party member
Posts: 775
Joined: Sat Jun 21, 2008 9:21 pm
Location: Berlin, Germany
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by qubodup »

^[ ^[ Error: main.lua:1: module 'sound.lua' not found:
no file "sound/lua.lua" in LOVE game directories.
I had to remove ".lua" in the require line to make it work on arch linux 64bit.

The game runs at about 1fps on Arch Linux 64bit on an Asus EeePC 1000H (Just letting you know in case you're curious. :) )
lg.newImage("cat.png") -- made possible by lg = love.graphics
-- Don't force fullscreen (it frustrates those who want to try your game real quick) -- Develop for 1280x720 (so people can make HD videos)
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by Jasoco »

Wow this is a blast from the past. I remember giving up on this project because of the bugginess. Actually since I gave up on this one I had released a second platformer engine that had even more bugs. I have now switched to early '90s style 3D for my current project. One day I will retry writing a 2D platformer again.
User avatar
Davidobot
Party member
Posts: 1226
Joined: Sat Mar 31, 2012 5:18 am
Location: Oxford, UK
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by Davidobot »

Jasoco wrote:Wow this is a blast from the past. I remember giving up on this project because of the bugginess. Actually since I gave up on this one I had released a second platformer engine that had even more bugs. I have now switched to early '90s style 3D for my current project. One day I will retry writing a 2D platformer again.
So you're telling me that you can make a 3D engine in a 2D game engine but can't make a platformer?!
PM me on here or elsewhere if you'd like to discuss porting your game to Nintendo Switch via mazette!
personal page and a raycaster
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: My Sidescroller Engine starring our favorite Janitor "Ea

Post by Jasoco »

Davidobot wrote:
Jasoco wrote:Wow this is a blast from the past. I remember giving up on this project because of the bugginess. Actually since I gave up on this one I had released a second platformer engine that had even more bugs. I have now switched to early '90s style 3D for my current project. One day I will retry writing a 2D platformer again.
So you're telling me that you can make a 3D engine in a 2D game engine but can't make a platformer?!
I've made numerous 2D platformers. They're buggy, but I made them.

Collisions are hard. I'm better at simple Zelda style than Mario. Scratch that. Collision correction is hard. I can do it but it's hard. The bugs I had in my last platformer (The one after this one) were worse than the ones in this one. In fact, this one actually worked better in most ways than the rewrite.
Post Reply

Who is online

Users browsing this forum: No registered users and 64 guests