Cannot modify a value type return value of `UnityEngine.Material.color' for changing alpha of gameobject - unity3d

I'm having trouble with this, although this is just for improvement for my code I can make the gameobject change it's alpha I just want it simpler.
here is my code:
SpriteRenderer go;
Color colora;
float x = 0f;
void Start () {
go = GetComponent<SpriteRenderer> ();
}
// Update is called once per frame
void Update () {
colora = new Color(255f,255f,255f,.5f);
go.material.color.a = colora.a;
}
this is the error one. just to make this code simpler.

Color is a struct and it is valueType.
go.material.color // it will return a copy of Color
You have to make another instance of Color then assign back to go.material.color
go.material.color = new Color(255f,255f,255f,.5f);

Related

UNITY How do I change image position?

Below is a snippet of code thats running every update but when I log the local position of the image it still says 0,0,0 when it should be 10,10,10. What am I doing wrong??? Ultimately I am trying to understand how to programmatically move an image around on screen
public partial class MainCanvasSystem : SystemBase
{
protected override void OnUpdate()
{
if (MainGameObjectCanvas.Instance != null && SystemAPI.HasSingleton<MainEntityCanvas>())
{
Entity mainEntityCanvasEntity = SystemAPI.GetSingletonEntity<MainEntityCanvas>();
LocalToWorld targetLocalToWorld = SystemAPI.GetComponent<LocalToWorld>(mainEntityCanvasEntity);
Canvas canvas = MainGameObjectCanvas.Instance;
Image image = canvas.GetComponentInChildren<Image>();
var rect = image.GetComponent<RectTransform>();
rect.localScale.Set(10,10,10);
Debug.Log(rect.localPosition.x);
}
}
}
I think there is general misunderstanding here.
rect.localScale.Set(10,10,10);
does .. nothing!
Transform.localScale is a property and returns a COPY of a Vector3 struct.
You are calling Vector3.Set on it which replaces the values within that Vector3 copy, yes, but then you never actually apply it anywhere.
=> you need to actually set the property!
You rather would do e.g.
rect.locaScale = Vector3.one * 10;
or
rect.localScale = new Vector3(10,10,10);
However, this said, changing a localScale won't change the position at all. The RectTransform.anchoredPosition is probably rather the one to go with.

material.SetColor doesn't work PC/Android build

This script works as follows: when I raycast an object, it fades out.
Script works great in the Unity Play Mode.
But objects dont wanna fade out on PC/Android build. Just nothing happen, but raycast is detecting object (problem not in raycast)
I debugged Android/PC and script is going into SetMaterialProperties method
Standard material, default new project, default scene, simple capsule gameObject, nothing specific
Because of what could this be?
private IEnumerator FadeIn()
{
Color objectColor = GetComponent<MeshRenderer>().material.color;
while (objectColor.a < 1)
{
float fadeAmount = objectColor.a + (_fadeSpeed * Time.deltaTime);
objectColor = new Color(objectColor.r, objectColor.g, objectColor.b, fadeAmount);
SetMaterialProperties(objectColor);
yield return null;
}
}
private void SetMaterialProperties(Color color)
{
foreach (var material in _materials)
{
material.SetColor("_Color", color);
material.SetFloat("_Mode", 3);
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.EnableKeyword("_ALPHABLEND_ON");
material.renderQueue = 3000;
}
}

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

Unity3D: Setting AudioSource volume dynamically using AnimationCurve

Newcomer to Unity here. For this project, I am reading in an outside AnimationCurve, and attempting to use it to adjust the volume of my GameObject every frame in the Update function. I have found documentation on how to access the volume of my AudioSource GameObject component (this is working), but I can't figure out how to use my evaluated curve to update the volume.
Screencap with imported AnimationCurve and evaluated values
My cs script is included below. Sorry if it's a bit opaque. This is for a neuroscience experiment, so I need to carefully control the animation curves. It reads in times and values (stored in currentCurveData) used to add keyframes to the new AnimationCurve (curveThisTrl) in the SetAnimationFrames() function.
The key part is in Update(). The initial tone.volume is correct, so I know it's reading that property from the GameObject. I can also see the correct curve values coming through in the Debug Log every frame, so I know the curve evaluation is working. It's just not changing the volume property of the GameObject as I want it to.
Hopefully this is enough information to spot a problem, but if not I can try to provide a test AnimationCurve for reproducibility. Thanks in advance for any help.
public class AnimationControl : MonoBehaviour {
private DataController dataControllerRef;
private CurveDataSingleTrial currentCurveData;
private float initTime;
public AnimationCurve curveThisTrl;
AudioSource tone;
void Awake()
{
initTime = Time.time;
}
// Use this for initialization
void Start ()
{
// Get references to key objects in scene
dataControllerRef = FindObjectOfType<DataController>(); // Has values from JSON
tone = GetComponent<AudioSource>();
Debug.Log(tone.volume);
// query the DataController for the current curve data
currentCurveData = dataControllerRef.GetCurrentCurveData();
SetAnimationFrames();
}
void SetAnimationFrames()
{
int numKeyFrames = currentCurveData.keyframeTimes.Length;
for (int c = 0; c < numKeyFrames; c++)
{
curveThisTrl.AddKey(currentCurveData.keyframeTimes[c], currentCurveData.keyframeVals[c]);
}
}
// Update is called once per frame
void Update ()
{
float currTime = Time.time - initTime;
tone.volume = curveThisTrl.Evaluate(currTime);
Debug.Log(tone.volume);
}
}