How to increase fog density over time in unity - c#

fairly new here.
I'm working on a game where I want my fog density to increase. I've succesfully done it, but i want it to increase over time, something like a few seconds or so.
Here is my script:
using UnityEngine;
public class FogScript : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
RenderSettings.fogDensity = 0.2f;
}
}
As you can see it's fairly simple. Just need to know how to increase the density over a few seconds instead of the moment it activates.

You can use a Coroutine. They are like temporary little Update methods and by default each frame the next iteration is executed.
// Adjust these via the Inspector in Unity
[SerializeField] private float targetDensity = 0.2f;
[Tooltip(2Fade duration in seconds")]
[SerializeField] private float fadeDuration = 1.0f;
private void OnTriggerEnter(Collider other)
{
// starts the FadeFog routine
StartCoroutine(FadeFog())
}
private IEnumerator FadeFog()
{
var timePassed = 0f;
while(timePassed <= fadeDuration)
{
// a factor from 0 to 1
var factor = timePassed / fadeDuration;
// linear interpolate between from and to with given factor
RenderSettings.fogDensity = Mathf.Lerp(0, targetDensity, factor);
// Let this frame be rendered and continue from here in the next frame
yield return null;
}
}
or since OnTriggerEnter itself may be an IEnumerator you can also directly use
private IEnumerator OnTriggerEnter(Collider other)
{
var timePassed = 0f;
while(timePassed <= fadeDuration)
{
var factor = timePassed / fadeDuration;
RenderSettings.fogDensity = Mathf.Lerp(0, targetDensity, factor);
yield return null;
}
}

void Update(){
fogD += Time.deltaTime * rateOfIncrease;
}

Related

How can I lerp a vector3 by time not by position?

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.

Quaternion.Lerp clock rotation

I am trying to rotate the hand of the clock on click, but nothing is actually happening, none of the arrows is actually moving so I probably did something wrong... any help would be much appreciated, thank you
script below
public class Clock : MonoBehaviour {
public GameObject minuteHand;
public GameObject hourHand;
private Quaternion targetRotation;
float speed = 0.1f;
void Start()
{
targetRotation = transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
minuteHand.transform.rotation = Quaternion.Lerp(minuteHand.transform.rotation, targetRotation, Time.deltaTime * speed);
}
} }
Your code is only executed exactly in one single frame when the mouse button goes down.
Also that is not how Lerp works. Lerp expects a factor between 0 and 1 and interpolates both values. If you multiply your speed (0.1) and the Time.deltaTime which for 60FPS has a value of about 1/60f = 0.017f you get a resulting factor of about 0.0017f => You will always stay pretty close to the first value
especially since additionally your targetRotation always equals the current transform.rotation!
I assume what you wanted is: Every click move the minute 6° ahead (360°/60 minutes = 6°/minute).
Once a full circle is done move the hour 30° ahead (360°/12 hours = 30°/hour)
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
// Store original orientations
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// First calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12)
{
hours = 0;
}
}
// Now update the rotations with the new time
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
minuteHand.transform.rotation = targetMinuteRotation;
hourHand.transform.rotation = targetHourRotation;
}
}
}
This would make the clock "jump" to the target rotations. If what you rather wanted is a smooth rotation (what I assume from the usage of Lerp) I would probably use a Coroutine for that:
public class Clock : MonoBehaviour
{
public GameObject minuteHand;
public GameObject hourHand;
float speed = 0.1f;
Quaternion originalRotationMinute;
Quaternion originalRotationHour;
int minutes;
int hours;
void Start()
{
originalRotationMinute = minuteHand.transform.rotation;
originalRotationHour = hourHand.transform.rotation;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// cancel the current routines
StopAllCoroutines();
// calculate the new time
minutes++;
if(minutes == 60)
{
minutes = 0;
hours++;
if(hours = 12) hours = 0;
}
// I'm assuming here you want to rotate around the Z axis
// if this is not the case change this according to your needs
var targetMinuteRotation = originalRotationMinute * Quaternion.Euler(0, 0, 6.0f * minutes);
var targetHourRotation = originalRotationHour * Quaternion.Euler(0, 0, 30.0f * hours);
// This time instead of directly setting the values start coroutines
// to rotate the hands smoothly according to the given speed
StartCoroutine (RotateTo(minuteHand, targetMinuteRotation));
StartCoroutine (RotateTo(hourHand, targetHourRotation));
}
}
// rotate the given object to the given target rotation
// according to the given speed
private IEnumerator RotateTo(GameObject obj, Quaternion targetRotation)
{
var targetTransform = obj.transform;
var current = targetTransform.rotation;
// I your are not rotating on the Z axis change this accordingly to your needs
var difference = targetRotation.eulerAngels.z - current.eulerAngles.z;
if(Mathf.Approximately(0, difference)) yield break;
var duration = difference / speed;
var timePassed = 0f;
while(timePassed <= duration)
{
var factor = timePassed / duration;
targetTransform.rotation = Quaternion.Lerp(current, targetRotation, factor);
timePassed += Time.deltaTime;
yield return null;
}
// t be sure set the final rotation once in the end
targetTransform.rotation = targetRotation;
}
}
Typed on smartphone but I hope the idea gets clear
For me only this works. You can't modify speed to make it even slower, but it looks fine (may be it will be helpful to someone)
float speed = 0.1f //how fast rotate
private void FixedUpdate()
{
nextRot = hour * -30;
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, nextRot), speed);
}

How to apply an Easing algorithm in Unity?

I want to move the Camera with a smooth motion so I am writing this script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraScroll : MonoBehaviour {
public GameObject targetCamera;
private bool isScrolling = false;
private Vector3 initialPosition;
private Vector3 scrollTarget;
private float scrollDuration;
private float scrollTick;
private float timeStartedScrolling;
#region Easing
float EasingInOutSine(float time, float start, float change, float duration) {
return -change/2 * (Mathf.Cos(Mathf.PI*time/duration) - 1) + start;
}
float EasingOutSine(float time, float start, float change, float duration) {
dynamic td = time/duration;
return change * Mathf.Sin(td * (Mathf.PI/2)) + start;
}
float EasingInOutBack(float time, float start, float change, float duration) {
float td2 = time/(duration/2.0f);
float s = 1.70158f;
if ((td2) < 1.0f) {
return change/2.0f*(td2*td2*(((s*(1.525f))+1.0f)*td2 - (s*(1.525f)))) + start;
} else {
return change/2.0f*((td2-2.0f)*(td2-2.0f)*(((s*(1.525f))+1.0f)*(td2-2.0f) + (s*(1.525f))) + 2) + start;
}
}
#endregion
void Start() {
if (targetCamera == null) {
targetCamera = GameObject.Find("Main Camera");
}
// Tests
//Scroll(new Vector3(4.0f, 0.0f, -10f), 2f); // seems to be working?
//Scroll(new Vector3(4.0f, 0.0f, -10f), 0.3f); // easing gets cut off
Scroll(new Vector3(4.0f, 0.0f, -10f), 1f); // easing gets cut off
}
void Update() {
if (isScrolling) {
scrollTick += Time.deltaTime;
float s = scrollTick / scrollDuration;
float timeSinceStarted = Time.time - timeStartedScrolling;
float percentageComplete = timeSinceStarted / scrollDuration;
if (percentageComplete > 1.0f) {
isScrolling = false;
Debug.Log("Scrolling ended");
} else {
// time, start, change, duration
var easing = EasingInOutSine(Time.time, 0, Mathf.Clamp01(Time.time*scrollDuration), scrollDuration);
targetCamera.transform.position = Vector3.Lerp(initialPosition, scrollTarget, easing);
}
}
}
void Scroll(Vector3 targetPosition, float duration) {
scrollDuration = duration;
scrollTarget = targetPosition;
initialPosition = targetCamera.transform.position;
timeStartedScrolling = Time.time;
isScrolling = true;
}
}
The problem is that the motion of the camera is cutoff and the easing is not applied properly if the duration is set to be 1 second or lower
I'd like the script to be able to use different easing algorithms in the future and play with deltaTime properly, I am not sure if I am doing it the right way
I think you just need a constant change.
With an increasing change the slow down effect of the easing will be overpowered by the exponential movement caused by the increasing change. This effect is most apparent in low duration movements because it will never reach the value ceiling slower so it will keep speeding up until the end.
Since your using your easing algorithm to output a percentage to throw into a lerp, you probably want to use a change of 1 so that the easing interpolates between 0 and 1.

Change light intensity back and forth over time

How can I change the light intensity value from 3.08 back to 1.0 after 2 seconds. I have comment in my code for additional info
public class Point_LightG : MonoBehaviour {
public Light point_light;
float timer;
// Use this for initialization
void Start () {
point_light = GetComponent<Light>();
}
// Update is called once per frame
void Update () {
timer -= Time.deltaTime;
lights();
}
public void lights()
{
if (timer <= 0)
{
point_light.intensity = Mathf.Lerp(1.0f, 3.08f, Time.time);
timer = 2f;
}
// so after my light intensity reach 3.08 I need it to gradually change back to 1.0 after 2 seconds.
}
}
To lerp between two values, just use the Mathf.PingPong with the Mathf.Lerp and provide a speed the lerp should happen at.
public Light point_light;
public float speed = 0.36f;
float intensity1 = 3.08f;
float intensity2 = 1.0f;
void Start()
{
point_light = GetComponent<Light>();
}
void Update()
{
//PingPong between 0 and 1
float time = Mathf.PingPong(Time.time * speed, 1);
point_light.intensity = Mathf.Lerp(intensity1, intensity2, time);
}
If you prefer to use a duration instead of a speed variable to control the light intensity then you that is better done with a coroutine function and just the Mathf.Lerp function with a simple timer. The lerp can then be done within x seconds.
IEnumerator LerpLightRepeat()
{
while (true)
{
//Lerp to intensity1
yield return LerpLight(point_light, intensity1, 2f);
//Lerp to intensity2
yield return LerpLight(point_light, intensity2, 2f);
}
}
IEnumerator LerpLight(Light targetLight, float toIntensity, float duration)
{
float currentIntensity = targetLight.intensity;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
targetLight.intensity = Mathf.Lerp(currentIntensity, toIntensity, counter / duration);
yield return null;
}
}
Usage
public Light point_light;
float intensity1 = 3.08f;
float intensity2 = 1.0f;
void Start()
{
point_light = GetComponent<Light>();
StartCoroutine(LerpLightRepeat());
}

Rotation script issues?

This script is called when the user release the mouse button:
float rot_duration = 3f;
float rot_speed = 1.8f;
Quaternion final_rot;
void Start()
{
cubeMesh = GameObject.FindWithTag("CubeMesh");
Vector3 initial_rot = transform.rotation.eulerAngles;
final_rot = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180));
}
public void Update()
{
if (Input.GetMouseButtonUp(0))
{
StartCoroutine (DelayRotate (0.1F));
}
}
IEnumerator DelayRotate(float waitTime)
{
yield return new WaitForSeconds (waitTime);
float rot_elapsedTime = 0.0F;
while (rot_elapsedTime < rot_duration) {
cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);
rot_elapsedTime += Time.deltaTime * rot_speed;
yield return null;
}
}
This script makes a GameObject rotate, 0.1 seconds after mouse button release. The problem is that it "flips" the GameObject quickly then starts rotating.
I believe it is flipping due to final_rot2 = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180)); (because of 180 value) What should I do instead?
I looked at code carefully and I was able to spot two mistakes.
1. The one mistake that is causing the problem is:
cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);
The guy above me said you should replace transform.rotation with cubeMesh.transform.rotation. That is close but wont work. What you are suppose to is to get the current position of the GameObject outside the while loop and store it somewhere, then you can use it later on inside the while loop. For example,
Quaternion currentLocation = cubeMesh.transform.rotation;
while(...){
cubeMesh.transform.rotation = Quaternion.Slerp (currentLocation, final_rot, rot_elapsedTime);
...Other codes
}
2. Another mistake I found is that it looks like you are trying to rotate the object within time because you have a variable called rot_duration.
If this is true then you failed when you did Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);.
If you want the object to rotate within rot_duration amount of time, change rot_elapsedTime to rot_elapsedTime / rot_duration. Also remove rot_speed as that will NOT work if you want to rotate over time.
If this is NOT what you are trying to do then the first mistake I found should fix your problem.
Your final Code should look like something below:
float rot_duration = 10f;
float rot_speed = 3f;
Quaternion final_rot;
GameObject cubeMesh;
void Start()
{
cubeMesh = GameObject.FindWithTag("CubeMesh");
Vector3 initial_rot = transform.rotation.eulerAngles;
final_rot = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180));
}
public void Update()
{
if (Input.GetMouseButtonUp(0))
{
StartCoroutine(Delay(1));
}
}
IEnumerator Delay(float waitTime)
{
yield return new WaitForSeconds(waitTime);
float rot_elapsedTime = 0.0F;
//Get the current rotation
Quaternion currentLocation = cubeMesh.transform.rotation;
while (rot_elapsedTime < rot_duration)
{
rot_elapsedTime += Time.deltaTime;
cubeMesh.transform.rotation = Quaternion.Slerp(currentLocation, final_rot, rot_elapsedTime / rot_duration);
yield return null;
}
}
The problem here is that this doesn't update for each frame. I see that you add Time.deltaTime, but it doesn't update per frame, it only uses the value for the current frame several times, since you do everything in one update.
This code might work:
float rot_duration = 10f;
float rot_speed = 3f;
float rot_elapsedTime = 3f;
Quaternion final_rot;
public void Update()
{
if (Input.GetMouseButtonUp(0))
{
StartCoroutine (Delay (1));
}
if (rot_elapsedTime < rot_duration) {
cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);
rot_elapsedTime += Time.deltaTime * rot_speed;
}
IEnumerator Delay(float waitTime)
{
yield return new WaitForSeconds (waitTime);
rot_elapsedTime = 0.0F;
}
But as being said, transform.Rotate is probably better.
Edit: Updated after OP's edit with new code, adding a 1 sec delay.

Categories

Resources