How do you do the hit test?

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.
Post Reply
User avatar
liyonglove2d
Prole
Posts: 38
Joined: Sun Mar 29, 2015 7:06 am

How do you do the hit test?

Post by liyonglove2d »

My second post here :) :)

I'm making a game, and encounter with many problems and want help! Here's a screensnap for you to figure out quickly what kind of game it is:
screen shot
screen shot
game1.png (467.51 KiB) Viewed 3152 times
As you can see, a player can click the chicken to attack it, a very basic operation. The chicken is a spriter animation, made with Spriter. All of its parts are drawn to a canvas firstly, and then the canvas is drawn to the screen.
There're irregular entities in the game, so I want accurate hit test, rather than the bounding-box-method hit test.
I use the following code to do the hit testing work( Spriter in the code is a thirdparty library name ).
But here's a problem. I found a terrifying warning in the love wiki, which is really a concern:
canvas.getPixel():
This function can be very slow: it can cause the CPU to wait for the GPU to finish all the work currently in its queue, which can be a whole frame's worth (or more.)

Code: Select all

function Spriter:testHit(pos_x, pos_y, x, y, scale_x, scaley)
	local canvas = self:getCanvas()
	x, y = self.offsetX - (pos_x - x) / ((self.scalex or 1) * (scale_x or 1)), self.offsetY - (pos_y - y) / ((scaley or 1) * (self.scaley or 1))
	if not (x >= 0 and y >= 0 and x < canvas:getWidth() and y < canvas:getHeight()) then return false end
	[color=#FF0000]local _,_,_,a = canvas:getPixel(x, y)[/color]
	if a > 0 then return true end
end
I know little about the performance of most of the functions of Love2D, so worried much about it.
Can I use canvas:getPixel() here?
How do you do the accurate hit test?


thanks a lot!
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: How do you do the hit test?

Post by arampl »

You shouldn't use getPixel method of canvas. It will be deprecated in v. 0.10 as slime stated several days ago. Effective and simple approach (using same method of Image) was shown to me by Azhukar (thanks man, I was just too dumb). See our discussion "Wrappers for glReadPixel, glColor3uiv / glColor4uiv" in the "Support and Development" section. Just find his .love file "Pixel-perfect buttons" there (page 3).

EDIT: But you will need to do hit-testing before placing images on the canvas (they don't have to be actually drawn in that phase).
User avatar
liyonglove2d
Prole
Posts: 38
Joined: Sun Mar 29, 2015 7:06 am

Re: How do you do the hit test?

Post by liyonglove2d »

arampl wrote:You shouldn't use getPixel method of canvas. It will be deprecated in v. 0.10 as slime stated several days ago. Effective and simple approach (using same method of Image) was shown to me by Azhukar (thanks man, I was just too dumb). See our discussion "Wrappers for glReadPixel, glColor3uiv / glColor4uiv" in the "Support and Development" section. Just find his .love file "Pixel-perfect buttons" there (page 3).

EDIT: But you will need to do hit-testing before placing images on the canvas (they don't have to be actually drawn in that phase).
thanks a lot!
I've read "Pixel-perfect buttons". I use the same way to do hit-testing in the the key frame animation library, and it's not bad for single static image. But as for spriter animation, there're several images in one frame, those are rotated/translated or scaled, so it's maybe a little hard to do the same thing. I'm still reading other responses of that topic, and hope no mistakes here.

Can I just do hit-testing by a canvas?? :x
User avatar
liyonglove2d
Prole
Posts: 38
Joined: Sun Mar 29, 2015 7:06 am

Re: How do you do the hit test?

Post by liyonglove2d »

seems no useful information in that topic :shock:
User avatar
arampl
Party member
Posts: 248
Joined: Mon Oct 20, 2014 3:26 pm

Re: How do you do the hit test?

Post by arampl »

by slime on Wed Mar 25, 2015 9:20 pm:
slime wrote:Canvas:getPixel will be removed in LÖVE 0.10.0. Canvas:getImageData is about as fast (or faster, if you would have called getPixel in a loop.)
Not sure, maybe this method is bad. Elders will tell, I hope.

1. Create one more canvas 1x1 pixel (in love.load() for example).

2. In hit-testing function use render to this canvas and love.graphics.translate(-mx, -my) (mx, my - current mouse coords).

3. Rotate, translate, scale, etc. your images and place them in this canvas (use some optimization techniques here, to draw only images whose bounding boxes is around mouse coords).

4. Use canvas:getImageData():getPixel(0, 0).

Something like this:

Code: Select all

function love.load()
   pick_canvas = love.graphics.newCanvas(1, 1)
end

function pick()
   local r, g, b = 0, 0, 0
   local mx, my = love.mouse.getPosition()
   pick_canvas:clear()
   pick_canvas:renderTo(function ()
      love.graphics.push()
      love.graphics.translate(-mx, -my)
         for i = #images, 1, -1 do
            if images[i].x <= mx and images[i].x + images[i].width >= mx and images[i].x <= my and images[i].y + images[i].y + height >= my then
               love.graphics.draw(images[i], images[i].x, images[i].y)
               r, g, b, a = pick_canvas:getImageData():getPixel(0, 0)
                  if (r + g + b) ~= 0 and a > 0 then return i end
            end
         end
      love.graphics.pop()
   end)
   return 0
end
Let's wait for elders' reply...
Last edited by arampl on Tue Mar 31, 2015 4:16 pm, edited 3 times in total.
User avatar
liyonglove2d
Prole
Posts: 38
Joined: Sun Mar 29, 2015 7:06 am

Re: How do you do the hit test?

Post by liyonglove2d »

Inspired by you, I come to this and dont know whether its a good way or not.
Render the pixel under mouse on the canvas to be tested to a 1x1 canvas, and then apply getImageData():getPixel() to the 1x1 canvas to test alpha value.
Hope it's practical :)
User avatar
liyonglove2d
Prole
Posts: 38
Joined: Sun Mar 29, 2015 7:06 am

Re: How do you do the hit test?

Post by liyonglove2d »

arampl wrote:by slime on Wed Mar 25, 2015 9:20 pm:
slime wrote:Canvas:getPixel will be removed in LÖVE 0.10.0. Canvas:getImageData is about as fast (or faster, if you would have called getPixel in a loop.)
Not sure, maybe this method is bad. Elders will tell, I hope.

1. Create one more canvas 1x1 pixel (in love.load() for example).

2. In hit-testing function use render to this canvas and love.graphics.translate(-mx, -my) (mx, my - current mouse coords).

3. Rotate, translate, scale, etc. your images and place them in this canvas (use some optimization techniques here, to draw only images whose bounding boxes is around mouse coords).

4. Use canvas:getImageData():getPixel(0, 0).

Something like this:

Code: Select all

function love.load()
   pick_canvas = love.graphics.newCanvas(1, 1)
end

function pick()
   local r, g, b = 0, 0, 0
   local mx, my = love.mouse.getPosition()
   pick_canvas:clear()
   pick_canvas:renderTo(function ()
      love.graphics.push()
      love.graphics.translate(-mx, -my)
         for i = #images, 1, -1 do
            if images[i].x <= mx and images[i].x + images[i].width >= mx and images[i].x <= my and images[i].y + images[i].y + height >= my then
               love.graphics.draw(images[i], images[i].x, images[i].y)
               r, g, b, a = pick_canvas:getImageData():getPixel(0, 0)
                  if (r + g + b) ~= 0 and a > 0 then return i end
               end
            end
      love.graphics.pop()
   end)
   return 0
end
Let's wait for elders' reply...
I've tested this with similar code in the game, and it's indeed getting better performance! That's so great :) :) :)
Thanks again!
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 189 guests