So right now I am making a basic touch control dpad that instead of having square buttons it has triangular buttons similar to the ones that you can find in the snes9xex emulator, and I am having some confusing issues
Shortly the up and down buttons are working as a charm but the left and right button are extremely weird
Because they do not detect when you press them like the prevew and the detected area do not match at all
But there's still a detected area wich I don't know how it looks exactly but it is there
I have one lead for why that happens and it is that the function that I use for detecting the triangles is confused because of the order of the positions because remember that the up and down buttons work properly and the prevew on screen is correct
I have left an attachment with the main.lua file that way you can see it for yourself and when running it and you have an error that sais "wtf" I made it this means that you have been able to press the right button
Issues with triangle collisions
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Issues with triangle collisions
- Attachments
-
- main.lua
- (2.93 KiB) Downloaded 355 times
Re: Issues with triangle collisions
It would be easier to use a point-circle collision around the buttons. Just a tip to reconsider as an option.
Re: Issues with triangle collisions
I think I agree with Rigachupe's suggestion, though I'm not sure if it's about a circle around each individual button, or one single big circle around all of them.
I think it should be a single big circle that encompasses all buttons, and with some extra pixels in the radius.
Among your players there'll be people with fat fingers or playing on a moving bus etc. and you want to be as permissive as possible with your d-pad.
I was going to suggest using dot products to test the touch position against each cardinal direction (up, down, left, right) based on the circle center, but it turns out that the dot products and the perfect diagonal angles cause things to reduce down to just picking the (absolute) biggest of the two touch coordinates as the d-pad direction. See the code below.
Note that this d-pad circle is drawn only for debugging purposes. The circle should not be visible in your actual game, where you'll only draw the triangle symbols for each button, as each button represents a slice of that circle.
I think it should be a single big circle that encompasses all buttons, and with some extra pixels in the radius.
Among your players there'll be people with fat fingers or playing on a moving bus etc. and you want to be as permissive as possible with your d-pad.
I was going to suggest using dot products to test the touch position against each cardinal direction (up, down, left, right) based on the circle center, but it turns out that the dot products and the perfect diagonal angles cause things to reduce down to just picking the (absolute) biggest of the two touch coordinates as the d-pad direction. See the code below.
Note that this d-pad circle is drawn only for debugging purposes. The circle should not be visible in your actual game, where you'll only draw the triangle symbols for each button, as each button represents a slice of that circle.
Code: Select all
-- Virtual D-Pad example.
io.stdout:setvbuf('no')
local mathAbs = math.abs
local HALF_SQUARE_ROOT = math.sqrt(2.0) / 2.0
local QUARTER_PI = math.pi / 4.0
local DPAD = {
radius = 128,
radiusSquared = 128 * 128,
center = {x = 200, y = 250},
direction = nil,
}
function love.load()
love.window.setTitle('Virtual D-Pad Example')
love.mouse.setCursor(love.mouse.getSystemCursor('crosshair'))
end
function love.update(dt)
local mx, my = love.mouse.getPosition()
local mouseVectorX = mx - DPAD.center.x
local mouseVectorY = my - DPAD.center.y
local mouseVectorLengthSquared = (mouseVectorX * mouseVectorX
+ mouseVectorY * mouseVectorY)
if mouseVectorLengthSquared > DPAD.radiusSquared then
DPAD.direction = nil
return
end
if mathAbs(mouseVectorX) > mathAbs(mouseVectorY) then
-- Horizontal direction.
DPAD.direction = mouseVectorX > 0.0 and 'right' or 'left'
else
-- Vertical direction.
DPAD.direction = mouseVectorY > 0.0 and 'down' or 'up'
end
end
function love.draw()
if DPAD.direction then
love.graphics.setColor(0.3, 0.75, 0.14, 0.3)
else
love.graphics.setColor(0.3, 0.75, 0.14, 0.1)
end
love.graphics.circle('fill', DPAD.center.x, DPAD.center.y, DPAD.radius, DPAD.radius)
love.graphics.setLineWidth(1.0)
love.graphics.setColor(0.5, 0.5, 0.5)
local cornerOffset = DPAD.radius * HALF_SQUARE_ROOT
love.graphics.line(DPAD.center.x - cornerOffset, DPAD.center.y - cornerOffset,
DPAD.center.x + cornerOffset, DPAD.center.y + cornerOffset)
love.graphics.line(DPAD.center.x + cornerOffset, DPAD.center.y - cornerOffset,
DPAD.center.x - cornerOffset, DPAD.center.y + cornerOffset)
love.graphics.setColor(1.0, 1.0, 0.0)
local mx, my = love.mouse.getPosition()
love.graphics.line(DPAD.center.x, DPAD.center.y, mx, my)
love.graphics.setColor(1.0, 1.0, 1.0)
love.graphics.print('- Hover the mouse on the virtual D-Pad.', 10, 10)
love.graphics.print('- Press Esc to quit.', 10, 30)
love.graphics.print('Mouse: ' .. mx .. ', ' .. my, 10, 50)
if DPAD.direction then
local angle1, angle2
if DPAD.direction == 'up' then
angle1, angle2 = -QUARTER_PI, -QUARTER_PI * 3.0
elseif DPAD.direction == 'down' then
angle1, angle2 = QUARTER_PI, QUARTER_PI * 3.0
elseif DPAD.direction == 'right' then
angle1, angle2 = -QUARTER_PI, QUARTER_PI
elseif DPAD.direction == 'left' then
angle1, angle2 = QUARTER_PI * 3.0, QUARTER_PI * 5.0
end
love.graphics.setColor(1.0, 1.0, 0.2, 0.5)
love.graphics.arc('fill', DPAD.center.x, DPAD.center.y, DPAD.radius, angle1, angle2)
love.graphics.setColor(1.0, 1.0, 1.0)
love.graphics.print(DPAD.direction, DPAD.center.x - 20, DPAD.center.y + DPAD.radius + 10, 0.0, 2.0, 2.0)
end
love.graphics.setColor(0.3, 0.75, 0.14, 1.0)
love.graphics.setLineWidth(3.0)
love.graphics.circle('line', DPAD.center.x, DPAD.center.y, DPAD.radius, DPAD.radius)
end
function love.keypressed(key)
if key == 'escape' then
love.event.quit()
end
end
Re: Issues with triangle collisions
A button is usually a rectangle. In your case triangle. A circle can be put around the button of this two shapes or inside of them. It is just like an collision shape attached to the image.
Btw you can put the images into attachements array while writing post and then insert them into text.
Btw you can put the images into attachements array while writing post and then insert them into text.
Re: Issues with triangle collisions
Thanks for the code man only by reading it I learned so much and I think that I will go for a circle now it's much better I just need to change it in a way that makes diagonals possibleRNavega wrote: ↑Sun Jul 28, 2024 5:06 am I think I agree with Rigachupe's suggestion, though I'm not sure if it's about a circle around each individual button, or one single big circle around all of them.
I think it should be a single big circle that encompasses all buttons, and with some extra pixels in the radius.
Among your players there'll be people with fat fingers or playing on a moving bus etc. and you want to be as permissive as possible with your d-pad.
I was going to suggest using dot products to test the touch position against each cardinal direction (up, down, left, right) based on the circle center, but it turns out that the dot products and the perfect diagonal angles cause things to reduce down to just picking the (absolute) biggest of the two touch coordinates as the d-pad direction. See the code below.
Note that this d-pad circle is drawn only for debugging purposes. The circle should not be visible in your actual game, where you'll only draw the triangle symbols for each button, as each button represents a slice of that circle.
preview.png
Code: Select all
-- Virtual D-Pad example. io.stdout:setvbuf('no') local mathAbs = math.abs local HALF_SQUARE_ROOT = math.sqrt(2.0) / 2.0 local QUARTER_PI = math.pi / 4.0 local DPAD = { radius = 128, radiusSquared = 128 * 128, center = {x = 200, y = 250}, direction = nil, } function love.load() love.window.setTitle('Virtual D-Pad Example') love.mouse.setCursor(love.mouse.getSystemCursor('crosshair')) end function love.update(dt) local mx, my = love.mouse.getPosition() local mouseVectorX = mx - DPAD.center.x local mouseVectorY = my - DPAD.center.y local mouseVectorLengthSquared = (mouseVectorX * mouseVectorX + mouseVectorY * mouseVectorY) if mouseVectorLengthSquared > DPAD.radiusSquared then DPAD.direction = nil return end if mathAbs(mouseVectorX) > mathAbs(mouseVectorY) then -- Horizontal direction. DPAD.direction = mouseVectorX > 0.0 and 'right' or 'left' else -- Vertical direction. DPAD.direction = mouseVectorY > 0.0 and 'down' or 'up' end end function love.draw() if DPAD.direction then love.graphics.setColor(0.3, 0.75, 0.14, 0.3) else love.graphics.setColor(0.3, 0.75, 0.14, 0.1) end love.graphics.circle('fill', DPAD.center.x, DPAD.center.y, DPAD.radius, DPAD.radius) love.graphics.setLineWidth(1.0) love.graphics.setColor(0.5, 0.5, 0.5) local cornerOffset = DPAD.radius * HALF_SQUARE_ROOT love.graphics.line(DPAD.center.x - cornerOffset, DPAD.center.y - cornerOffset, DPAD.center.x + cornerOffset, DPAD.center.y + cornerOffset) love.graphics.line(DPAD.center.x + cornerOffset, DPAD.center.y - cornerOffset, DPAD.center.x - cornerOffset, DPAD.center.y + cornerOffset) love.graphics.setColor(1.0, 1.0, 0.0) local mx, my = love.mouse.getPosition() love.graphics.line(DPAD.center.x, DPAD.center.y, mx, my) love.graphics.setColor(1.0, 1.0, 1.0) love.graphics.print('- Hover the mouse on the virtual D-Pad.', 10, 10) love.graphics.print('- Press Esc to quit.', 10, 30) love.graphics.print('Mouse: ' .. mx .. ', ' .. my, 10, 50) if DPAD.direction then local angle1, angle2 if DPAD.direction == 'up' then angle1, angle2 = -QUARTER_PI, -QUARTER_PI * 3.0 elseif DPAD.direction == 'down' then angle1, angle2 = QUARTER_PI, QUARTER_PI * 3.0 elseif DPAD.direction == 'right' then angle1, angle2 = -QUARTER_PI, QUARTER_PI elseif DPAD.direction == 'left' then angle1, angle2 = QUARTER_PI * 3.0, QUARTER_PI * 5.0 end love.graphics.setColor(1.0, 1.0, 0.2, 0.5) love.graphics.arc('fill', DPAD.center.x, DPAD.center.y, DPAD.radius, angle1, angle2) love.graphics.setColor(1.0, 1.0, 1.0) love.graphics.print(DPAD.direction, DPAD.center.x - 20, DPAD.center.y + DPAD.radius + 10, 0.0, 2.0, 2.0) end love.graphics.setColor(0.3, 0.75, 0.14, 1.0) love.graphics.setLineWidth(3.0) love.graphics.circle('line', DPAD.center.x, DPAD.center.y, DPAD.radius, DPAD.radius) end function love.keypressed(key) if key == 'escape' then love.event.quit() end end
Re: Issues with triangle collisions
No problem bro
PS I take back what I said about "not drawing the circle". I guess it's a case by case basis. Some mobile apps draw virtual dpads all the time, and they look fine:
PS I take back what I said about "not drawing the circle". I guess it's a case by case basis. Some mobile apps draw virtual dpads all the time, and they look fine:
Re: Issues with triangle collisions
And about the diagonals, while you could do the dot product of the touch vector against the diagonal vectors and pick the biggest one, there's a cheaper way by getting the ratios (mouseVectorX / mouseVectorY) and (mouseVectorY / mouseVectorX).
If the absolute values of both of these ratios are above some number between 1.0 (when mvx == mvy) and 0.0 (when either mvx or mvy is zero), then the touch is happening in one of the four diagonal "zones" of the d-pad.
Then you can use the signs of mvx and mvy to tell which diagonal it is, that is, which of NE, NW, SE or SW the touch is happening at.
This graph shows these zones formed by the ratios of (mvx/mvy) and (mvy/mvx). Starting from a ratio limit of 0.6, adjust "r" to see how it looks with different limits:
https://www.desmos.com/calculator/jhbuk6ic7e
So you're going for something like:
If the absolute values of both of these ratios are above some number between 1.0 (when mvx == mvy) and 0.0 (when either mvx or mvy is zero), then the touch is happening in one of the four diagonal "zones" of the d-pad.
Then you can use the signs of mvx and mvy to tell which diagonal it is, that is, which of NE, NW, SE or SW the touch is happening at.
This graph shows these zones formed by the ratios of (mvx/mvy) and (mvy/mvx). Starting from a ratio limit of 0.6, adjust "r" to see how it looks with different limits:
https://www.desmos.com/calculator/jhbuk6ic7e
So you're going for something like:
Code: Select all
if mathAbs(mvx/mvy) >= limit and mathAbs(mvy/mvx) >= limit then
(Determine which of the four diagonals it is, using the signs of mvx and mvy)
else
(Not a diagonal, but the standard up,down,left,right directions like in the demo)
end
Re: Issues with triangle collisions
Actually the way that I did the diagonals is by getting the angle of the vector and just check if it is in the range that I am looking for this made it much more flexible I can change the diagonal offset pretty easily and I can even turn it into a joystick if I wantRNavega wrote: ↑Sun Jul 28, 2024 1:30 pm And about the diagonals, while you could do the dot product of the touch vector against the diagonal vectors and pick the biggest one, there's a cheaper way by getting the ratios (mouseVectorX / mouseVectorY) and (mouseVectorY / mouseVectorX).
If the absolute values of both of these ratios are above some number between 1.0 (when mvx == mvy) and 0.0 (when either mvx or mvy is zero), then the touch is happening in one of the four diagonal "zones" of the d-pad.
Then you can use the signs of mvx and mvy to tell which diagonal it is, that is, which of NE, NW, SE or SW the touch is happening at.
I used this equation in order to get the angle it's pretty janky do you think there's a better way to do it?
Code: Select all
if mouseVectorX < 0 then anglePlus = 180 else anglePlus = 0 end
vecAngle = (math.atan(mouseVectorY/mouseVectorX) * 180/math.pi) + anglePlus
Re: Issues with triangle collisions
Other than how it's creating a global (anglePlus), there's nothing wrong with your code, it's great.
I had never used Lua's math.atan() before, it's a bit confusing... I'm used to atan2().
Anyway, the top-right quadrant gives out a negative angle, so if you want a full 360º range I'd try this:
I had never used Lua's math.atan() before, it's a bit confusing... I'm used to atan2().
Anyway, the top-right quadrant gives out a negative angle, so if you want a full 360º range I'd try this:
Code: Select all
local RAD2DEG = 180.0 / math.pi
(...)
local anglePlus -- Making sure that anglePlus is a local.
if mouseVectorY > 0.0 then
anglePlus = mouseVectorX < 0.0 and 180.0 or 0.0
else
anglePlus = mouseVectorX < 0.0 and 180.0 or 360.0
end
local vecAngle = math.atan(mouseVectorY / mouseVectorX) * RAD2DEG + anglePlus
Re: Issues with triangle collisions
Yeah I realized after sending the response that atan2 exist wich was made specifically for what I was doing and there actually is a function in lua that is also specifically made for converting radiants to degrees so here's what I ended up using
The `*-1+90` was just to make it compatible with what I had before
Code: Select all
vecAngle = math.deg(math.atan2(mouseVectorX, mouseVectorY))*-1 + 90
Who is online
Users browsing this forum: Ahrefs [Bot], Google [Bot] and 7 guests