Tweening the color of a GUI button that changes color when you click it

Hello! I am having an issue when it comes to tweening the color of an image button.

This function makes it so that the button given as the parameter will fade and get slightly bigger when your mouse enters it, and go back to normal when the mouse leaves.
I do this by storing the original color and size of the button in the beginning, then I have some functions to change the color and size of the button accordingly.

Everything works fine for a button that will never change colors, but the issue comes when the color of the button can change when I click on it.
Say for example I have a button that’s red, but turns green when you click on it.
What will happen is:

  1. My mouse will enter the button, making it turn a darker shade of red
  2. I click the button, making it turn green as intended
  3. My mouse leaves the button, and it turns back to red since that was stored as the original color

What can I do about this? Is there way of getting around it while still using most of what I have, or will I have to design the whole system differently?

My code is included below. I have it in a modulescript so I can use this for all the buttons in my game.

Main script:

function UIAnimations.SetUpButton(button : ImageButton)
	
	local originalColor = button.ImageColor3
	local originalSize = button.Size
	
	local FADEAMOUNT = 1.5
	local SCALE = 1.1
	local SPEED = .08

	local endSize = UDim2.new(
		originalSize.X.Scale*SCALE,
		0,
		originalSize.Y.Scale*SCALE,
		0
	)
	
	button.MouseEnter:Connect(function()
		TweenImageButtonColor(button, GetFadeColor(originalColor, FADEAMOUNT), SPEED)
		TweenButtonSize(button, endSize, Enum.EasingDirection.Out, SPEED)
	end)

	button.MouseLeave:Connect(function()
		TweenImageButtonColor(button, originalColor, SPEED)
		TweenButtonSize(button, originalSize, Enum.EasingDirection.In, SPEED)
	end)
end

Functions used:

-- Tweens color for image buttons
local function TweenImageButtonColor(button, color, speed)
	local goal = {ImageColor3 = color}
	local tweenInfo = TweenInfo.new(speed)
	local Tween = TweenService:Create(button, tweenInfo, goal)
	Tween:Play()
end


-- Tweens size for buttons
local function TweenButtonSize(button, size, direction, speed)
	button:TweenSize(
		size,
		Enum.EasingDirection.Out,
		Enum.EasingStyle.Sine,
		speed,
		true
	)
end


-- Returns darker shade of the given color
local function GetFadeColor(color : Color3, fade_amount)
	return Color3.new(
		color.R/fade_amount,
		color.G/fade_amount,
		color.B/fade_amount
	)
end
1 Like

Just use some bool variables.
make a variable named “isClicked”

local isClicked = false

And whenever the mouse is getting hovered on the image button check if isClicked value is false otherwise stop that function.

Example:

local btn = path.to.button
local color = Color3.fromRGB(255,0,0)

local isClicked = false
btn.MouseEnter:Connect(function()
   if isClicked then return end
   btn.ImageColor3 = color -- Replace it with tween
end)
btn.MouseLeave:Connect(function()
   if isClicked then return end
   btn.ImageColor3 = some_other_color
end)
btn.MouseButton1Click:Connect(function()
    if not isClicked then
        isClicked = true
        btn.ImageColor3 = Some_color
    end
end)
2 Likes

Thanks for the suggestion!
I’ll try it out tomorrow and see how it works.

1 Like

Actually, I should’ve specified, I also want this to work for buttons where the color can change back and forth, or even have more than 2 possible colors. This looks like once I click the button, I’ll be done with it, which isn’t exactly what I want.

1 Like

Instead of storing the “previous” color of the button, keep track of these things:

  • Base color of the button. Is it green or red?
  • Base size of the button.
  • Its hover state. Is the mouse over it or not?

A function should derive the new color of the button whenever any of these changes.

On MouseEnter, set hover state to hovered.
On MouseLeave, set hover state to not hovered.
On click, change the base color.

After any of these operations, update the button’s appearance based on what it should look like now.
On hover state changing to hovered, the button’s size increases and the color fades, so get the new size (baseSize * SCALE) and the new color (GetFadeColor(baseColor)) and tween to it.
On hover state changing to not hovered, the button returns to normal size and normal color, so tween to baseSize and baseColor.
On button click, the color changes, so tween the color to baseColor if it’s not hovered or GetFadeColor(baseColor) if it is hovered.

Actually, this can be made a lot less complicated by putting all of this in a single function to just update the button.
The function tweens to the correct size based on hover state and to the correct color based on hover state, and you just run this function after changing anything about the button.

Some actual code since it’s not hard for me:

function UIAnimations.SetUpButton(button : ImageButton)
	
	local buttonObject = {
		Button = button,
		Color = button.ImageColor3,
		Size = button.Size,
		Hover = false,
	}
	-- preferably, store all of these properties in the button's custom Attributes
	
	button.MouseEnter:Connect(function()
		buttonObject.Hover = true
		UIAnimations.UpdateButton(buttonObject)
	end)

	button.MouseLeave:Connect(function()
		buttonObject.Hover = false
		UIAnimations.UpdateButton(buttonObject)
	end)
	
	return buttonObject
end
-- after running this function, you need to hang on to the buttonObject and change properties in it.
-- this is why you should get rid of buttonObject and instead set Attributes of the button, because you don't need to pass around a table. your code doesn't seem to be equipped to handle passing around a table wrapping a button instead of the actual gui button

function UIAnimations.UpdateButton(buttonObject)
	local FADEAMOUNT = 1.5
	local SCALE = 1.1
	local SPEED = .08
	
	local button = buttonObject.Button
	
	if buttonObject.Hover then
		local endSize = UDim2.new(
			buttonObject.Size.X.Scale*SCALE,
			0,
			buttonObject.Size.Y.Scale*SCALE,
			0
		)
		TweenImageButtonColor(button, GetFadeColor(buttonObject.Color, FADEAMOUNT), SPEED)
		TweenButtonSize(button, endSize, Enum.EasingDirection.Out, SPEED)
		
	else
		TweenImageButtonColor(button, buttonObject.Color, SPEED)
		TweenButtonSize(button, buttonObject.Size, Enum.EasingDirection.In, SPEED)
	end
end

There’s still a lot to improve and this isn’t ideal code, but it’s a start.

1 Like