I can’t name it, but I describe it and solve it using vectors and dot products.
Essentially you’re looking for the circle that’s closest to the axis-aligned vector pointing in a particular direction dictated by a button press.
As for how to go about solving it…
Consider each circle to consist of an x
coordinate, a y
coordinate and a radius
.
E.g.
struct Circle
{
float x;
float y;
float radius;
};
Now consider the concept of a vector to consist of an x
component and a y
component:
struct Vector
{
float x;
float y;
};
(If you don’t know much about vectors, see here.)
First, generate your button direction vector (which will always be an axis-aligned unit vector):
- If the right button is pressed, use
{ 1.0f, 0.0f }
- If the left button is pressed, use
{ -1.0f, 0.0f }
- If the up button is pressed, use
{ 0.0f, -1.0f }
- If the down button is pressed, use
{ 0.0f, 1.0f }
Iterate through all non-selected circles and generate the vectors between those circles and the selected circle by subtracting the position of the non-selected circle from the selected circle.
(There’s a good video about vector subtraction here.)
That gives you the vectors between the selected circle and the non-selected circles.
Now calculate the dot products between those vectors and the button direction vectors.
(For more information about the dot product, see here, or this video.)
Finally, figure out which dot product is the largest.
The circle that generated that dot product is the circle that you should move to.
Note that this will give odd results if the selected circle is already the leftmost/rightmost/upmost/bottomost circle.
That condition will have to be handled separately.
Also this will select the circle closest to the axis line,
which isn’t necessarily the closest circle in that direction.
If the closest circle is required, that would require a different approach.
E.g.
Circle circles[4]
{
// Define the circles
};
constexpr size_t circleCount = 4;
size_t selectedIndex = 0;
Vector getButtonDirection()
{
if(arduboy.justPressed(RIGHT_BUTTON))
return { 1.0f, 0.0f };
if(arduboy.justPressed(LEFT_BUTTON))
return { -1.0f, 0.0f };
if(arduboy.justPressed(UP_BUTTON))
return { 0.0f, -1.0f };
if(arduboy.justPressed(DOWN_BUTTON))
return { 0.0f, 1.0f };
return { 0.0f, 0.0f };
}
float dot(const Vector & left, const Vector & right)
{
return ((left.x * right.x) + (left.y * right.y));
}
size_t findNextPoint(const Vector & direction)
{
const Circle & selected = circles[selectedIndex];
size_t nextIndex = selectedIndex;
float maximumDot = -1.0f;
for(size_t index = 0; index < circleCount; ++index)
{
if(index == selectedIndex)
continue;
const Circle & circle = circles[index];
Vector vector { (circle.x - selected.x), (circle.y - selected.y) }:
float dotProduct = dot(direction, vector);
if(dotProduct > maximumDot)
{
maximumDot = dotProduct;
nextIndex = index;
}
}
return nextIndex;
}
void selectNextPoint()
{
Vector direction = getButtonDirection();
if((direction.x == 0) && (direction.y == 0))
return;
selectedIndex = findNextPoint(direction);
}
(Completely untested code. Might not work.)