0
\$\begingroup\$

I am making a 2D isometric game that uses the mouse. When I left click on an object, this object should be selected, but how do I determine what object that's currently selected and show a halo around it?

My objects are stored in a list of game objects as std::vector<Game_Object *> Object_Game. I am using the SDL library with C++. I did some research on Google but only found articles about Unity. Can someone help me with this?

\$\endgroup\$
  • \$\begingroup\$ Are you making a 2D- or a 3D game? \$\endgroup\$ – Daniel_1985 Nov 8 at 9:26
  • \$\begingroup\$ I am making a 2d game, it is type “isometric”. \$\endgroup\$ – Traistorm Nov 8 at 9:48
  • \$\begingroup\$ If your objects are inside a vector, can't you iterate through it and manually make collisions ? \$\endgroup\$ – TomTsagk Nov 8 at 12:54
  • 1
    \$\begingroup\$ Is your game tile-based? If so, you could find whatever isometric tile the mouse is pointing at and then determine whatever character / object is at that position. If not, you could always use the same technique by using a quadtree to keep track of characters / objects in your game and transform the isometric position to a position in the quadtree and find objects / characters at that position. \$\endgroup\$ – Darin Beaudreau Nov 8 at 13:00
0
\$\begingroup\$

Your use-case is two-fold:

  1. Projecting your 2d mouse coordinates to 3d world coordinates, to create a ray.
  2. Performing collision detection on the new coordinates, compared to your game objects.

NDC to 3D world coordinates

To do this, you need your view and projection transform matrices:

mat4 view = lookat(camPos, camPos+camDir, vec3(0.0f,1.0f,0.0f);
// For 3D
mat4 projection = perspective(fovAngle, aspectRatio, znear, zfar);
//for 2D
mat4 projection = ortho(0, width, height, 0);

combine these matrices using affine transformations:

mat4 worldToScreen = projection * view;

then invert them:

mat4 screenToWorld = inverse(worldToScreen);

Now, we take our mouse coordinates, and transform into world coordinates:

vec3 worldMouse = screenToWorld * vec4(mouseX,mouseY,-1.0f,1.0f);

Then finally we create our ray:

vec3 ray = normalize(worldMouse - camPos);

Collision Detection

Now, we can iterate through a vector of game objects, to determine which one has been clicked on:

gameObject *selectedObject; = nullptr;
for (auto &gameobject: gameObjects)
{
    if (gameobject.collide(ray))
    {
        selectedObject = gameobject;
        break;
    }
}

Then you can have some rendering code that draws a halo on the ground at the targeted object position:

void render()
{
    if (selectedObject != nullptr)
    {
        selectedHalo.drawAt(selectedObject->getPosition());
    }
    // then draw your game objects as normal.
}

This technique is known as "3D picking". There are plenty of more detailed tutorials available, but I covered the basic gist of it.

\$\endgroup\$
  • \$\begingroup\$ This is what you'd do in 3D but the original poster indicated this is a 2D game. Can you recommend how to construct the corresponding matrices for a 2D isometric game? \$\endgroup\$ – amitp Nov 8 at 17:40
  • \$\begingroup\$ Oh, thank you very much ! \$\endgroup\$ – Traistorm Nov 9 at 0:28
  • \$\begingroup\$ @amitp The principle still stands for a 2d game: change the mouse coordinates from NDC space to world space, then perform collision detection. Also, isometric is not 2D, it is usually defined as 2.5D. That being said, I will extend my answer appropriately. \$\endgroup\$ – Ian Young Nov 9 at 12:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.