Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Highlighting a sprite when mouse left clicks it  (Read 5356 times)

0 Members and 1 Guest are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Highlighting a sprite when mouse left clicks it
« on: May 31, 2015, 05:19:35 am »
So I've working code that can detect when the mouse has left clicked within the bounds of a sprite. For reference the method is below and works very well.

bool icon::hasMouseLeftClickedOnIcon(sf::Vector2f mousePosWhenLeftPressed)
{
    if (getIconSpriteBounds().contains(mousePosWhenLeftPressed))
    {
        // mouse is on sprite!
                return true;
    }
        else
        {
                return false;
        }
}
 

Now when this is true, I wanted the sprite to have a small outline in say bright yellow to show that this sprite is the one that has been selected. Initially I had planned to use outlines but then I realized that only shapes have a setOutlineThickness etc methods.

Now my sprite's texture is a small texture with a circle and a transparent background.
So then I tried creating a circle with the fill-colour, I set it's position to the sprites position. I draw the circle first and then the sprite on top of it. The circle's radius is just a little larger than the texture circle, so it get the appearance of an outline.

Code is simple as well.


sf::CircleShape circle(28);
circle.setFillColor(sf::Color::Yellow);
circle.setPosition(sprite.getPosition().x, sprite.getPosition().y);
gameWindow.draw(circle);
gameWindow.draw(sprite);

 

However I find that the circle is not always line up correctly. One side of the outline is not as thick/even as the other side etc. So I'm assuming that as the texture is rectangle with a transparent background, then the circle part of the texture doesn't quite sync up with the circle shape that I am drawing.

So I am wondering is there an easier way to achieve this functionality, i.e. create a small outline of a sprite/texture when it gets selected by the mouse.

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Highlighting a sprite when mouse left clicks it
« Reply #1 on: May 31, 2015, 07:11:51 am »
So I am wondering is there an easier way to achieve this functionality, i.e. create a small outline of a sprite/texture when it gets selected by the mouse.
The simplest way would be to simply have two versions of your sprite pre-drawn, one with outline and one without. Then just draw the right one.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Highlighting a sprite when mouse left clicks it
« Reply #2 on: May 31, 2015, 09:28:50 pm »
I agree with Jesper's solution for sprites - two sprites: one highlighted, the other not highlighted.

However, a couple of points on your post.

1) Does the misalignment look something like this:

If so, it's because you're setting the top-left corners of both circles to the same position when you're trying to align them. You'll need to adjust for that extra size or just set the origins to the circles' centres.
The circles with their bounding boxes:


2) You're right that sprite doesn't have outlines but shapes do but if you're sprite is just showing a circle, you can use sf::CircleShape. Just to be clear, you can texture shapes (including circles) too. You could then use the outline with that.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Highlighting a sprite when mouse left clicks it
« Reply #3 on: June 02, 2015, 06:19:52 am »
Ok thanks Jesper and Hapax. Yeah 2 sprites/images is probably the easier option but I was hoping for a solution within SFML itself. Mostly due to the fact I struggle with GIMP. I would have 30 such icons/images to double up on - so 60 images in total. :) I was trying to have 1 highlight image, but then I get the same alignment issue anyway.

1) Does the misalignment look something like this:


Yes the alignment is exactly like this. I have done a little bit of tinkering where I minus the circle's x and y position by a few pixels...however it is never exact, requiring a lot of trial and error.

If so, it's because you're setting the top-left corners of both circles to the same position when you're trying to align them. You'll need to adjust for that extra size or just set the origins to the circles' centres.

Ok - I'm not sure I got the origin part above.

Do you mean?
- get the centre of the sprite using the local bounds method, i.e. x=width/2, y=height/2.
- Then create my circle which is slightly large radius that the sprite.
- Then I set the origin to centre of my sprite and set my position accordingly?
- Then draw the circle and sprite?


2) You're right that sprite doesn't have outlines but shapes do but if you're sprite is just showing a circle, you can use sf::CircleShape. Just to be clear, you can texture shapes (including circles) too. You could then use the outline with that.

This is an awesome suggestion. I don't know why I never tried this as it is clearly in the textures tutorial. It works quite well, except it looks like my textures are not perfect circles and there is a small transparent gap between my texture and the outline. Oh well - it still looks very nice and very easy to implement.

So thank you again - much appreciated.
« Last Edit: June 02, 2015, 06:27:19 am by starkhorn »

dabbertorres

  • Hero Member
  • *****
  • Posts: 506
    • View Profile
    • website/blog
Re: Highlighting a sprite when mouse left clicks it
« Reply #4 on: June 02, 2015, 07:41:03 am »
For highlighting, I modified the color of the sprite.

So, by default a Sprite's color is solid black (0, 0, 0, 255), right? I change the color to be (128, 128, 128, 255), and call that my "base" color. That's a pretty standard grey. So your sprite will be a bit lighter when drawn than when you made it in a paint program, so you'll want to take that into account. Then, when I want to make the sprite show as highlighted, I add to it's current color by a certain amount. For me, I found adding by (40, 40, 40, 0) to look decent. I called this value my "color change".

For example, for a Button class I made:
const sf::Color COLOR_CHANGE = {40, 40, 40, 0};
const sf::Color BASE_COLOR = {128, 128, 128};

Button::Button(...)
{
  sprite.setColor(BASE_COLOR);
}

// when I want it to be highlighted
sprite.setColor(BASE_COLOR + COLOR_CHANGE);

// "unhighlight" it
sprite.setColor(BASE_COLOR);

// on press
sprite.setColor(BASE_COLOR - COLOR_CHANGE);

// unpress
sprite.setColor(BASE_COLOR);
 

Work decent enough for my purposes at least. Just another suggestion. :)

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Highlighting a sprite when mouse left clicks it
« Reply #5 on: June 02, 2015, 10:20:55 am »
Hi DabberTorres,

Oh that is great idea - thank you for sharing.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Highlighting a sprite when mouse left clicks it
« Reply #6 on: June 03, 2015, 01:06:53 am »
by default a Sprite's color is solid black (0, 0, 0, 255), right?
No. The default colour for a sprite is solid white as a sprite's colour effectively filters the colours in the sprite's texture. White allows all of the texture through as is, and black changes all of the colours in the texture to black.


Ok - I'm not sure I got the origin part above.

Do you mean?
- get the centre of the sprite using the local bounds method, i.e. x=width/2, y=height/2.
- Then create my circle which is slightly large radius that the sprite.
- Then I set the origin to centre of my sprite and set my position accordingly?
- Then draw the circle and sprite?
Sort of but not exactly.
Basically, to set the origin of the circle to its centre:
circle.setOrigin(circle.getRadius(), circle.getRadius());
You'd then need to just update its position to match whatever the centre of the sprite is.
Although it might be easier to set the origin of the sprite to its centre as well as the origin of the circle to its centre. That way, you can set both positions identically. You may need to alter some of your original positioning but, since the sprite is a circle, it's likely that positioning using its centre may actually be more simple.
Then draw circle and sprite :)
(The origin is whereabouts on the object is placed at the position you specify with setPosition)


It works quite well, except it looks like my textures are not perfect circles and there is a small transparent gap between my texture and the outline.
One option is to stretch the texture slightly past the edge to cut off the anti-aliased part of the sprite's circle.
You can do this by setting the texture coordinates to be a pixel or two from the edge of the texture.
It could look something like this:
const int amountToTrim = 1; // number of pixels to remove from the edge
sf::IntRect trimmedTextureRect = sprite.getTextureRect();
trimmedTextureRect.width -= amountToTrim * 2;
trimmedTextureRect.height -= amountToTrim * 2;
trimmedTextureRect.left += amountToTrim;
trimmedTextureRect.top += amountToTrim;
sprite.setTextureRect(trimmedTextureRect);
(only do this once)


1) Does the misalignment look something like this:
[image]
Yes the alignment is exactly like this. I have done a little bit of tinkering where I minus the circle's x and y position by a few pixels...however it is never exact, requiring a lot of trial and error.
The amount to subtract from the circle's x and y should be:
// semi-pseudo code
circleX -= circleRadius - (spriteWidth / 2)
circleY -= circleRadius - (spriteHeight / 2)
so, to position the circle you could use something like this:
circle.setPosition(sf::Vector2f(
    sprite.getPosition().x - (circle.getRadius() - (sprite.getLocalBounds().width / 2.f)) // x
    sprite.getPosition().y - (circle.getRadius() - (sprite.getLocalBounds().height / 2.f)) // y
    );
but the quality of this positioning can depend on the accuracy of the sprite's circle within the texture.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

dabbertorres

  • Hero Member
  • *****
  • Posts: 506
    • View Profile
    • website/blog
Re: Highlighting a sprite when mouse left clicks it
« Reply #7 on: June 03, 2015, 02:47:35 am »
by default a Sprite's color is solid black (0, 0, 0, 255), right?
No. The default colour for a sprite is solid white as a sprite's colour effectively filters the colours in the sprite's texture. White allows all of the texture through as is, and black changes all of the colours in the texture to black.

Riiight... My bad.

Only difference really is that your texture will end up a bit darker than when you made it then. :)

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Highlighting a sprite when mouse left clicks it
« Reply #8 on: June 05, 2015, 01:49:50 am »
Hi Hapax,

Thank you so much for going into even further detail - much appreciated. I always struggled with the setorigin concept/method so this was really helpful in my understanding and implementation of it.

Anyway, setting the origin of the circle and the sprite to the centre worked perfectly so thank you.