Hello,
I have a custom inventory GUI where I am using buttons for each item. On each button is an image, such as:
(http://www.tom-simpson.com/Rope%20Cropped.png)
The issue being when I click
GUI.ProcessClick(mouse.x, mouse.y, eModeInteract);
or mouse over
(GUIControl.GetAtScreenXY(mouse.x, mouse.y);)
it takes into account the whole button, including the grey transparent area (unless I have another button on top z order wise)
Is there a way to ignore the transparent pixels?
I did search the forums and came across a couple of suggestions and wanted to know if these would be the route to go down, or if there's something better?
http://www.adventuregamestudio.co.uk/forums/index.php?topic=28882.msg367578#msg367578
http://www.adventuregamestudio.co.uk/forums/index.php?topic=44095.msg587336#msg587336 - I guess this one only works if the graphic is a certain shape
Thanks!
Yeah, AFAIK there's no built-in way. If you're using magic pink for transparency you could probably do a getpixel() on the sprite, but with alpha that gets more complicated.
The dummy character and pixel-perfect click detection hack is probably your best bet.
I did take a quick look at the GetPixel stuff. Am I right in thinking it would return the pixel colour of any buttons behind it on the transparent section? Edit: No, it's picking up the colours from the room background behind the GUI
In theory, if my inv items was made up of three (unique? does it matter if I'm doing the first btn check? and I know the button behind is 99% not going to match) colours, could I do something like...
if (theControl == btnHose) && ((surface.GetPixel(mouse.X, mouse.Y)) == COLOURA / COLOURB / COLOURC) //mouse is over button, and not a transparent pixel
lblHotspot.Text = "Hose";
} else {
// do nothing, since it's not over button / transparent pixel
}
(I know the operator bit isn't right)
I meant GetPixel() on the sprite itself, or rather, on its DrawingSurface. Copy the sprite to a DynamicSprite, get a DrawingSurface for it, and call GetPixel().
Right! I'm not very good with DrawingSurface etc. so I've given this a go, and it seems to work..
if (theControl == btnLunchbox) { //mouseover lunchbox inv item
DynamicSprite* sprite = DynamicSprite.CreateFromExistingSprite(1183, false); //store sprite of inv item with pink bg no transparancy
DrawingSurface *surface = Room.GetDrawingSurfaceForBackground(); //draw surface
surface.DrawImage(btnLunchbox.X, btnLunchbox.Y, sprite.Graphic); //draw inv item on surface
if (surface.GetPixel(mouse.x, mouse.y) == 63519) { //check if mouse is over pink transparency colour
btnLunchbox.NormalGraphic = 1125; // set normal version of inv item graphic
lblHotspot.Text = ""; // clear label
surface.Release();
sprite.Delete();
} else {
btnLunchbox.NormalGraphic = 1126; //mouse is over inv item, so set mouseover graphic
lblHotspot.Text = "Lunchbox"; //mouse is over inv iem, so set label
}
I'm also putting the btnLunchbox.NormalGraphic = 1125; when mouse is over no buttons
You got it. I'd personally refactor it as a standalone function taking the sprites you want to detect and the button versions as parameters,but you have the logic of it.
Broke something, will update!
Another thing you'll need to do is to calculate the x,y coordinates relative to the spite, not just use mouse.x/y. In practice this means you subtract (Button.X/Y + Button.OwningGUI.X/Y) from mouse.x/y.
Hm, how come I need to do that?
This is basically on the same code I posted earlier (in terms of anything mentioning mouse.x)
Oh, looking more closely at your code, you did it a little differently than I meant (by getting a drawingsurface for the background, which I think is a bad idea: here it looks like you're actually drawing the button sprite to the background, surely not the intention). Still, even with your approach it should only work at all if the GUI is full-screen (or at least, located at 0,0.
Yeah, I came across that earlier and 'fixed' it but I'm sure is bad but it's all I could get to work :p
I didn't realise what was happening at first, because I was testing on the Lunchbox inventory item, which is sat squarely on the bag gui button and hadn't turned the inventory off. Only when I started tested on the rope did I realise I was drawing on to the background. So, here's what I have at the moment. I tried a function as well (I'm not very good with either functions or drawingsurface, a lot of the manual stuff goes over my head).
function InvUpdate(Button *btnName, String description, int sprite_number_nontrans, int sprite_number_normal, int sprite_number_mouseover) {
DrawingSurface *backgroundCopy2;
DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
if (backgroundCopy2 == null) backgroundCopy2 = surface.CreateCopy(); // first time, create back-up copy of background
else surface.DrawSurface(backgroundCopy2); // restore previous background
DynamicSprite* sprite = DynamicSprite.CreateFromExistingSprite(sprite_number_nontrans, false); //store sprite of inv item with pink bg no transparancy
//DrawingSurface *surface = sprite.GetDrawingSurface(); // I tried using this at one point?
surface.DrawImage(btnName.X, btnName.Y, sprite.Graphic); //draw inv item on surface
if (surface.GetPixel(mouse.x, mouse.y) == 63519) { //check if mouse is over pink transparency colour
OverInv = false;
btnName.NormalGraphic = sprite_number_normal; // set normal version of inv item graphic
lblHotspot.Text = ""; // clear label
surface.Clear();
surface.DrawSurface(backgroundCopy2);
surface.Release();
sprite.Delete();
} else {
surface.Clear();
surface.DrawSurface(backgroundCopy2);
surface.Release();
sprite.Delete();
btnName.NormalGraphic = sprite_number_mouseover; //mouse is over inv item, so set mouseover graphic
lblHotspot.Text = description; //mouse is over inv iem, so set label
OverInv = true;
}
}
Which I call with
InvUpdate(btnRope, "Rope", 1184, 1129, 1130);
and yeah, my GUI is full screen.
Try this, man:
bool MouseOverPixelPerfect(this Button*, int mouseOverGraphic, String label)
{
// Calculate mouse coordinates relative to button sprite canvas
int x = mouse.x - this.X - this.OwningGUI.X;
int y = mouse.y - this.Y - this.OwningGUI.Y;
// Get the color on button sprite canvas at mouse cursor pixel
DynamicSprite* buttonMask = DynamicSprite.CreateFromExistingSprite(this.NormalGraphic, false);
DrawingSurface* maskSurface = buttonMask.GetDrawingSurface();
int pixelColor = maskSurface.GetPixel(x,y);
maskSurface.Release();
buttonMask.Delete();
if(pixelColor == COLOR_TRANSPARENT) // if this doesn't work then try your harcoded number, 63519
{
// Transparent, so don't highlight
this.MouseOverGraphic = this.NormalGraphic;
lblHotspot.Text = "";
return false;
}
// Otherwise, highlight
lblHotspot.Text = label;
this.MouseOverGraphic = mouseOverGraphic;
return true;
}
Call it like:
if (theControl == btnRope)
btnRope.MouseOverPixelPerfect(1130, "Rope");
Hey! That works just as well as mine ;)
Thanks a lot for your help Snarky - Solved!