I am changing a texture upon an event trigger. At the moment the change is quite abrupt. I would like to make the transition so that the current texture fades out and the next texture fades in (using the _Glow parameter. Both transitions should happen over a period of 3 seconds.
So far I was able to make the fade in but it is for 12sec. Should I use two coroutines?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class VFXController : MonoBehaviour
{
private AssetBundle assetBundle;
private Texture texture;
private Texture nextTexture;
private Renderer renderer;
public GameObject visual;
private float currentGlowValue = 0.0f;
private float targetGlowValue = 12.6f;
private IEnumerator toggleTexture;
// Start is called before the first frame update
void Start()
{
assetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "session_vfx_textures"));
if (assetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
renderer = visual.GetComponent<Renderer>();
toggleTexture = ToggleTexture(12.6f);
InitEvents();
}
private void InitEvents()
{
EventsManager.current.onChangeVFXTexture += ChangeTexture;
}
private void OnDestroy()
{
EventsManager.current.onChangeVFXTexture -= ChangeTexture;
}
private void ChangeTexture(SessionNames name)
{
nextTexture = assetBundle.LoadAsset<Texture>(name.ToString());
StartCoroutine(toggleTexture);
}
IEnumerator ToggleTexture(float duration)
{
for (float t = 0f; t < duration; t += Time.deltaTime)
{
renderer.material.SetFloat("_Glow", currentGlowValue + t);
yield return null;
if (renderer.material.GetFloat("_Glow") >= 12.0f)
{
renderer.material.SetTexture("_MainTex", nextTexture);
StopCoroutine(toggleTexture);
}
}
}
}
Please check Range in the shader for _GLOW property. It might be set Range(0,15) or something. If you want to bring it upto 3 seconds then change range to _Glow ("Intensity", Range(0, 3)) = 1
For anyone wondering how to create a Fade in/out effect using a coroutine. Here is the solution.
IEnumerator Fade()
{
float elapsedTime = 0;
while (elapsedTime < transitionDuration)
{
currentGlowValue = Mathf.Lerp(13.0f, 0.0f, (elapsedTime / transitionDuration));
visual.GetComponent<Renderer>().material.SetFloat("_Glow", currentGlowValue);
elapsedTime += Time.deltaTime;
yield return null;
}
visual.GetComponent<Renderer>().material.SetTexture("_MainTex", nextTexture);
elapsedTime = 0;
while (elapsedTime < transitionDuration)
{
currentGlowValue = Mathf.Lerp(0.0f, 13.0f, (elapsedTime / transitionDuration));
visual.GetComponent<Renderer>().material.SetFloat("_Glow", currentGlowValue);
elapsedTime += Time.deltaTime;
yield return null;
}
}
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateWalls : MonoBehaviour
{
public GameObject gameObjectToRaise;
public float duration;
public Vector3 raiseAmount;
public bool go = false;
public Color[] colors = new Color[4];
public bool randomColors = false;
private GameObject objtoraise;
private GameObject[] walls;
private bool scaleOver = false;
private void Start()
{
Init();
ColorWalls();
// The z Axis must be minimum 1 or any value above 0 could be also 0.1f
// but it's better to keep it minimum as 1 by default.
if (raiseAmount.z < 1)
{
raiseAmount.z = 1f;
}
if (go)
{
StartCoroutine(ScaleOverSeconds(objtoraise, new Vector3(raiseAmount.x, raiseAmount.y,
raiseAmount.z), duration));
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
//if (scaleOver)
//{
if (objtoraise != null)
{
if (raiseAmount.z < 1)
{
raiseAmount.z = 1f;
}
Destroy(objtoraise);
Init();
ColorWalls();
StartCoroutine(ScaleOverSeconds(objtoraise, new Vector3(raiseAmount.x, raiseAmount.y,
raiseAmount.z), duration));
scaleOver = false;
//}
}
}
}
private void Init()
{
objtoraise = Instantiate(gameObjectToRaise);
objtoraise.name = "Walls";
walls = GameObject.FindGameObjectsWithTag("Wall");
}
public IEnumerator ScaleOverSeconds(GameObject objectToScale, Vector3 scaleTo, float seconds)
{
float elapsedTime = 0;
Vector3 startingScale = objectToScale.transform.localScale;
while (elapsedTime < seconds)
{
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
objectToScale.transform.localScale = scaleTo;
scaleOver = true;
}
private void ColorWalls()
{
for (int i = 0; i < walls.Length; i++)
{
if (randomColors)
{
walls[i].transform.GetChild(0).GetComponent<Renderer>().material.color
= GetRandomColour32();
}
else
{
walls[i].transform.GetChild(0).GetComponent<Renderer>().material.color = colors[i];
}
}
}
private Color32 GetRandomColour32()
{
//using Color32
return new Color32(
(byte)UnityEngine.Random.Range(0, 255), //Red
(byte)UnityEngine.Random.Range(0, 255), //Green
(byte)UnityEngine.Random.Range(0, 255), //Blue
255 //Alpha (transparency)
);
}
}
Inside the Update() when I press the R key it's destroying the Instantiated object and then Instantiate is again and start the coroutine again. The problem is when I press on the R key many times in a row after two times I'm getting MissingReferenceException exception in the editor :
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
GenerateWalls+d__12.MoveNext () (at Assets/Scripts/GenerateWalls.cs:81)
Line 81 is :
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
The goal is to be able to generate the walls each time over again when pressing R it should stop the current coroutine and start over.
Maybe the problem is that it's in the middle of the coroutine and because the old coroutine didn't stop yet then the object is missing in the middle because I destroy it?
How then I should do it to be able to press R over and over again and it will start the coroutine over and over? Not to start multiple coroutines but to start each time the coroutine over again.
The solution is to add : StopCoroutine In the Update()
This is not the solution. I thought stopping the coroutine will stop also the while loop inside but it didn't. It seems that checking for null inside the while loop solved the problem :
public IEnumerator ScaleOverSeconds(GameObject objectToScale, Vector3 scaleTo, float seconds)
{
if (objectToScale != null)
{
float elapsedTime = 0;
Vector3 startingScale = objectToScale.transform.localScale;
while (elapsedTime < seconds)
{
if (objectToScale == null)
{
yield return null;
}
else
{
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
}
objectToScale.transform.localScale = scaleTo;
scaleOver = true;
}
}
using UnityEngine;
using UnityEditor;
using System.Collections;
public class LerpExample : MonoBehaviour
{
[Header("Animation-Curve")]
public AnimationCurve slideCurve;
public Transform finalPosition;
private Vector3 initialPosition;
public float time;
private void Awake()
{
initialPosition = transform.position;
}
private void Start()
{
StartCoroutine(MoveObject());
}
private void Update()
{
}
private IEnumerator MoveObject()
{
float i = 0;
float rate = 1 / time;
while (i < 1)
{
i += rate * Time.deltaTime;
transform.position = Vector3.Lerp(initialPosition, finalPosition.position, slideCurve.Evaluate(i));
yield return 0;
}
}
}
I'm using animation curves to make the transform start decreasing speed and then when getting close to the target to decrease the speed.
but I ant now to lerp without finalPosition position but with finalPosition as time.
for example, if I will set the time to 7 so the transform will start lerp from its position, and after 7 seconds where ever the transform is reached decrease down the speed back.
The target instead position will be time.
Now it start to slow down near the target after 7 seconds or in 7 seconds for example 7 seconds but I want that it will start to slow down in 7 seconds without a vector3 target just after 7 seconds slow down and stop.
I have this situation :
An object that starts moving by force with a rigidbody on the terrain.
While the object is moving I want the player to start moving too beside the object with the rigidbody.
The player should start moving slowly to max speed than when the other moving object near stops moving the player should slowly slow down to stop.
IN general, I used the SpeedUp and SlowDown methods but they were working fine when I wanted to do it when moving the player forward. The problem is that the parameter "Forward" will move the player only in the forward direction.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using FIMSpace.FLook;
public class Rolling : MonoBehaviour
{
public GameObject mainCam;
public CinemachineFreeLook freeLookCamGameplay;
public CinemachineFreeLook freeLookCamPickUp;
public Transform player;
public Transform crate;
public Transform cube;
public Animation anim;
public UnlockCrate unlockCrate;
public float timeToStopRolling;
public float speed;
public float waitBeforeSlowdown;
public float startDrag;
public float endDrag = 50;
public float rotationSpeed;
public static bool hasStopped = false;
private bool crateOpenOnce = false;
private bool alreadyRolling;
private Rigidbody rb;
private Quaternion defaultRotation;
private Animator animator;
private bool startSpeedUp = true;
public float lerpTimeMultiplicator = 0.25f;
private float timeElapsed = 0;
private float lerpDuration = 3f;
private float startValue = 1;
private float endValue = 0;
private float valueToLerp = 0;
private bool triggerOnce = false;
private void Start()
{
rb = GetComponent<Rigidbody>();
defaultRotation = rb.rotation;
animator = player.GetComponent<Animator>();
}
private void Update()
{
var distance = Vector3.Distance(crate.position, player.position);
if (distance < 1.7f && crateOpenOnce == false && unlockCrate.HasOpened())
{
rb.isKinematic = false;
crateOpenOnce = true;
}
if(crateOpenOnce && startSpeedUp)
{
StartCoroutine(SpeedUp());
StartCoroutine(WaitBeforeSlowdown());
startSpeedUp = false;
}
if(animator.GetFloat("Forward") == 0f && startSpeedUp == false &&
triggerOnce == false)
{
triggerOnce = true;
}
}
private IEnumerator Slowdown()
{
while(timeElapsed < lerpDuration)
{
timeElapsed += Time.deltaTime;
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
animator.SetFloat("Forward", valueToLerp);
// Yield here
yield return null;
}
}
private IEnumerator SpeedUp()
{
while(timeElapsed < lerpDuration)
{
timeElapsed += Time.deltaTime;
valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
animator.SetFloat("Forward", valueToLerp);
// Yield here
yield return null;
}
}
private IEnumerator WaitBeforeSlowdown()
{
yield return new WaitForSeconds(13f);
timeElapsed = 0;
StartCoroutine(Slowdown());
}
private void OnCollisionEnter(Collision collision)
{
//NOTE: In general you should go for Tags instead of the name
if (collision.gameObject.name == "Crate_0_0")
{
if (crateOpenOnce)
{
rb.drag = 0f;
// Directly start a routine here (if none is already running)
if (!alreadyRolling) StartCoroutine(RollingRoutine());
}
}
}
private void OnCollisionExit(Collision collision)
{
if (collision.gameObject.name == "Crate_0_0")
{
var brain = mainCam.GetComponent<CinemachineBrain>();
brain.m_DefaultBlend.m_Time = 1f;
freeLookCamGameplay.enabled = false;
freeLookCamPickUp.enabled = true;
}
}
private Vector3 GetRandomDirection()
{
var rnd = Random.insideUnitSphere;
rnd.y = 0;
return rnd.normalized;
}
private IEnumerator RollingRoutine()
{
// Just in case prevent concurrent routines
if (alreadyRolling) yield break;
// Block new routines from starting
alreadyRolling = true;
// Get the random direction for this routine
var rollDirection = GetRandomDirection();
// Roll for the given time within the FixedUpdate call
for (var timePassed = 0f; timePassed < timeToStopRolling; timePassed += Time.deltaTime)
{
// Wait until you are in FixedUpdate
// the code after this is now executed within FixedUpdate
yield return new WaitForFixedUpdate();
rb.AddForce(Vector3.right /*rollDirection*/ * speed * Time.deltaTime);
}
// Wait before slowing down
yield return new WaitForSeconds(waitBeforeSlowdown);
// Do slow down and rotate to default until both conditions are fulfilled
var dragLerpFactor = 0f;
// Store the original drag to reset it later
var defaultDrag = rb.drag;
while (!Mathf.Approximately(rb.velocity.sqrMagnitude, 0) || rb.rotation != defaultRotation)
{
// Again wait until you are in FixedUpdate
yield return new WaitForFixedUpdate();
dragLerpFactor += Time.deltaTime * lerpTimeMultiplicator;
rb.drag = Mathf.Lerp(startDrag, endDrag, dragLerpFactor);
rb.MoveRotation(Quaternion.RotateTowards(rb.rotation, defaultRotation, rotationSpeed * Time.deltaTime));
}
// Just to be sure to end with clean value assign once
rb.rotation = defaultRotation;
rb.drag = defaultDrag;
rb.velocity = Vector3.zero;
hasStopped = true;
Destroy(transform.GetComponent<Rigidbody>());
Destroy(transform.GetComponent<SphereCollider>());
}
}
That is why I'm trying to use the code in the LerpExample script.
The main goal is to move the player slowly to max speed and then slowly to stop beside the rolling t transform in the Rolling script.
So I've been making a small game to do with Snake, and I'm struggling as to how I can make the Snake's Body appear and follow the position of the head whenever the snake's head touches the apple. I've managed to get the Snake's body to spawn but I can't get it to follow the head correctly. Can anyone help me and tell me how I can do this? Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Snake_Move : MonoBehaviour
{
// variables
public Vector2 pos;
private Vector2 moveDirection;
private float moveTimer;
private float timerSeconds;
//Function which runs once when the program starts
void Start()
{
timerSeconds = 0.0167f;
moveTimer = timerSeconds;
moveDirection = new Vector2(0.1f, 0);
}
//Function which updates itself based on your refresh rate
public void Update()
{
AutoMove();
ChangeDirection();
transform.position = new Vector2(pos.x, pos.y);
transform.eulerAngles = new Vector3(0, 0, AngleCalculator(moveDirection) - 90);
}
//Moves the snake 60 units each second
private void AutoMove()
{
moveTimer += Time.deltaTime;
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
}
}
//Changes direction of the snake based on arrow key pressed
private void ChangeDirection()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
if (moveDirection.y != -0.1f)
{
moveDirection.x = 0;
moveDirection.y = 0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
if (moveDirection.y != 0.1f)
{
moveDirection.x = 0;
moveDirection.y = -0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
if (moveDirection.x != -0.1f)
{
moveDirection.y = 0;
moveDirection.x = 0.1f;
}
}
else if (Input.GetKeyDown(KeyCode.LeftArrow))
{
if (moveDirection.x != 0.1f)
{
moveDirection.y = 0;
moveDirection.x = -0.1f;
}
}
}
//Calculates the angle at which the snake is moving; used to calculate rotation of sprite
private float AngleCalculator(Vector2 direction)
{
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
return angle;
}
private void SnakeBodySprite()
{
GameObject snakeApple = GameObject.Find("SnakeApple");
Apple_RandomSpawn appleScript = snakeApple.GetComponent<Apple_RandomSpawn>();
//something here?????
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Apple_RandomSpawn : MonoBehaviour
{
private Vector2 foodPos;
void Start()
{
SpawnApple();
}
void Update()
{
transform.position = new Vector2(foodPos.x, foodPos.y);
SnakeAte();
}
public void SpawnApple()
{
foodPos = new Vector2(Random.Range(-17, 17), Random.Range(-9, 9));
}
public void SnakeAte()
{
GameObject snakeBody = GameObject.Find("SnakeBody");
GameObject snakeHead = GameObject.Find("SnakeHead");
Snake_Move snakeMove = snakeHead.GetComponent<Snake_Move>();
if (foodPos.x <= snakeMove.pos.x + 1 &&
foodPos.x >= snakeMove.pos.x - 1 &&
foodPos.y <= snakeMove.pos.y + 1 &&
foodPos.y >= snakeMove.pos.y -1)
{
SpawnApple();
Instantiate(snakeBody);
}
}
}
This is kind of a broad question, so it's hard to answer completely. The thought that comes to my mind is using a Queue of move Vectors for the head, and then applying those movements to the body. You would need a reference to the snake body object, and need to know how many movements the head is from the body. It looks like that might be 60 in your case.
I would add the Queue in this section:
Queue<Vector2> moveDirections = new Queue<Vector2>();
SnakeBody snakeBody; // Reference to 1st snake body element
float offset = 60; // ?
private void AutoMove()
{
moveTimer += Time.deltaTime;
// enqueue the most recent moveDirection
moveDirections.Enqueue(moveDirection);
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
// Get oldest moveDirection from the head to apply to the body
Vector2 bodyMovement = moveDirections.Dequeue();
snakeBody.transform.Translate(bodyMovement);
}
// If the queue count is greater than how far ahead the head should be from the
// first body element, remove one from queue.
if (moveDirections.Count > offset) {
moveDirections.Dequeue();
}
}
This would only work for the first body element, so you could add a script to each body element keeping track of its child body element. Position the child element with the same logic used above.
NOTE: I haven't tested this, I'm just trying to give a high-level overview of how to solve this problem.
The script is attached to empty gameobject :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwitchText : MonoBehaviour
{
public GameObject[] objectsTexts;
private bool isDisplaying = false;
private Vector3[] lastFwd;
private float curAngleX = 0;
private GameObject[] objectsWithText;
public void Init()
{
objectsWithText = GameObject.FindGameObjectsWithTag("ObjectToAddText");
lastFwd = new Vector3[objectsWithText.Length];
for(int i = 0; i < objectsWithText.Length; i++)
{
lastFwd[i] = objectsWithText[i].transform.forward;
}
}
private void Update()
{
if (isDisplaying == false)
{
StartCoroutine(UpdateDisplayPhrase(objectsWithText));//objectsTexts[i].name, objectsWithText[i].GetComponent<TextMesh>()));
}
}
private bool myApproximation(float a, float b, float tolerance)
{
return (Mathf.Abs(a - b) < tolerance);
}
private IEnumerator UpdateDisplayPhrase(GameObject[] objects)//string text, TextMesh t)
{
// block multiple calls
//if (isDisplaying) yield break;
isDisplaying = true;
for (int i = 0; i < objectsWithText.Length; i++)
{
var curFwd = objectsWithText[i].transform.forward;
// measure the angle rotated since last frame:
var ang = Vector3.Angle(curFwd, lastFwd[i]);
if (myApproximation(ang, 179f, 1f) == true)
{
var t = objectsWithText[i].GetComponent<TextMesh>();
var text = objectsTexts[i].name;
// you can simply yield IEnumerators so they are executed and at the same time
// wait until finished
yield return StartCoroutine(FadeTextTo(0, 0.6f, t));//FadeTextToZeroAlpha(1, t);
t.text = text;
// NOTE: you pass in 0
// -> DIVIDING BY 0 ?!
yield return StartCoroutine(FadeTextTo(1, 0.6f, t));//FadeTextToFullAlpha(0, t);
}
// when done reset the blocking flag
//isDisplaying = false;
}
}
public IEnumerator FadeTextTo(float targetAlpha, float maxDuration, TextMesh textMesh)
{
// more efficient to get both colors beforehand
var fromColor = textMesh.color;
var toColor = new Color(fromColor.r, fromColor.g, fromColor.b, targetAlpha);
// this is optional ofcourse but I like to do this in order to
// always have the same fading speed even if it is already slightly faded into one direction
var actualDuration = maxDuration * Mathf.Abs(fromColor.a - toColor.a);
var passedTime = 0f;
while (passedTime < actualDuration)
{
var lerpFactor = passedTime / actualDuration;
// now the huge advantage is that you can add ease-in and -out if you like e.g.
//lerpFactor = Mathf.SmoothStep(0, 1, lerpFactor);
textMesh.color = Color.Lerp(fromColor, toColor, lerpFactor);
// avoid overshooting
passedTime += Mathf.Min(Time.deltaTime, actualDuration - passedTime);
yield return null;
}
// just to be sure in the end always set it once
textMesh.color = toColor;
}
}
I'm calling the Init method in another script in the Start after adding text first time to the gameobjects.
Using a break point in the SwitchText script on the line :
StartCoroutine(UpdateDisplayPhrase(objectsWithText));
objectsWithText contain 3 objects also objectsTexts contain 3 objects.
The problem is that the objectsWithText not rotating yet bit in the Update it's starting the Coroutine already.
The main goal is to switch the text on the TextMesh objects to the names of the objects in objectsTexts.
This script rotate the objects :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public GameObject[] objectsToRotate;
public float duration = 5f;
private void OnMouseDown()
{
StartCoroutine(StartRotationOfObjects());
}
private IEnumerator StartRotationOfObjects()
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
// Random wait period before rotation starts
if (i == 0)
{
yield return new WaitForSeconds(0);
}
else
{
yield return new WaitForSeconds(Random.Range(0, 2f));
}
StartCoroutine(Rotates(objectsToRotate[i].transform, duration));
}
}
private IEnumerator Rotates(Transform objectToRotate, float duration)
{
Quaternion startRot = objectToRotate.rotation;
float t = 0.0f;
while (t < duration)
{
t += Time.deltaTime;
objectToRotate.rotation = startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up);
yield return null;
}
objectToRotate.rotation = startRot;
}
}
I have two lights components. First i'm finding both Lights and disable them.
Then I want to enable them when changing some object scale and using the object scaling duration time for the lights dim.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DimLights : MonoBehaviour
{
//Lights Change
public Light[] lightsToDim = null;
public float maxTime;
private GameObject[] myLights;
private float mEndTime = 0;
private float mStartTime = 0;
private void Start()
{
myLights = GameObject.FindGameObjectsWithTag("Light");
mStartTime = Time.time;
mEndTime = mStartTime + maxTime;
LightsState(false);
}
public void LightsState(bool state)
{
foreach (GameObject go in myLights)
{
go.GetComponent<Light>().enabled = state;
}
}
public void LightDim()
{
foreach (Light light in lightsToDim)
{
light.intensity = Mathf.InverseLerp(mStartTime, mEndTime, Time.time);
}
}
}
The second script is scaling some object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChangeScale : MonoBehaviour
{
//Scaling change
public GameObject objectToScale;
public float duration = 1f;
public Vector3 minSize;
public Vector3 maxSize;
private bool scaleUp = false;
private Coroutine scaleCoroutine;
//Colors change
public Color startColor;
public Color endColor;
public float colorDuration; // duration in seconds
private void Start()
{
startColor = GetComponent<Renderer>().material.color;
endColor = Color.green;
objectToScale.transform.localScale = minSize;
}
// Use this for initialization
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
//Flip the scale direction when F key is pressed
scaleUp = !scaleUp;
//Stop old coroutine
if (scaleCoroutine != null)
StopCoroutine(scaleCoroutine);
//Scale up
if (scaleUp)
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
scaleCoroutine = StartCoroutine(scaleOverTime(objectToScale, maxSize, duration));
}
//Scale Down
else
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
scaleCoroutine = StartCoroutine(scaleOverTime(objectToScale, minSize, duration));
}
}
if (Input.GetKeyDown(KeyCode.C))
{
StartCoroutine(ChangeColor());
}
}
IEnumerator scaleOverTime(GameObject targetObj, Vector3 toScale, float duration)
{
float counter = 0;
//Get the current scale of the object to be scaled
Vector3 startScaleSize = targetObj.transform.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
yield return null;
}
}
IEnumerator ChangeColor()
{
float t = 0;
while (t < colorDuration)
{
t += Time.deltaTime;
GetComponent<Renderer>().material.color = Color.Lerp(startColor, endColor, t / colorDuration);
yield return null;
}
}
}
In the second script the ChangeScale i want inside the scaleOverTime method to dim the light using the method LightDim in the DimLights script.
It's not that complicated. You change the scaleOverTime function to work on light by copying it making a new function from it. The only thing to change is the Vector3.Lerp function to Mathf.Lerp function and also targetObj.transform.localScale to targetObj.intensity.
A simple Light dim function:
IEnumerator dimLightOverTime(Light targetObj, float toIntensity, float duration)
{
float counter = 0;
//Get the current intensity of the Light
float startIntensity = targetObj.intensity;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.intensity = Mathf.Lerp(startIntensity, toIntensity, counter / duration);
yield return null;
}
}
Unfortunately, you are using an array so the function should be made to take an array:
IEnumerator dimLightOverTime(Light[] targetObj, float toIntensity, float duration)
{
float counter = 0;
//Get the current intensity of the Light
float[] startIntensity = new float[targetObj.Length];
for (int i = 0; i < targetObj.Length; i++)
{
startIntensity[i] = targetObj[i].intensity;
}
while (counter < duration)
{
counter += Time.deltaTime;
for (int i = 0; i < targetObj.Length; i++)
{
targetObj[i].intensity = Mathf.Lerp(startIntensity[i], toIntensity, counter / duration);
}
yield return null;
}
}
This prevents having to start new coroutine for each Light and saving some time.
The new Update function:
public Light[] lightsToDim = null;
private Coroutine lightCoroutine;
// Use this for initialization
void Update()
{
if (Input.GetKeyDown(KeyCode.F))
{
//Flip the scale direction when F key is pressed
scaleUp = !scaleUp;
//Stop old coroutine
if (scaleCoroutine != null)
StopCoroutine(scaleCoroutine);
if (lightCoroutine != null)
StopCoroutine(lightCoroutine);
//Scale up
if (scaleUp)
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
scaleCoroutine = StartCoroutine(scaleOverTime(objectToScale, maxSize, duration));
lightCoroutine = StartCoroutine(dimLightOverTime(lightsToDim, 1, duration)); ;
}
//Scale Down
else
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
scaleCoroutine = StartCoroutine(scaleOverTime(objectToScale, minSize, duration));
lightCoroutine = StartCoroutine(dimLightOverTime(lightsToDim, 0, duration)); ;
}
}
}
Notice the new variable "lightCoroutine". That's used to store the old coroutine just like we did for the scaleCoroutine.