Can't change button GUIStyle background in EditorWindow - unity3d

Unity version: 2019.4.1f1
I'm trying to change background of button in my EditorWindow. Trying to achieve effect pressed button in normal state:
void OnGUI() {
buttonStyleNormal = new GUIStyle(GUI.skin.button);
buttonStyleToggled = new GUIStyle(GUI.skin.button);
buttonStyleToggled.active.textColor = Color.blue;
buttonStyleToggled.normal = buttonStyleToggled.active;
...
GUILayout.Button("Developing", buttonStyleToggled);
GUILayout.Button("Compilation", buttonStyleNormal);
}
Result is here:
Problem stays even if I set background explicitly:
buttonStyleToggled.normal.background = buttonStyleToggled.active.background;
buttonStyleToggled.normal.scaledBackgrounds = buttonStyleToggled.active.scaledBackgrounds;

I don't see where you set the texture or color for the active state of the button.
Color activeButtonColor = new Color(0.3f, 0.3f, 0.3f, 1.0f);
buttonStyleToggled.active.background = activeButtonColor;

Related

Unity material.color.a code is not working

void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("tree"))
{
Color color = other.gameObject.GetComponent<Renderer>().material.color;
color.a = 0.5f;
}
}
If an object with a "tree" tag enters the camera's trigger, I want the opacity of that object to be 0.5. But didn't worked. How can i fix this? Thanks.
While the other two answers are technically correct, you are most likely missing a very important step to allow for the changing of the alpha of a Material. I'll take a guess and assume you generated a new Material in the Editor by using the Asset Creation Menu. By default, the Material RenderMode is set to Opaque.
To allow for changes of the Material color's alpha, you will need to set the RenderMode either to Transparent or Fade. If you are working with a custom shader, you will need to alter the code to format to one of the mentioned RenderTypes. If you need help modifying your shader, that would best be answered in a new question.
For clarity, here is a gif of what the confusion might be:
Edit: For completeness, here is a full script that will toggle the RenderMode of your material at runtime if you do not wish to change it at compile time.
using UnityEngine;
public static class MaterialUtils
{
public enum BlendMode
{
Opaque,
Cutout,
Fade,
Transparent
}
public static void SetupBlendMode(Material material, BlendMode blendMode)
{
switch (blendMode)
{
case BlendMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
material.SetFloat("_Mode", 3.0f);
break;
case BlendMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
material.SetFloat("_Mode", 0.0f);
break;
default:
Debug.LogWarning("Warning: BlendMode: " + blendMode + " is not yet implemented!");
break;
}
}
}
[RequireComponent(typeof(MeshRenderer))]
public class TestScript : MonoBehaviour
{
[SerializeField] private MeshRenderer mr = null;
[SerializeField] private float alphaChange = 0.5f;
private bool isOpaque = true;
private void Awake()
{
if (mr == null)
mr = GetComponent<MeshRenderer>();
}
private void OnMouseDown()
{
// store our color struct and change the alpha channel
Color clr = mr.material.color;
clr.a = alphaChange;
// instance our material to alter the rendermode
Material mat = mr.material;
// update our render mode to transparent and our color to the new alpha
MaterialUtils.SetupBlendMode(mat, isOpaque ? MaterialUtils.BlendMode.Transparent : MaterialUtils.BlendMode.Opaque);
mat.color = clr;
// apply our material change
mr.material = mat;
// toggle our bool
isOpaque = !isOpaque;
}
}
Your original question does not state whether or not you need to toggle the material back to opaque, but I included it. You can keep the RenderMode as Transparent and simply change the alpha back to 1.0f to make it fully opaque again. Again, here's a gif example of the above script in action:
To show that the snippet is working, I place 2 spheres behind the cubes. The snippet is probably a bit overkill for what you need, but if someone else stumbles on the question and needs a more versatile answer here it is!
Color is just a struct and basically just a container of values without further functionality. It is not linked to the Material it was taken from.
By assigning only
color.a = XY;
you do nothing yet.
You have to assign it back to the material!
void OnTriggerStay(Collider other)
{
if (!other.CompareTag("tree")) return;
var material = other.GetComponent<Renderer>().material;
var color = material.color;
color.a = 0.5f;
material.color = color;
}
You're not really setting the color with the code you wrote.
Color color = other.gameObject.GetComponent<Renderer>().material.color;
color.a = 0.5f;
With the first line you take the color from the object and with the second you set the opacity. But you don't assign it back to the object. You can assign the color back to the object and it should work:
other.gameObject.GetComponent<Renderer>().material.color = color;

Using CoRoutine Unity 3D Buttons

I'm currently making a quiz game that has three buttons, from an object pool, and I want them to turn green or red depending on whether or not they are the correct answer. This works perfectly.
When I add the coRoutine to change the button back to clear so the next question can be answered, the button almost never changes color after clicking and essentially nothing happens. Would really appreciate any help!! Thank you.
public void HandelClick()
{
var colors = GetComponent<Button> ().colors;
if( ! answerData.isCorrect)
{
colors.normalColor = Color.red;
GetComponent<Button>().colors = colors;
}
else
{
colors.normalColor = Color.green;
GetComponent<Button> ().colors = colors;
playerMovement.dodge();
}
StartCoroutine("Revert");
//gameController.AnswerButtonClicked(answerData.isCorrect);
}
IEnumerator Revert()
{
Debug.Log(" we are reverting " + Time.time);
yield return new WaitForSeconds(1.8f);
Debug.Log(" we are reverting again " + Time.time);
var colors = GetComponent<Button> ().colors;
colors.normalColor = Color.clear;
GetComponent<Button> ().colors = colors;
gameController.AnswerButtonClicked(answerData.isCorrect);
}
Changing the colors works as you said (you can see that in the Inspector of the Button)
The problem is that the Image component's color doesn't get updated automatically since the Button isn't receiving any pointer event like PointerDown, PointerExit etc => the new color is not applied to the Image (only in the cases where you do a new pointer event like enter, exit, up or down).
You could solve this by doing
GetComponent<Image>().color = colors.normalColor;
additional everywhere you change it.
Note: In general you should use GetComponent only once in Awake
private Button _button;
private Image _image;
private void Awake()
{
_button = GetComponent<Button>();
_image = GetComponent<Image>();
}
and than reuse the references _image and _button

Set a background to dynamically created list items in unity

I want to add a background to the prefab when it clicked as it should look as its selected I have added the click listener which is working but I'm not able to add a background
for (int i = 0; i < list.Count; i++) {
GameObject tempobj = Instantiate (amtPrefab);
listGameObject.Add(tempobj);
tempobj.GetComponent<Button>().onClick.AddListener(() =>
OnButtonClick(tempobj)
);
}
I'm using this code and I want to change the color in the OnButtonClick method that i'm passing the clicked object to
Thanks in advance for the help
Use Ui Button how you are doing currently and in your Background image of your prefab add your script to change the color.
Subscribe to the click event:
tempobj.GetComponent<Button> ().onClick.AddListener(() => OnButtonClick(tempobj));
And only need to call your delegate event OnButtonClick()
void OnButtonClick()
{
//change backgroung color code here
}

ImageJ: how to get Image inside GenericDialog to repaint?

In my ImageJ plugin I display a GenericDialog which has a bunch of images attached to it, like this:
// global:
ColorProcessor cp = new ColorProcessor(50, 50); // new ColorProcessor
ImagePlus ip;
public void run(ImageProcessor ip) {
GenericDialog gdiag = new GenericDialog("Foo"); // new Dialolg
gdiag.addDialogListener(this); // adding Listener
gdiag.addMessage("Lorem Ipsum"); // adding Message
gdiag.addSlider("Bar", 1, 360, 1); // adding Slider
Color c = new Color(r, g, b);
cp.setColor(tarColor);
cp.fill();
ip = new ImagePlus("fooimg", cp);
gdiag.addImage(ip);
gdiag.showDialog();
}
I keep a reference to the Colorprocessor and the ImagePlus. When the slider gets moved on the GenericDialog, my the dialogItemChanged() event fires. Here I change the Color on the Image:
public boolean dialogItemChanged(GenericDialog gd, AWTEvent event) {
float fooVal = (float) ((Scrollbar)(gd.getSliders().get(0))).getValue();
// calculating color based on fooVal ...
Color selColor = new Color(r, g, b);
cp.setColor(selColor);
cp.fill();
}
Now when I run this, the Color in the Image does not update. Only when I change the size of the dialog and move the border over the image, the color displays correctly.
How can I force the dialog to repaint?
I tried so many different updates & repaints, I am out of options.
Wayne Rasband added this capability in the 1.51b12 daily build of ImageJ; see his response on the ImageJ mailing list, where this question was cross-posted.

Is there any way to make some rectangular areas of a mask to be transparent?

I am using UGUI to make a Novice guide to guide people to play my game.
And need the whole UI be mask, but some rectangular areas to be lighted.
How to do?
Create a new gameobject and add a image component to it. Create a image with transparent areas where you want your ui to be visible. Assign that image to the image component. Then add a mask component
Put your other gui elements inside this gameobject so that is could overlap and hide everything except transparent areas. Here is the picture of demo setup.
IMHO, what you want to achieve is not easy to be done perfectly in Unity. Here is my personal solution:
I put a black panel below every other GUI, so that it darkens my entire screen.
I put an empty game object called BrightRoot below the panel, so that everything under BrightRoot will float over and "brightened".
In my tutorial script, I add function to look for a UI game object by name and change its parent to the BrightRoot. In example:
// To brighten the object
GameObject button = GameObject.Find("PlayButton");
Tansform oldParent = button.transform.parent;
button.transform.SetParent(BrightRoot, true);
// To darken it again
button.transform.SetParent(oldParent, true);
The perfect solution would be to write a UI shader that darken any pixel outside some rectangles and brighten the inside. Then set that shader to all UI objects.
Editted:
This just another easy method, using UI Vertex effect. Just need to implement IsPointInsideClipRect, put this component to your UI objects, and set the rectangles list:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
[AddComponentMenu("UI/Effects/Clip")]
public class Clip : BaseVertexEffect
{
// We need list of rectangles here - can be an array of RectTransform
public RectTransform[] ClipRects;
public override void ModifyVertices(List<UIVertex> vertexList)
{
if (!IsActive())
{
return;
}
bool isClipped = true;
for (int i = 0; i < count; i++)
{
UIVertex uiVertex = vertexList[i];
foreach (RectTransform rect in ClipRects)
{
if (IsPointInsideClipRect(rect, uiVertex.position))
{
isClipped = false;
break;
}
}
}
Color32 color = isClipped ? new Color32(0.5f, 0.5f, 0.5f, 0.5f) : new Color(1.0f, 1.0f, 1.0f, 1.0f);
for (int i = 0; i < count; i++)
{
UIVertex uiVertex = vertexList[i];
uiVertex.color = color;
}
}
private static bool IsPointInsideClipRect(RectTransform rect, Vector3 position)
{
// ...
}
}