Where should I reset the timeElapsed? - c#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DetectCollision : MonoBehaviour
{
public Transform player;
public Transform target;
public bool turnOnOffPlayerAnimator = false;
float timeElapsed = 0;
float lerpDuration = 3;
float startValue = 1;
float endValue = 0;
float valueToLerp = 0;
private Animator playerAnimator;
private bool entered = false;
private bool resetElapsed = false;
// Start is called before the first frame update
void Start()
{
playerAnimator = player.GetComponent<Animator>();
if (turnOnOffPlayerAnimator)
playerAnimator.enabled = false;
}
// Update is called once per frame
void Update()
{
if (IsFacing(target))
{
if (entered)
{
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
}
}
else
{
if (valueToLerp < 0.9f)
{
if(resetElapsed == false)
{
timeElapsed = 0;
resetElapsed = true;
}
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
}
}
if(turnOnOffPlayerAnimator)
{
playerAnimator.enabled = false;
}
else
{
playerAnimator.enabled = true;
}
}
private void OnTriggerEnter(Collider other)
{
entered = true;
Debug.Log("Entered !");
}
private void OnTriggerExit(Collider other)
{
entered = false;
Debug.Log("Exited !");
}
private bool IsFacing(Transform target)
{
Vector3 forward = player.TransformDirection(Vector3.forward);
Vector3 toTarget = target.position - player.position;
return Vector3.Dot(forward, toTarget) > 0;
}
}
I reset it once back to value 0 in this part :
if(resetElapsed == false)
{
timeElapsed = 0;
resetElapsed = true;
}
but it also working only once.
I need somehow to reset the value to 0 each time the player is switching direction facing or not facing the target but not sure where and how to do it in the Update.
if not resetting it to 0 when the player will not facing the target or will face it after not facing again the value of timeElapsed is bigger then the lerpDuration value.

You could store the result of your IsFacing() method in a field and check in the next update run if it's has still the same value.
Simple example:
private bool prevFacing = false;
void Update() {
var currFacing = IsFacing(target);
if(currFacing != prevFacing) {
// here you switched from facing to not facing or vise verca.
}
prevFacing = currFacing;
}

Related

How can I stop row of moving images when one reaches a certain point? (Slot reels)

I am making a slot machine reel and I want my slots to stop at define point. I got the reel movement that looks nice but I am not sure how to stop it correctly. Currently I am compeering if image is at a define point but because it is moving it isn't exactly precise.
Here is my code:
private void Update()
{
if (canSpin)
SpinReall();
if ((Input.GetKeyDown(KeyCode.Space)))
{
if (!canSpin)
canSpin = true;
else
canStop = true;
}
}
public void SpinReall()
{
foreach (RectTransform slot in slots)
{
Vector3 newPoss = new Vector3(0, slot.localPosition.y - scrollSpeed);
slot.localPosition = newPoss;
if (slot.localPosition.y <= bottomBorder)
{
Vector3 currentPosition = slot.transform.localPosition;
currentPosition.y = slot.localPosition.y + offsetPosition;
slot.transform.localPosition = currentPosition;
}
if (canStop)
{
if (slots[stopIndex].transform.localPosition.y == stopPoss.localPosition.y)
{
canSpin = false;
canStop = false;
break;
}
}
}
}
How about considering using Mathf.Lerp ?
Using Lerp to move object will never move beyond the end value.
Example (move targetValue from 1f to 10f in 5 seconds)
float timeElapsed;
float lerpDuration = 5f;
float startValue = 1f;
float endValue = 10f;
float targetValue;
void Update()
{
if (timeElapsed < lerpDuration)
{
targetValue = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
timeElapsed += Time.deltaTime;
}
}
References:
https://docs.unity3d.com/ScriptReference/Mathf.Lerp.html
https://gamedevbeginner.com/the-right-way-to-lerp-in-unity-with-examples/

Why when pressing the b key the transform is moving backward but not in the same duration when moving forward?

For example the duration is set to 10 seconds. When the flag bool go is true the transform will move in 10 seconds to the target(destinationTransform). but when I press the b key in the middle while the transform is moving forward the transform start moving backward to the original position but not in 10 seconds but faster.
Is that because the distance is not the same as when it's moving forward ?
I'm trying to do that when i press the b key in the middle the transform will move backward but in the duration time no matter the distance. maybe i messed the lerp code in the backward state ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cinemachine;
public class MoveToTarget : MonoBehaviour
{
public enum TransitionState
{
None,
MovingTowards,
MovingBackward,
Transferring
}
public Transform destinationTransform;
public bool isChild = false;
public AnimationCurve curve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, 1.0f);
public float duration = 10.0f;
public bool go = false;
private float t;
private Transform originTransform;
private float timer;
private TransitionState state = TransitionState.MovingTowards;
private Vector3 originPosition;
private SphereCollider col;
private bool enableCollider = true;
private bool updateOriginPosition = true;
void Start()
{
t = 0.0f;
curve.postWrapMode = WrapMode.Once;
originPosition = transform.position;
col = GetComponent<SphereCollider>();
}
void Update()
{
if(Input.GetKeyDown(KeyCode.B))
{
t = 0.0f;
state = TransitionState.MovingBackward;
}
if (go)
{
if (updateOriginPosition == true)
{
originPosition = transform.position;
updateOriginPosition = false;
}
if (col != null && enableCollider)
{
//col.enabled = false;
//transform.GetComponent<Rigidbody>().isKinematic = true;
Destroy(col);
Destroy(transform.GetComponent<Rigidbody>());
//transform.GetComponent<InteractableItem>().enabledInteraction = false;
enableCollider = false;
}
switch (state)
{
case TransitionState.MovingTowards:
var v = destinationTransform.position - transform.position;
if (v.magnitude < 0.001f)
{
state = TransitionState.Transferring;
originTransform = destinationTransform;
timer = 0;
return;
}
t += Time.deltaTime;
float s = t / duration;
transform.position = Vector3.Lerp(originPosition,
destinationTransform.position, curve.Evaluate(s));
break;
case TransitionState.MovingBackward:
t += Time.deltaTime;
float s1 = t / duration;
transform.position = Vector3.Lerp(transform.position,
transform.parent.position,
curve.Evaluate(s1));
break;
case TransitionState.Transferring:
timer += Time.deltaTime;
this.transform.position = Vector3.Lerp(originTransform.position, destinationTransform.position, timer);
if (timer >= 1.0f)
{
this.transform.parent = destinationTransform;
transform.localPosition = new Vector3(0, 0, 0);
isChild = true;
go = false;
state = TransitionState.None;
this.enabled = false;
return;
}
break;
default:
this.enabled = false;
return;
}
}
}
}
The solution is first to update the originPosition in the Update when pressing the B key :
if(Input.GetKeyDown(KeyCode.B))
{
t = 0.0f;
originPosition = transform.position;
state = TransitionState.MovingBackward;
}
Then in the MovingBackward state to set the originPosition instead the transform.position.
case TransitionState.MovingBackward:
t += Time.deltaTime;
float s1 = t / duration;
transform.position = Vector3.Lerp(originPosition,
transform.parent.position,
curve.Evaluate(s1));
break;
The complete code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cinemachine;
public class MoveToTarget : MonoBehaviour
{
public enum TransitionState
{
None,
MovingTowards,
MovingBackward,
Transferring
}
public Transform destinationTransform;
public bool isChild = false;
public AnimationCurve curve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, 1.0f);
public float duration = 10.0f;
public bool go = false;
private float t;
private Transform originTransform;
private float timer;
private TransitionState state = TransitionState.MovingTowards;
private Vector3 originPosition;
private SphereCollider col;
private bool enableCollider = true;
private bool updateOriginPosition = true;
void Start()
{
t = 0.0f;
curve.postWrapMode = WrapMode.Once;
originPosition = transform.position;
col = GetComponent<SphereCollider>();
}
void Update()
{
if(Input.GetKeyDown(KeyCode.B))
{
t = 0.0f;
originPosition = transform.position;
state = TransitionState.MovingBackward;
}
if (go)
{
if (updateOriginPosition == true)
{
originPosition = transform.position;
updateOriginPosition = false;
}
if (col != null && enableCollider)
{
Destroy(col);
Destroy(transform.GetComponent<Rigidbody>());
enableCollider = false;
}
switch (state)
{
case TransitionState.MovingTowards:
var v = destinationTransform.position - transform.position;
if (v.magnitude < 0.001f)
{
state = TransitionState.Transferring;
originTransform = destinationTransform;
timer = 0;
return;
}
t += Time.deltaTime;
float s = t / duration;
transform.position = Vector3.Lerp(originPosition,
destinationTransform.position, curve.Evaluate(s));
break;
case TransitionState.MovingBackward:
t += Time.deltaTime;
float s1 = t / duration;
transform.position = Vector3.Lerp(originPosition,
transform.parent.position,
curve.Evaluate(s1));
break;
case TransitionState.Transferring:
timer += Time.deltaTime;
this.transform.position = Vector3.Lerp(originTransform.position, destinationTransform.position, timer);
if (timer >= 1.0f)
{
this.transform.parent = destinationTransform;
transform.localPosition = new Vector3(0, 0, 0);
isChild = true;
go = false;
state = TransitionState.None;
this.enabled = false;
return;
}
break;
default:
this.enabled = false;
return;
}
}
}
}

Coding smoother Shooting Recoil

So, I started following a tutorial and then added some other things that I needed and everything works fine, even the recoil, but the problem is that it is really choppy, it moves once a frame and it isn't smooth at all (which is what I want) I don't know a lot about programming so I hope you can help me :)
My code:
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Audio;
public class GunController : MonoBehaviour
{
[Header("Gun Setting")]
public float fireRate = 0.1f;
public int clipSize = 30;
public int reservedAmmoCapacity = 270;
//Variables that change throughout the code
bool canShoot;
int _currentAmmoInClip;
int _ammoInReserve;
//Muzzle Flash
public ParticleSystem muzzleFlash;
//Aiming
public Vector3 normalLocalPosition;
public Vector3 aimingLocalPosition;
public float aimSmoothing = 10;
[Header("Mouse Settings")]
public float mouseSensitivity = 1;
Vector2 _currentRotation;
public float weaponSwayAmount = 10;
//Weapon Recoil
public bool randomizeRecoil;
public Vector2 randomRecoilConstraints;
//You only need to assign if randomize recoil is off
public Vector2[] recoilPattern;
//Audio
AudioSource shootingSound;
//Reloading
public float reloadTime = 1.5f;
private void Start()
{
_currentAmmoInClip = clipSize;
_ammoInReserve = reservedAmmoCapacity;
canShoot = true;
shootingSound = GetComponent<AudioSource>();
}
private void Update()
{
DetermineAim();
DetermineRotation();
if (Input.GetMouseButton(0) && canShoot && _currentAmmoInClip > 0)
{
shootingSound.Play();
StartCoroutine(FinishShooting());
muzzleFlash.Play();
canShoot = false;
_currentAmmoInClip--;
StartCoroutine(ShootGun());
}
else if (Input.GetKeyDown(KeyCode.R) && _currentAmmoInClip < clipSize && _ammoInReserve > 0)
{
StartCoroutine(Reload());
}
}
void DetermineRotation()
{
Vector2 mouseAxis = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
mouseAxis *= mouseSensitivity;
_currentRotation += mouseAxis;
_currentRotation.y = Mathf.Clamp(_currentRotation.y, -90, 90);
transform.localPosition += (Vector3)mouseAxis * weaponSwayAmount / 1000;
transform.root.localRotation = Quaternion.AngleAxis(_currentRotation.x, Vector3.up);
transform.parent.localRotation = Quaternion.AngleAxis(-_currentRotation.y, Vector3.right);
}
void DetermineAim()
{
Vector3 target = normalLocalPosition;
if (Input.GetMouseButton(1)) target = aimingLocalPosition;
Vector3 desiredPosition = Vector3.Lerp(transform.localPosition, target, Time.deltaTime * aimSmoothing);
transform.localPosition = desiredPosition;
}
void DetermineRecoil()
{
transform.localPosition -= Vector3.forward * 0.1f;
if (randomizeRecoil)
{
float xRecoil = Random.Range(-randomRecoilConstraints.x, randomRecoilConstraints.x);
float yRecoil = Random.Range(-randomRecoilConstraints.y, randomRecoilConstraints.y);
Vector2 recoil = new Vector2(xRecoil, yRecoil);
_currentRotation += recoil;
}
else
{
int currentStep = clipSize + 1 - _currentAmmoInClip;
currentStep = Mathf.Clamp(currentStep, 0, recoilPattern.Length - 1);
_currentRotation += recoilPattern[currentStep];
}
}
IEnumerator ShootGun()
{
_currentAmmoInClip -= 1;
DetermineRecoil();
RayCastEnemy();
yield return new WaitForSeconds(fireRate);
canShoot = true;
}
void RayCastEnemy()
{
RaycastHit hit;
if (Physics.Raycast(transform.parent.position, transform.parent.forward, out hit, 1 << LayerMask.NameToLayer("Enemy")))
{
try
{
Debug.Log("Hit an enemy");
Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
rb.constraints = RigidbodyConstraints.None;
rb.AddForce(transform.parent.transform.forward * 50);
}
catch { }
}
}
IEnumerator FinishShooting()
{
yield return new WaitForSeconds(0.3f);
shootingSound.Stop();
}
IEnumerator Reload()
{
canShoot = false;
yield return new WaitForSeconds(reloadTime);
int amountNeeded = clipSize - _currentAmmoInClip;
if (amountNeeded > _ammoInReserve)
{
_currentAmmoInClip += _ammoInReserve;
_ammoInReserve -= amountNeeded;
canShoot = true;
}
else
{
canShoot = false;
_currentAmmoInClip = clipSize;
_ammoInReserve -= amountNeeded;
canShoot = true;
}
}
}
I don't see the function DetermineRecoil() called anywhere in the code, but maybe this solution will work:
let _currentRotation = Vector2.Lerp(_currentRotation, _currentRotation + recoilPattern[currentStep], 10*Time.deltaTime);
It will change the value of _currentRotation smoothly.

Stopwatch in c# (unity)

i'm making a door (similiar to the Doom 64's ones) and i have this code:
public class aperturaPorta : MonoBehaviour
{
public Transform playerCheck;
public Vector3 halfSize = new Vector3 (3f, 3f, 0.5f);
public LayerMask playerLayer;
bool playerEntering = false;
public BoxCollider collider;
public MeshRenderer renderer;
bool aprendo = false;
bool chiudendo = false;
public float openSpeed;
int counter = 1;
public int tick = 99;
// Update is called once per frame
void Update()
{
playerEntering = Physics.CheckBox(playerCheck.position, halfSize, Quaternion.identity, playerLayer, QueryTriggerInteraction.UseGlobal);
if (playerEntering && Input.GetButtonDown("e")) {
aprendo = true;
chiudendo = false;
}
if (counter == 100) {
chiudendo = true;
}
if (aprendo) {
transform.position += new Vector3 (0f, openSpeed, 0f);
counter += 1;
if (counter > tick) {
aprendo = false;
chiudendo = true;
}
}
if (chiudendo) {
transform.position -= new Vector3 (0f, openSpeed, 0f);
counter -= 1;
if (counter < 1) {
chiudendo = false;
}
}
}
}
This work but the door start closing when it finishes openening but it's too fast so i want to implement a two or three seconds stopwatch so that when it finishes the door start closing, how can i do it? thank you
ps: excuse me but i'm a newbie in unity
If I understand correctly you want a simple delay when the door is open before it closes? Keeping the same code structure you can add an other counter for that.
public float openSpeed;
int counter = 1;
public int tick = 99;
public int delayTicks = 100;
private int delayCounter = 0;
// Update is called once per frame
void Update()
{
playerEntering = Physics.CheckBox(playerCheck.position, halfSize, Quaternion.identity, playerLayer, QueryTriggerInteraction.UseGlobal);
if (playerEntering && Input.GetKeyDown(KeyCode.P))
{
aprendo = true;
chiudendo = false;
}
if (counter == 100)
{
chiudendo = true;
}
if (aprendo)
{
transform.position += new Vector3(0f, openSpeed, 0f);
counter += 1;
if (counter > tick)
{
delayCounter = delayTicks;
aprendo = false;
}
}
if (delayCounter > 0)
{
delayCounter--;
if (delayCounter <= 0)
{
chiudendo = true;
}
}
else if (chiudendo)
{
transform.position -= new Vector3(0f, openSpeed, 0f);
counter -= 1;
if (counter < 1)
{
chiudendo = false;
}
}
}

How can i dim a light component?

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.

Categories

Resources