『QT』about click mouse to select the sprite(image)

General discussion about LÖVE, Lua, game development, puns, and unicorns.
poorenglish
Prole
Posts: 47
Joined: Thu Sep 24, 2009 1:49 pm

『QT』about click mouse to select the sprite(image)

Post by poorenglish »

I click the mouse hope to select the sprite(image,animation) on the program.
Method 1,get the location of the mouse , the sprite(image) location and the width and height,to judge whether the mouse's postion is in the image.OK!
Continue,the image is rectangle,but the sprite is not the rectangle,some part is transparent in the image,when I click on the transparent's part,it is in the image,but it is not in the sprite.It seems I need prepare the table to store the image info,which grid is transparent?When I use the animation,it is too complexity.
Method 2,get the color of the mouse click,judge whether the color is same as backgroud, that I do not need to store the image info.
OK,is there a function to get the color when click the mouse.or get the color on the special location on the image?
Method 3,Is there a more effect mode which I do not know?

OK thanks very much.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by coffee »

Till you get a better answer since i'm not an expert on this but I think one theoretical solution is use ImageData:getPixel to check the alpha of the clicked point in that image. If is transparent then you advance in Z-order of stack of objects sharing same location/pixel (drawing order). Continue to check the alpha in next object till you get an object that alpha not transparent and so you select then that object as draggable. (https://love2d.org/wiki/ImageData:getPixel).
poorenglish
Prole
Posts: 47
Joined: Thu Sep 24, 2009 1:49 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by poorenglish »

OK,thks!I'll try it
User avatar
ston
Prole
Posts: 21
Joined: Fri Jan 27, 2012 9:53 am
Location: Holt, a small village in Wiltshire. We have cider!

Re: 『QT』about click mouse to select the sprite(image)

Post by ston »

To add to what coffee said, I think that you need to use a frame buffer to get at the image data, i.e. render your sprite into a frame buffer.

Just tested this using a simple 40x40 .png image, which was a small black square inside a transparent border:

Code: Select all

-- square.png is 40x40
state_string = ""

function love.load()

	-- allow our black box image to be seen; pink-ish background
	love.graphics.setBackgroundColor(200, 160, 160)

	-- create a framebuffer to render the box image into
	box_buffer = love.graphics.newFramebuffer(40, 40)

	-- the box image
	my_square = love.graphics.newImage("square.png")

	-- set the render target
	love.graphics.setRenderTarget(box_buffer)
	-- draw the image into the framebuffer
	love.graphics.draw(my_square, 0, 0)
	-- clear the render target
	love.graphics.setRenderTarget()

	-- the box's image data
	box_image_data = box_buffer:getImageData()
end

function love.draw()

	-- draw the box in the buffer (at 100,100)
	love.graphics.draw(box_buffer, 100, 100)

	-- display the state string
	love.graphics.print(state_string, 200, 200)
end


function love.mousepressed(x, y, button)

	local in_area = false

	-- is the click in our image area?
	if x >= 100 and x < 140 and y >= 100 and y < 140 then
		in_area = true
	end

	if not in_area then
		state_string = "OUTSIDE"
	end

	if in_area then
		r, g, b, a = box_image_data:getPixel(x - 100, y - 100)
		state_string = "ALPHA: " .. a
	end
end

If you click outside the image area entirely, "OUTSIDE" is displayed, "ALPHA: 255" is displayed if you have clicked in a part which is not transparent and "ALPHA: 0" if it is a transparent part of the image.

Things probably get more complicated if you have a stack of images and you have to navigate through their 'Z order' (I'm not sure how to do that yet, sorry).

HTH :-)
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by coffee »

ston wrote:Things probably get more complicated if you have a stack of images and you have to navigate through their 'Z order' (I'm not sure how to do that yet, sorry).

HTH :-)
Thank you for your testing my concept but I'm not really sure if your system will work since isn't a demo with multiple objects. Are you thinking check a "flattened" buffer image with all objects? That won't work but however if you thinking do a temporary buffer for each separate image I think will do the trick.

About Z order. Isn't quite hard if you do an object management similar or close to this one
https://love2d.org/wiki/Skip_list:Drawing_Order
The concept of z-order is nothing much more than have a table to keep the order that elements must be draw (sort of layering). Then I think would be enough do a clumsy sweep of all elements to see what is the first element at top that:
1 - is in the mouse position
2 - have that point transparent

EDITED: A possible flaw with the transparent technique is if the image object have inside alpha "holes". In that case would fail get that object even if wanted. Alternative to this would be create a engine that would use a alpha pixel data image (not a good description I know) that would keep if that point is intended to be draggable or not.
User avatar
ston
Prole
Posts: 21
Joined: Fri Jan 27, 2012 9:53 am
Location: Holt, a small village in Wiltshire. We have cider!

Re: 『QT』about click mouse to select the sprite(image)

Post by ston »

coffee wrote:Are you thinking check a "flattened" buffer image with all objects?
I was only thinking of one image for the purpose of the little demo I knocked up. I don't see how a 'flattened buffer' could work at all (how would you decode it back to the image/sprite you're interested in?); you'd need to use a stack of frame buffers as you indicate and check though them until finding the uppermost one which isn't transparent where the mouse is clicking.

As well as the 'alpha holes' problem, you might also need to take into consideration different levels of alpha-blending (not all images would necessarily have completely transparent regions), but you could quite easily associate an alpha level with any particular image.
About Z order. Isn't quite hard if you do an object management similar or close to this one
https://love2d.org/wiki/Skip_list:Drawing_Order
Ta, quite useful info that.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by coffee »

ston wrote: I was only thinking of one image for the purpose of the little demo I knocked up. I don't see how a 'flattened buffer' could work at all (how would you decode it back to the image/sprite you're interested in?)
Yes, so as I said before
That won't work
;)
Sorry, I wasn't doubting of your coding abilities but since I saw only one layer/object I wasn't sure if you were distracted/aware/noticed that possible problem dealing with multiple objects.
ston wrote:As well as the 'alpha holes' problem, you might also need to take into consideration different levels of alpha-blending (not all images would necessarily have completely transparent regions), but you could quite easily associate an alpha level with any particular image.
Well, that could work applying a value of 1 in alpha, but would turn a "dirty" method that actually could provoke some "ghost" image effects with some contrasting colors /large transparent zones or became worse when multiple transparent objects stacked. As coding method we woudn't be doing the right thing but yes could work as turnaround to avoid implement other measures or create "data" images for all draggable objects. Good suggestion.
User avatar
ston
Prole
Posts: 21
Joined: Fri Jan 27, 2012 9:53 am
Location: Holt, a small village in Wiltshire. We have cider!

Re: 『QT』about click mouse to select the sprite(image)

Post by ston »

You got me to thinking about multiple layers earlier on today, so I've knocked up a better demo this evening.

This draws 10 random circles to the screen. Each time one is clicked on, it's brought up to the top of the Z-order and allows you to drag it about with the mouse. That way, you can see that a circle at any z-order can be selected. It uses the same framebuffer/alpha-channel idea as before.

Code: Select all

-- main layers table
t = {}


function love.load()

	-- get window size
	win_x = love.graphics.getWidth()
	win_y = love.graphics.getHeight()

	-- set b/g colour
	love.graphics.setBackgroundColor(220, 180, 180)

	-- the point at which the mouse clicks one of the circles
	bound_x = 0
	bound_y = 0

	-- create our set of circles
	for i = 1, 10, 1 do

		-- new drawing layer
		layer = {}

		-- circle's radius
		c_radius = math.random(40, 80)

		-- circle's colour
		r = math.random(50, 255)
		g = math.random(50, 255)
		b = math.random(50, 255)

		-- framebuffer to draw the circle to
		f_buff = love.graphics.newFramebuffer(c_radius * 2, c_radius * 2)

		-- draw the circle into the framebuffer
		love.graphics.setRenderTarget(f_buff)
		love.graphics.setColor(r, g, b)
		love.graphics.circle("fill", c_radius, c_radius, c_radius, 30)
		love.graphics.setRenderTarget()

		-- starting position for the framebuffer containing this circles
		-- framebufer is within the bounds of the window
		buff_x = math.random(0, win_x - c_radius * 2)
		buff_y = math.random(0, win_y - c_radius * 2)

		-- create this layer's information
		-- framebuffer
		layer["f_buff"] = f_buff

		-- x, y position
		layer["buff_x"] = buff_x
		layer["buff_y"] = buff_y

		-- width and height of framebuffer
		layer["buff_w"] = c_radius * 2
		layer["buff_h"] = c_radius * 2

		-- whether this circle is being held by the mouse
		layer["bound"] = false

		-- add the new layer to the collection
		t[i] = layer

	end

end


function love.draw()

	-- iterate through the layers and draw each framebuffer
	-- this is effectively in reverse Z-order
	for i = 1, 10, 1 do

		this_layer = t[i]

		love.graphics.draw(this_layer["f_buff"], this_layer["buff_x"], this_layer["buff_y"])

	end

end


-- checks to see whether the mouse click is inside the circle within the provided framebuffer layer
-- x, y are the mouse-click coordinates
function click_is_inside(the_layer, x, y)

	rc = false
	within  = false

	-- get the bounds of the frame buffer; left, right, top, bottom
	buff_l = the_layer["buff_x"]
	buff_r = buff_l + the_layer["buff_w"]

	buff_t = the_layer["buff_y"]
	buff_b = buff_t + the_layer["buff_h"]

	-- is the mouse click within the bounds of the framebuffer?
	if buff_l <= x and x <= buff_r and buff_t <= y and y <= buff_b then

		within = true

	end

	if within then

		-- click is within the framebuffer, is it on the circle contained therein?
		f_buffer = the_layer["f_buff"]

		-- check the alpha of the pixel where the mouse is
		img_data = f_buffer:getImageData()

		r, g, b, a = img_data:getPixel(x - buff_l, y - buff_t)

		if a == 255 then

			-- the click is on the circle
			rc = true

		end

	end

	return rc

end



function love.update(dt)

	-- is the top circle bound?
	if t[10]["bound"] then

		-- yes; update its framebuffer position according to the relative mouse movement
		mouse_x, mouse_y = love.mouse.getPosition()

		-- how far has the mouse moved since the last update?
		diff_x = mouse_x - bound_x
		diff_y = mouse_y - bound_y

		-- update our 'capture point' information, otherwise we'll start
		-- accelerating the movement of the circle (not what we want)
		bound_x = mouse_x
		bound_y = mouse_y

		-- finally, move the framebuffer to track the mouse movement
		t[10]["buff_x"] = t[10]["buff_x"] + diff_x
		t[10]["buff_y"] = t[10]["buff_y"] + diff_y

	end

end



function love.mousepressed(x, y, button)

	-- reverse-traverse the layers (highest Z order first)
	for i = 10, 1, -1 do

		this_layer = t[i]

		if click_is_inside(this_layer, x, y) then

			-- 'bound' for dragging
			this_layer["bound"] = true

			-- record the point where the mouse grabbed the circle
			bound_x = x
			bound_y = y

			-- promote the layer to the top of the Z-order
			table.remove(t, i)
			table.insert(t, this_layer)

			-- job done; only one circle can be clicked
			break

		end


	end

end


function love.mousereleased(x, y, button)

	-- clear the 'bound' condition; we only need to do this
	-- for the top layer as it's always promoted when clicked on :-)
	t[10]["bound"] = false

end

coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by coffee »

ston wrote:You got me to thinking about multiple layers earlier on today, so I've knocked up a better demo this evening.

This draws 10 random circles to the screen. Each time one is clicked on, it's brought up to the top of the Z-order and allows you to drag it about with the mouse. That way, you can see that a circle at any z-order can be selected. It uses the same framebuffer/alpha-channel idea as before.
Nice, your Z-code works but you probably have something wrong eating memory or infinite looping. I change and move some circles but some time after always crash.

Is still poorenglish around to enjoy this?
poorenglish
Prole
Posts: 47
Joined: Thu Sep 24, 2009 1:49 pm

Re: 『QT』about click mouse to select the sprite(image)

Post by poorenglish »

Sorry,late to replay,I enjoy it.
When I use it on animation,it seems need modify on the AnAL.lua?
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests