Implementing Mouse Lasso

I am toying around with a Boogaloopers clone (http://www.youtube.com/watch?v=zuaRi_fhdlQ).

I have a small problem with the lassoing.

Here's my current naive algorithm. The problem with this is that the player can swipe a U-shaped pattern with the mouse, and it is detected as a polygon, since the isPointInPolygon-method connects the first and last points together. I wonder if there's a simple way to fix this?

private void collisionDetection() {

Player p = Player.getPlayer();

Array<Beam> beams = p.getBeams();

if (beams.size < 3)
return;

for (int i = 0; i < beams.size; i++) {

Beam b1 = beams.get(i);

for (int k = i + 1; k < beams.size; k++) {

Beam b2 = beams.get(k);

// Don't do collision detection with adjacent beams
if (p.areConnected(b1, b2))
continue;

if (Intersector.intersectSegments(b1.getStart(), b1.getEnd(), b2.getStart(), b2.getEnd(), null)) {

Array<Vector2> path = p.getPath();
if (path.size < 3)
continue;

boolean destroyed = false;

// Destroy any monsters inside the polygon
for (int j = 0; j < entities.size; j++) {
Entity e = entities.get(j);

if (e instanceof Player)
continue;

if (Intersector.isPointInPolygon(path, e.getPosition())) {
destroyed = true;
e.destroy();
}
}

if (destroyed) {
SFX.play("sfx-destroy");
}

return;
}
}
}
}

• What do you want it to do? If the start and end don't cross then don't lasso?
– jzx
Jul 29, 2014 at 19:54

The problem is you need to close the loop, to make sure the lasso is complete (based on the behavior of the video).

You do that by testing if one of the segments intersect with another segment, thus closing the loop.

It might look something like this (note I don't use libgdx, so this is untested):

Array<Vector2> path = p.getPath();
// Look for an intersection point
for (int i=0; i<path.size-1; ++i)
{
for (int j=i+2; j<path.size-1; ++j)
{
Vector intersection;
if (Intersection.intersectSegments(path[i], path[i+1], path[j], path[j+1], intersection))
{
Array<Vector2> loop = new Array<Vector2>();

// Destroy any monsters inside the polygon
for (int j = 0; j < entities.size; j++)
// ....

// exit loop, restart path
}
}
}


What's happening there is we start at the beginning, and test each segment with subsequent segments in the path (note j starts at i+2). If there is an intersection, we've found a loop, so we use the returned intersection point and test for containment.

If you find that the intersection criteria is too restrictive, you can extend the first and last segment, so the loop doesn't have to be closed exactly. You can add an extra "fake" point at the beginning and other at the end, following the same direction of the segment at a configurable distance (see picture).

• I would I like to add that the outter loop should be left out and the inner loop performed whenever a line is added - this will allow instant feedback needed for lasso ingame. Jul 30, 2014 at 12:31
• Got it working just fine with this method. Thanks! Jul 30, 2014 at 14:21

If performance isnt a problem for you and you want simple solution, just draw a thick line and check color under your cursor. If at any point the color was equal to the line color, you know the polygon was closed.
This can be even improved by checking color of all pixels between last and current mouse position.
Other option would be to perform MANY line segment intersections.

• Unfortunately your solution doesn't work, you are asking for almost 100% closed polygon,if you check the video the game automatically closes the curve, your solution require the player to have pixel acuracy in closing the curve which almost doesn't work in real scenarios. Jul 30, 2014 at 0:34
• @concept3d read the improved version - simply read all pixels in between, if the line width is 2 or more pixels, there is now way to miss it. This solution may be naive, but 100% working for all shapes. Jul 30, 2014 at 10:02