Creating and removing shapes from HardOnCollider on the fly

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by vrld »

Because shapes are really just Lua tables, you can add any custom information to them. This can be used to build an arbitrarily complex collision dispatching system atop of the callbacks. See for example my GPN11 gamejam entry (beware of the old api though). Relevant bits and pieces:
Collision callbacks
collidable.lua - collidable mixins
bomb.lua - catchall ("*") collision response
scrap.lua - individual response depending on other shape type
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
molul
Party member
Posts: 264
Joined: Sun Feb 05, 2012 6:51 pm
Location: Valencia, Spain
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by molul »

Cool, I'll have a look. Thank you!

EDIT: I fixed the problem explained below by making Spiral enter the wall 1 pixel. I don't know why it's neccessary but now it works, so I'll assume it's a Hardon "feature" (lol).



By the way, vldr, I'd appreciate a lot if you could bring some light to my current problem. I'm detecting collisions with floor, ceiling and walls with this function (the most optimized I've been able to do so far), but you can skip it for now (I copied it just in case you want to check if it's wrong):

Code: Select all

--********************************************************
-- spiral:collidingWith
--********************************************************
function spiral:collidingWith(what) -- what can be "floor", "ceiling" and "walls"
	local neighbors = spiral.bbox:_getNeighbors()
	for _,shape in pairs(neighbors) do
		for group, _ in pairs(shape._groups) do
			if (group == what) then
				if (what == "floor" and spiral:collidingWithFloor(shape)) then
					return true
				end

				if (what == "ceiling" and spiral:collidingWithCeiling(shape)) then
					return true
				end
				
				if (what == "walls") then
					local wall = spiral:collidingWithWalls(shape)
					if (wall) then return wall end
				end
			end
		end
	end
	return false
end
Thus, when none of the negihbours belong to the group I'm checking, I return false. This works like a charm except for the walls collision, that gets walls at left side of the player perfectly but not always at its right side. The function I'm using for detecting walls is (you can skip this one as well and just have a look to the next chunk):

Code: Select all

--********************************************************
-- spiral:collidingWithWalls
--********************************************************
function spiral:collidingWithWalls(shape)
	local spCX,spCY = spiral.bbox:center()
	local spX1,spY1, spX2,spY2 = spiral.bbox:bbox()
	local shCX,shCY = shape:center()
	local shX1,shY1, shX2,shY2 = shape:bbox()

	if (spiral.y + 20 < shY2 -- past ceiling
		and spiral.y + spiral.height - 20 > shY1 -- past floor
		) then
		--print ("in vertical range")
		if (spX1 <= shX2 and spX2 > shX2) then 
			spiral.x = shX2 - 10
			if (spiral.velX < 0) then spiral.velX = 0 end
			return "left"
		end

		if (spX2 >= shX1 and spX1 < shX1) then 
			spiral.x = shX1 - spiral.width + 10
			if (spiral.velX > 0) then spiral.velX = 0 end
			return "right"
		else -- if right wasn't reached, I want to know how the player's and the shape's coordinates
			print ("SPX1 ".. spX1.."\tSPX2 ".. spX2)
			print ("SHX1 ".. shX1.."\tSHX2 ".. shX2)
		end
	end
end

The insteresting part is just this (don't skip this one now, hehe):

Code: Select all

		if (spX2 >= shX1 and spX1 < shX1) then 
			spiral.x = shX1 - spiral.width + 10
			if (spiral.velX > 0) then spiral.velX = 0 end
			return "right"
		else -- if right wasn't reached, I want to know how the player's and the shape's coordinates
			print ("SPX1 ".. spX1.."\tSPX2 ".. spX2)
			print ("SHX1 ".. shX1.."\tSHX2 ".. shX2)
		end
Sometimes it detects the wall at right correctly, but sometimes not, so I put those two prints to get the values to try to debug the problem. Surprisingly, the values I get should get the colision and not print anything, but they don't. You can see it in the attachment. Explanation:

SPX1, SPX2 = Spiral (player) bounding box x1 and x2.
SHX1, SHX2 = the shape's bounding box x1 and x2. It's a wall shape (otherwise the message wouldn' be printed).
In the game window you can see "WALLS: false". This prints "left" or "right" if a wall is detected.

As you can see in the picture, the player's bounding box is next to the right wall, spX2 == shX1 (=1024) and spX1 < shX1. With these values, it should enter the "if", not the "else", so I wonder what's wrong.

I've tried with many alternatives (getting collisions with ALL shapes from the "walls" group, for instance), but the result is the same :S


I've attached the project if you need to have a look at the code.
Attachments
ShouldBeRight.png
ShouldBeRight.png (359.46 KiB) Viewed 1542 times
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by vrld »

It appears that you haven't attached the file. From the screenshot it's clear that the bug cannot be caused by the code segment you've shown, so it would be interesting to examine other places where the detection could go wrong. I also wonder why you are rolling your own collision detection but asking questions as if you are using the one provided by HC. :huh:
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
molul
Party member
Posts: 264
Joined: Sun Feb 05, 2012 6:51 pm
Location: Valencia, Spain
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by molul »

Sorry, I already fixed the problem (I edited the post so nobody lost time on it, and also I removed the .love file to save space in the server). For some reason, in shapes' bottom and right edges, collision is not perfectly detected unless those edges enter another shape by at least one pixel. Not sure why that happened, but I figured out a workaround that works.

By the way, I'm using your HOC. Not the main collide callbacks, but some of its functions and variables (shape:collidesWith(), shape._neighbors, shape:bbox() and shape:center, and of course the HC:update(dt)). The main "on_collide" callback didn't suit my needs as I couldn't detect whether I was colliding any shape in a group or not (I need it to update my variables player.onGround, player.onWall, and player.onCeiling), so I had to write my own functions, based on your useful library. Actually I just expecting you to tell me something like "HOC does not detect bottom and right edged until you enter them by 1 pixel at least", but I assumed that was what was happening and I moved on.

Anyway, sorry for wasting your time, vrld. Believe me I spent a lot of hours before coming here to ask, but I found out how to fix it a little while after that... one more time >_<
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by vrld »

molul wrote:Not the main collide callbacks, but some of its functions and variables (shape:collidesWith(), shape._neighbors, shape:bbox() and shape:center, and of course the HC:update(dt)).
The only purpose of HC:update(dt) is to check for collisions and call the callbacks accordingly, so you should skip it too.
molul wrote:The main "on_collide" callback didn't suit my needs as I couldn't detect whether I was colliding any shape in a group or not (I need it to update my variables player.onGround, player.onWall, and player.onCeiling), so I had to write my own functions, based on your useful library.
As said before, you can add any information to the shapes which you can query in the callbacks. A simple example might be this:

Code: Select all

-- on creation
wall = HC:addRectangle(0,0,20,100)
wall.type = 'wall'

-- the callback
function on_collide(dt, a,b, dx,dy)
    -- determine the player/obstacle shape
    local player, obstacle = a,b
    if player.type == 'wall' then
        player, obstacle = obstacle, player
        dx,dy = -dx,-dy
    end
    if player.type ~= 'player' then return end -- none of the shapes was the player

    if obstacle.type == 'wall' then
        -- stop player and move shape out of the wall
        player.parent.speed = 0
        player:move(dx,dy)
    end
end
molul wrote:Actually I just expecting you to tell me something like "HOC does not detect bottom and right edged until you enter them by 1 pixel at least", but I assumed that was what was happening and I moved on.
It detects whether to geometric shapes intersect and calculates the direction you need to move one of the shapes so that they don't intersect anymore. There is no such thing as pixels ;)
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
molul
Party member
Posts: 264
Joined: Sun Feb 05, 2012 6:51 pm
Location: Valencia, Spain
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by molul »

vrld wrote:The only purpose of HC:update(dt) is to check for collisions and call the callbacks accordingly, so you should skip it too.
Good to know, thanks! However, I'm using the HOC to get collisions with items and enemies, so I can keep it :)

vrld wrote:As said before, you can add any information to the shapes which you can query in the callbacks. A simple example might be this:

Code: Select all

{code}
In fact I tried something like that. If a == player and b.type == "ground", then player.onGround = true. But then I couldn't figure out how to get if player.onGround wasn't true anymore. Using a tiled map to create collision shapes, when using the "collide_stop" callback, I could get if the player wasn't colliding with a ground type shape that was colliding with last frame, but the "on_collide" could be detecting another floor tile, so I was getting a blinking "true"/"false" value when walking from one tile to another. That's why I ended up writing my own functions.

I'm sure there must be a way to do it using the main HC functionality, but I couldn't figure out how to do it.
User avatar
TechnoCat
Inner party member
Posts: 1612
Joined: Thu Jul 30, 2009 12:31 am
Location: Milwaukee, WI
Contact:

Re: Creating and removing shapes from HardOnCollider on the

Post by TechnoCat »

vrld wrote:
molul wrote:Actually I just expecting you to tell me something like "HOC does not detect bottom and right edged until you enter them by 1 pixel at least", but I assumed that was what was happening and I moved on.
It detects whether to geometric shapes intersect and calculates the direction you need to move one of the shapes so that they don't intersect anymore. There is no such thing as pixels ;)
To make this more clear: If the vertex of one shape is on the line of another shape, that isn't a collision (intersection).
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Amazon [Bot] and 5 guests