Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

How can I detect clicks on a texture (which will be a button in my game) which has the form of a triangle or circle. I only know the rectangle solution which uses the position, width, and height; which won't work because clicks will be detected on transparent pixels.

I have heard of pixel-perfect collision, would that be the right way to do this?

It would be great if someone could give me a example for such a solution.

share|improve this question

3 Answers 3

up vote 9 down vote accepted

I wouldn't bother with pixel-perfect collision if you only need to detect clicks on triangles and circles.

For circles you can use a basic distance check from the center of the button.

if ( radius >= Math.sqrt( Math.pow( clickX - centerX, 2 ) + Math.pow( clickY - centerY, 2 ) ) )
    // we have been clicked

And for triangles you can use a point-in-triangle test. If you have a triangle with vertices A, B, and C:

/**
 * Return true if p1 and p2 are on the same side of BA
 */
public static boolean SameSide(Vector2 p1, Vector2 p2, Vector2 A, Vector2 B)
{
    // Convert points to Vector3 for use the Cross product, which is Vector3-only
    Vector3 cp1 = Vector3.Cross(new Vector3(B-A, 0), new Vector3(p1-A, 0));
    Vector3 cp2 = Vector3.Cross(new Vector3(B-A, 0), new Vector3(p2-A, 0));
    return Vector3.Dot(cp1, cp2) >= 0;
}

/**
 * Return true if the point p is in the triangle ABC
 */
public static boolean PointInTriangle(Vector2 p, Vector2 A, Vector2 B, Vector2 C)
{
    return SameSide(p,A, B,C) && SameSide(p,B, A,C) && SameSide(p,C, A,B);
}

There is also the Barycentric technique, which increases computational efficiency at the expense of clarity. XNA provides a Vector2.Barycentric method which can help alleviate that issue.

share|improve this answer

If you had extremely complicated shapes, using pixel testing might be a good way to go, but if you have just circles and triangles, you use different methods that will be faster to set up, and execute faster as well.

For a circle all you have to do is know the radius, and when the user clicks, call a method that calculates the distance between the center of the circle and the point where the user clicked, if that distance is lower than the radius, then the user has clicked the circle.

private static double GetDistance(PointF point1, PointF point2)
{
    //pythagoras theorem c^2 = a^2 + b^2
    //thus c = square root(a^2 + b^2)
    double a = (double)(point2.X - point1.X);
    double b = (double)(point2.Y - point1.Y);

    return Math.Sqrt(a * a + b * b);
}

Code via http://www.daniweb.com/software-development/csharp/code/217149

Triangles are a bit more complicated, but this page explains two different methods on how to accomplish it.

http://www.blackpawn.com/texts/pointinpoly/default.html

share|improve this answer

Well the circle is even easier than the rectangle actually, all you need to know is the radius and the centerpoint of the circle then you can do the hit testing in a way similar to the rectangle. The Triangle is much harder, for complex shapes sometimes what people will do is to create a bunch of bounding spheres or boxes and just do a hit test on all of those, where the hit is not perfect but an estimate, sometimes this is ok sometimes not.

There are algorithms for arbitrary polygons, which solves it for a very general case but assumes you have polygon data. You could possibly also scan every pixel in the texture and look at it's alpha value but I think you'll find that very slow for a lot of textures. So I think for the triangle what you want to do is to, in addition to the texture, keep track of the points of the triangle. If you do that you can do hittesting for that shape pretty easily.

I did something similar in javascript not long ago, except for polygons: Determine if two points are on the same side of a line in javascript

You could translate that algorithm to C# and assume 3 points instead of 6.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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