Gib20055

Anybody know how to detect a mouse click on a sprite

I would guess you'd start off reading something like mouse.x and mouse.y and then iterating through all the coordinates of the sprite to see if the point clicked is in the sprites non-transparent pixels (slow)

or..

Is there a way to hit test the sprites region Since this is specifly a game dev kit, I would assume there would be a method in the sprite class part of the engine to handle this like I would in vb.net for a polygon region(InRegion), and not have to iterate through each non-transparent pixel. Is that in the sprite class for hit testing If not, why ...that's a standard thing for a game(hit testing/collision detection). Guess thats for a MS XNA developer to answer

Thanks!

Gib



Re: XNA Game Studio Express Detect mouse click on a sprite

Bill Reiss

Well there is probably an easier way, but I'm thinking you could store the mask in something other than a Texture2D which is easier to query (bits in a byte array or something similar, a 2D array of bools if it's not too big). Then you would just have to calculate the pixel coordinates based on any scaling (if applicable) and see if the mask bit is "on" there.




Re: XNA Game Studio Express Detect mouse click on a sprite

Bill Reiss

I forgot, there is also this tutorial on ZiggyWare which gets into per-pixel collision detection.

http://www.ziggyware.com/readarticle.php article_id=48






Re: XNA Game Studio Express Detect mouse click on a sprite

musicalglass

#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion
// Tutorials in plain English by Dillinger
namespace Tutorials.Xna.SpriteClickable
{
/// <summary> This is the main hype for your game </summary>
public class GameEngine : Microsoft.Xna.Framework.Game
{
public GameEngine()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}

/// <summary> Allows the game to perform any initialization it needs to ...</summary>
protected override void Initialize()
{
base.Initialize();
}

// Initialize Graphics Content
GraphicsDeviceManager graphics;
ContentManager content;
SpriteBatch spriteBatch;
Texture2D spriteTexture;
Color spriteColor;

// Declare a 2 space float variable for storing Sprite Vertical and Horizontal position ( X & Y )
Vector2 spritePosition = new Vector2(100f, 100f);

/// <summary> Load graphics content...</summary>
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// Load Sprite resources
spriteBatch = new SpriteBatch(this.graphics.GraphicsDevice);
spriteTexture = content.Load<Texture2D>(@"Resources\Images\sprite1");
spriteColor = Color.White;
}
}

/// <summary> Unload your graphics content...</summary>
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
{
content.Unload();
}
}

/// <summary> Update Game Logic ... </summary>
protected override void Update(GameTime gameTime)
{
UpdateMouse();

checkMouseClick();

if (leftMouseClicked == true) // Don't bother collision checking unless mouse is clicked
{
OnMouseOver(); // Check if mouse is inside texture area
if (MouseOverSprite == true)
{
PixelCheck(); // Check if individual pixel is non Alpha
if (PixelDetected == true) spriteColor = Color.Red;
}
} else spriteColor = Color.White;

base.Update(gameTime);
}

/// <summary> Clear Screen & Draw Game ... </summary>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Black);

// Draw Sprite
spriteBatch.Begin();
spriteBatch.Draw(spriteTexture, spritePosition, spriteColor);
spriteBatch.End();

base.Draw(gameTime);
}

// Mouse coordinates are initialized at 0, 0
Vector2 mousePosition = Vector2.Zero;
void UpdateMouse()
{
MouseState mouseState = Mouse.GetState();
IsMouseVisible = true; // Show the mouse cursor ( default is false )

// The mouse X and Y positions are returned relative to the top-left of the game window.
mousePosition.X = mouseState.X;
mousePosition.Y = mouseState.Y;

} // end UpdateMouse

bool MouseOverSprite = false;
void OnMouseOver()
{
if ((mousePosition.X >= spritePosition.X) && mousePosition.X <= (spritePosition.X + spriteTexture.Width) &&
mousePosition.Y >= spritePosition.Y && mousePosition.Y <= (spritePosition.Y + spriteTexture.Height))
MouseOverSprite = true;
else MouseOverSprite = false;
} // end OnMouseOver


bool PixelDetected = false;
Vector2 pixelPosition = Vector2.Zero;
uint[] PixelData = new uint[1]; // Delare an Array of 1 just to store data for one pixel
void PixelCheck()
{
// Get Mouse position relative to top left of Texture
pixelPosition = mousePosition - spritePosition;

// I know. I just checked this condition at OnMouseOver or we wouldn't be here
// but just to be sure the spot we're checking is within the bounds of the texture...
if (pixelPosition.X >= 0 && pixelPosition.X < spriteTexture.Width &&
pixelPosition.Y >= 0 && pixelPosition.Y < spriteTexture.Height)
{
// Get the Texture Data within the Rectangle coords, in this case a 1 X 1 rectangle
// Store the data in pixelData Array
spriteTexture.GetData<uint>(0, new Rectangle((int)pixelPosition.X, (int)pixelPosition.Y, (1), (1)), PixelData, 0, 1);

// Check if pixel in Array is non Alpha, give or take 20
if (((PixelData[0] & 0xFF000000) >> 24) > 20)
PixelDetected = true;
else PixelDetected = false;
}
} // end PixelCheck

bool leftMouseClicked = false;
void checkMouseClick()
{
MouseState mouseState = Mouse.GetState();
if (mouseState.LeftButton == ButtonState.Pressed)
leftMouseClicked = true;
else leftMouseClicked = false;
} // end checkMouseClick
}
}






Re: XNA Game Studio Express Detect mouse click on a sprite

Calvin Bell

Would it be easier to create a very very small bounding sphere that follows your mouse around or create a new bounding sphere when you click and see if the mouse bounding sphere intersects with any items in the screen

I wonder how small a bounding sphere can go





Re: XNA Game Studio Express Detect mouse click on a sprite

DanBrink

Couldn't you have a bounding box on the sprite and then check if the mouse's coordinates are inside the box

I'm new to this bounding box functions, so I'm not sure but that would be the most logical way I could think of.




Re: XNA Game Studio Express Detect mouse click on a sprite

conard

I like the idea of how you create a ray from the near plane to the far where the mouse was clicked. All you need is some objects that are intersectable to see what the ray intersects with. You can even create a plane that represents the near plane to know which object is closest.





Re: XNA Game Studio Express Detect mouse click on a sprite

musicalglass

"Couldn't you have a bounding box on the sprite and then check if the mouse's coordinates are inside the box "

I don't know, Dan. Maybe.
I was under the assumption that Bounding Box collision only detects collision between two rectangles. The mouse is not a rectangle, it is a Vector2.

I could be wrong.
If anybody thinks there is a more elegant way to do it, feel free to show me.

The real question is: why do I have to waste another day or two of my life writing my own class for something that should be built in
Like, don't people need to click on things in some games Cheeeez!






Re: XNA Game Studio Express Detect mouse click on a sprite

musicalglass

"I like the idea of how you create a ray from the near plane to the far where the mouse was clicked."

You're talking about the Microsoft example for clicking 3D objects, I assume.
This is a 2D example so there are no closer objects. Everything is identical.
To do that you would need to have a Z axis. You would still not need to cast a ray though for 2D, since all sprites are flat. You could simply determine which had the lowest Z