onMouseOver Events

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

onMouseOver Events

Post by Rob.m »

Hi all,
I am new here and I have trouble with the docs. Everyones help has been greatly appreciated.

I am wondering how to implement JavaScript like onMouseOver events.

I don't think I will have any trouble detecting an onMouseOver condition. I will just poll the mouse x,y and see what it is over but I will have trouble regestering events to objects.

by way of some psuedo code -

Code: Select all

button1 = {minx = 100, maxx = 200, miny = 100, maxy = 200, onmousover = 'button1mo'}
button2 = {minx = 100, maxx = 200, miny = 300, maxy = 400, onmousover = 'button2mo'}
buttons = {button1, button2}
This is fine for something simple but if would get too tedious too fast when there are a large number of objects / buttons.

I have two questions -

1) How do I pass a refference to an 'object' using it's name space -

Code: Select all

button1 = {minx = 100, maxx = 200, miny = 100, maxy = 200, onmousover = 'button1mo'}
button2 = {minx = 100, maxx = 200, miny = 300, maxy = 400, onmousover = 'button2mo'}
buttons = {}
for x=1, 2 do
  buttons[] = ??? 'button' .. x - to achieve the same as the code in the box above
end
2) How do I pass a refference to a 'function' using it's name space -

Code: Select all

function button1mo(mx, my)
  -- do something
end

-- execute onMouseOver event for button1
function do_any_onMouseOver(button_number) -- button number is 1
  object = buttons[button_number]
  funct_name = object.onmouseover
  ??? call function named button1mo(mx, my)
end
I don't actualy need name space for the called function name. It would be fine if I could just put the functions into a numericly indexed array.

If need be I can just put mx,my in the global scope.

Can love go this far ???
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: onMouseOver Events

Post by Jasoco »

Well, you'd have to write your own.What you're looking for is a mouse enter and mouse exit callback in which case you'd want to check every frame if the mouse is over the object or not like normal at the end of the frame, and record that as a flag on the object itself, and at the beginning of the frame you'd check if "mouse is over" is false and "mouse was previously over" is true. Where previously is whether the mouse was over it at the end of the previous frame. This is when you'd call the mouseover callback and set a flag so it doesn't execute over and over. Basically in laymans terms, every frame you're taking the mouse X and Y and checking if it's inside an object. And recording this as true or false. At the same time you're checking if this flag was false in the previous frame and is true now. Then that's an enter. If both flags are true or both are false then don't do anything, and if the recorded flag was true before and is false now then that's an exit.

Maybe someone else can explain better. I'd have to code this and see how to do it. But I think I'm right.

Edit: Hey, I know who can explain better! ME!

FIRST you need to put your buttons in a table. Never do stuff like button1, button2, enemy4, etc. Always put those multiple things in tables. Create the buttons for example:

Code: Select all

local buttons = {} --Create a table to put the buttons all in...
buttons[1] = {
	x = 100, y = 100, w = 120, h = 40, mouseIsOver = false, mouseWasOver = false,
	onMouseEnter = function() print("Mouse has entered #1!") end, onMouseExit = function() print("Mouse has exited #1!") end
}
buttons[2] = {
	x = 300, y = 200, w = 100, h = 30, mouseIsOver = false, mouseWasOver = false,
	onMouseEnter = function() print("Mouse has entered #2!") end, onMouseExit = function() print("Mouse has exited #2!") end
}
And the code. Both the update and draw are merged for simplicity here but can be separated easily:

Code: Select all

local mx, my = love.mouse.getX(), love.mouse.getY()
for i = 1, #buttons do
	local b = buttons[i]                            -- Create a time saving shortcut to the button ID to make it soooo much 
                                                       easier to code this. buttons[1] becomes simply b.
	local isInside = inside(mx,my, b.x,b.y,b.w,b.h) -- Check if the mouse is inside the button by using the following function 
                                                       at the bottom of this post.
	b.mouseWasOver = b.mouseIsOver
	b.mouseIsOver = isInside

	if b.mouseWasOver == false and b.mouseIsOver == true then
		if b.onMouseEnter then b.onMouseEnter() end --If the function does not exist in the buttons generation code, it will
                                                      not execute and this prevents it from erroring by checking to see if 
                                                      it exists first before trying to call it.
	elseif b.mouseWasOver == true and b.mouseIsOver == false then
		if b.onMouseExit then b.onMouseExit() end
	elseif b.mouseWasOver == true and b.mouseIsOver == true then
		--If you want anything to happen while the mouse is over the button
	else
		--If you want anything to happen while the mouse is NOT over the button
	end

	lgr.setColor(0,0,255)
	if b.mouseIsOver then
		lgr.setColor(255,0,0)
	end
	lgr.rectangle("fill", b.x, b.y, b.w, b.h)

end
Alternatively instead of for i = 1, #buttons do and local b = buttons you can do a simple for i, b in pairs(buttons) do which will literally do the same exact thing. The other way is just simpler to explain.

If you don't have an inside function, use this one. It checks to see if a single point is inside a rectangle:

Code: Select all

function inside(x1,y1, x2,y2,w2,h2)
	return not (x1 < x2  or x2+w2 < x1 or y1 < y2 or y2+h2 < y1)
end
Now, as for onMouseDown and onMouseUp and onMouseClick, those will take a bit more code as you would need to properly check if the mouse is down or up before entering and after entering to make sure the mouse isn't just being dragged, and to make sure a clicked but not released mouse will not execute if the mouse is moved out of the box before releasing. (For when a user wants to cancel his click mid-click.) If I think of it, I'll try to code that. It's a bit harder. And makes the code more complex. And then there's if you want to have keyboard based selecting of the buttons as well as the mouse. It just gets complicated. There might actually be an existing GUI library that does all this for you if you need it.
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests