Scalling an object in Unity - c#

I'm new in unity and in C# in general.
I was trying to make an animation with scale of a rectangle where it's getting bigger and smaller with time. I tried to use the statement transform.localScale but I didn't know how to make it with time, like a loop. So it gets big and small in a time frame of the 30s for example.
cube.transform.localScale = new Vector3(2.0f, 2.0f, 2.0f);

float TotalTime;
float Scale = 1;
GameObject Target;
// Start is called before the first frame update
void Start()
{
Target = this.gameObject;
}
// Update is called once per frame
void Update()
{
TotalTime += Time.deltaTime;
if (TotalTime < 30)
{
Scale += 0.01f;
Target.transform.localScale = Vector3.one * Scale;
}
}

Related

How to make object rotate around target with random height and with option to change the rotation radius?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateAroundTarget : MonoBehaviour
{
public Transform target;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.RotateAround(target.transform.position, new Vector3(0,1,0), 20 * Time.deltaTime);
transform.position = new Vector3(0,Random.Range(0,5f),0);
}
}
the RotateAround was working fine but once i added the Random.Range part the object is no just jumping very fast.
i guess i need somehow to add a delay between the random pickups ? but not sure how to make it smooth so the object will rotate around the target and from time to time randomly will change the height smooth up and down.
and how to add an option to change the rotation around the radius around the target?
tried the code above but it's still far away from what I wanted.
I tried using InvokeRepeating but then the transform is not rotating around anymore.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateAroundTarget : MonoBehaviour
{
public Transform target;
// Start is called before the first frame update
void Start()
{
InvokeRepeating("ChangePosition", 0, 2);
}
// Update is called once per frame
void Update()
{
transform.RotateAround(target.transform.position, new Vector3(0,1,0), 20 * Time.deltaTime);
}
private void ChangePosition()
{
transform.position = new Vector3(0, Random.Range(0, 5f), 0);
}
}
There are a couple issues with your code. First, setting the position with:
transform.position = new Vector3(0,Random.Range(0,5f),0);
will completely overwrite any X/Z change caused by the prior RotateAround. That's why your rotation stopped as soon as you introduced this code. To set the position without losing the X/Z values, you could use:
transform.position = new Vector3(
transform.position.x,
Random.Range(0,5f),
transform.position.z);
So now, the rotation works again. But the height changes are still erratic because your code is setting a new random height every frame. What can we do instead?
Let's try constraining the maximum height change to a certain speed, and only set a new height target when the previous one has been reached. So your code might look like:
public class RotateAroundTarget : MonoBehaviour
{
public Transform target;
public float verticalSpeed = 20;
public float radius = 10;
private float targetHeight;
// Start is called before the first frame update
void Start()
{
// Initialize with a height to start moving toward
targetHeight = GetNewTargetHeight();
// If we start at a given distance away from the target, then this
// will become our radius when we RotateAround it
transform.position = new Vector3(0, 0, radius);
}
// Update is called once per frame
void Update()
{
transform.RotateAround(target.transform.position,
new Vector3(0,1,0), 20 * Time.deltaTime);
// Just like your rotation rate, we scale this based on game time
float maxHeightChange = verticalSpeed * Time.deltaTime;
float targetHeightDelta = targetHeight - transform.position.y;
if (maxHeightChange >= Mathf.Abs(targetHeightDelta)){
// If the current height is close enough to the target, we can move it
// there and then generate a new height to go towards
transform.position = new Vector3(
transform.position.x,
targetHeight,
transform.position.z);
targetHeight = GetNewTargetHeight();
}
else{
// Otherwise, limit the magnitude of the height change by the speed and
// apply it to the current height
float allowedHeightChange = Mathf.Clamp(
targetHeightDelta,
-maxHeightChange,
maxHeightChange);
transform.position = new Vector3(
transform.position.x,
transform.position.y + allowedHeightChange,
transform.position.z);
}
}
private float GetNewTargetHeight()
{
return Random.Range(0,5f);
}
}

What is wrong with the AnimationCurve ? The lerp duration never change

I I set the lerp to 1 or to 10 the transform is moving to the target too fast.
At the top :
public AnimationCurve curve = AnimationCurve.Linear(0.0f, 0.0f, 1.0f, 1.0f);
public float duration = 10.0f;
private float t;
At Start()
void Start()
{
t = 0.0f;
}
At Update()
void Update()
{
switch (state)
{
case TransitionState.MovingTowards:
var v = targetTransform.position - transform.position;
if (v.magnitude < 0.001f)
{
state = TransitionState.Transferring;
originTransform = targetTransform;
timer = 0;
return;
}
t += Time.deltaTime;
float s = t / duration;
transform.position = Vector3.Lerp(transform.position,
targetTransform.position, curve.Evaluate(s));
break;
}
}
The curve animation in the editor :
You seem to lerp from Transform.Position to your TargetPosition. That means that everytime you move you lerp from a new starting position. This will make your object move exponantially. Try lerping from a fixed start position to a fixed end position. (Unless this is what you actually want to happen)
If I read your code correctly your duration is the exact duration in seconds that your lerp should take. So I assume that's correct, just fix the "start" position of your lerp.

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 gradually increase camera speed moving upwards in unity

I want to create a game in which the camera moves in the y-axis (upwards) with gradually increasing speed.
void Update () {
float translation = 0.5f;
transform.Translate (0, translation, 0);
I used this code, but I want to increase the rate of speed
One method would be to create a timer and increment the speed every time X amount of seconds has passed:
float translation = 0.5f;
float timer = 0f;
void Update()
{
timer += Time.deltaTime;
if (timer > 1f) //after 1 second has passed...
{
timer = 0; // reset timer
translation += 0.5f; //increase speed by 0.5
}
transform.Translate (0, translation, 0);
}
Functions like Vector3.Lerp(), Vector3.MoveTowards and Mathf.Lerp(), Mathf.MoveTowards() will help you do just that.
You can also multiply your translation by Time.deltaTime and control the speed by controlling the translation value.
public float BaseTranslationSpeed = 0.5f ;
public float TranslationSpeedIncreaseRate = 1 ;
private float translationSpeed ;
void Start()
{
translationSpeed = BaseTranslationSpeed ;
}
void Update ()
{
translationSpeed += TranslationSpeedIncreaseRate ;
// Multiplying by Time.deltaTime is advised in order to be frame independant
transform.Translate (0, translationSpeed * Time.deltaTime , 0);
}
You can even use an Animation curve to control the speed :
public AnimationCurve SpeedOverTime ; // Change the curve in the inspector
private float startTime ;
void Start()
{
startTime = Time.time ;
}
void Update ()
{
// Multiplying by Time.deltaTime is advised in order to be frame independant
transform.Translate (0, SpeedOverTime.Evaluate( Time.time - startTime ) * Time.deltaTime , 0);
}

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