I am looking for a way to create a text in Unity3D that looks like it slightly moves(without really changing position) like shaking text. I saw this in a game and it looks cool.
In other words I wants the text to move vertically some x values and back again to its position.
Doing this with coding not working for me, Here is what I did
Vector2 v = transform.position;
v += new Vector2(1f,1f);
transform.position = v;
not working. any suggestion?
I am not very familiar with animation in Unity, can I use animation to do this?
You need to use animation,
Animation will make the movement is smooth.
Create a animation for your text.
change your y at different time frame last frame make it 0. (Change y values to meet
your requirements) play hope this will work
you can watch the following video it might help if your not familiar with animations.
https://www.youtube.com/watch?v=_16b6Pl6cvM
Use coroutines.
public Text text;
void Start(){
StartCoroutine(ShakeText());
}
IEnumerator ShakeText(){
RectTransform rt = text.rectTransform;
Vector2 startPos = rt.anchoredPosition;
for(float t = 0; t <= 1; t += Time.deltaTime * 5){
rt.anchoredPosition = startPos + Vector2.up * t;
yield return null;
}
for(float t = 0; t <= 1; t += Time.deltaTime * 5){
rt.anchoredPosition = startPos + Vector2.up * (1 - t);
yield return null;
}
rt.anchoredPosition = startPos;
}
This is a simple example of moving the text up and down but it can help you understanding and implementing something more complex, mixing rotation, scaling, etc.
Related
So I was looking for ways to do smooth angle motion in Unity and I stumbled upon this clip of code:
IEnumerator SlideToPosition(Vector3 targetPos, float time)
{
// Use an animation curve to make it look sweet!
AnimationCurve smoothly = AnimationCurve.EaseInOut(0, 0, 1, 1);
Transform myTrans = transform; // cache the transform for extra efficiency!
float curTime = 0;
Vector3 startPosition = myTrans.position;
moving = true;
while (curTime < time)
{
myTrans.position = Vector3.Lerp(startPosition, targetPos, smoothly.Evaluate(curTime / time));
curTime += Time.deltaTime;
yield return null;
}
moving = false;
myTrans.position = targetPos;
}
This worked absolutely fantastically and I was looking for a way to do angled motion the same way as the poster of the original method (from 6 years ago) said it would be easy to do angular movement in the same way. I've tried everything and for the life of me can't seem to get it to rotate more than a degree or so. Can anyone help me out? Here is where I'm currently at:
IEnumerator rotateToPosition(Vector3 targetAngle, float time)
{
// Use an animation curve to make it look sweet!
AnimationCurve smoothly = AnimationCurve.EaseInOut(0, 0, 1, 1);
Transform myTrans = transform; // cache the transform for extra efficiency!
float curTime = 0;
Quaternion startAngle = myTrans.rotation;
moving = true;
while (curTime < time)
{
myTrans.rotation = Quaternion.Lerp(startAngle, Quaternion.Euler(targetAngle), smoothly.Evaluate(curTime / time));
curTime += Time.deltaTime;
yield return null;
}
moving = false;
myTrans.rotation = Quaternion.Euler(targetAngle);
}
Any help would be greatly appreciated. Thanks!
The last parameter of Lerp is the time component - this is a float value between 0 and 1 which you can think of as the percentage of movement between the start and finish. i.e. a value of 0.5f would be exactly half way between (in your example) startAngle and targetAngle.
So, just do curTimefor the last parameter, as you add to it each frame with curTime += Time.deltaTime this gradually moves between 0 and 1. If you want to vary the speed of the lerp then multiply this value e.g. to make it 50% faster use curTime += Time.deltaTime * 1.5f.
This question already has answers here:
Moving from one place to another over time (or rotating) in Unity
(2 answers)
Create a coroutine to fade out different types of object
(2 answers)
Closed 2 years ago.
I want to make the object change its position in a few seconds. For example, it will "reach" a point within 5 seconds.
Choose a position and reach it within a fixed number of time. It is possible? Does it have a function?
Lat example. My object is in (10f, 10f, 0) I want him to reach (20f, 10f, 0) in 2 seconds.
Is it possible?
Update: in scratch, for example it called "glide 10, 78. secs to 3" - moving to 10X, 78Y in 3 seconds
Unless you're 90 years old, just use a tweeng.
It's this easy
StartCoroutine(5f.Tweeng( (p)=>transform.position=p,
startHere,
endHere) );
it goes from startHere to endHere in 5 seconds.
That's all there is to it.
A tweeng extension is only a few lines of code, example: https://stackoverflow.com/a/37228628/294884
You can do anything with a tweeng, fade volume, twist objects, animate the size of type, fade images, whatever.
Every single large project you'll ever work on, they already use tweeng. It couldn't be simpler.
Use Vector3.Lerp inside a coroutine.
Vector3 beginPos = new Vector3(10f, 10f, 0);
Vector3 endPos = new Vector3(20f, 10f, 0);
float time = 2;
void Start(){
StartCoroutine(Move(beginPos, endPos, time));
}
IEnumerator Move(Vector3 beginPos, Vector3 endPos, float time){
for(float t = 0; t < 1; t += Time.deltaTime / time){
transform.position = Vector3.Lerp(beginPos, endPos, t);
yield return null;
}
}
Vector3.Lerp basically interpolates between two vectors:
Lerp(a, b, t) = (1-t)a + tb
Lerp(a, b, 0) = (1-0)a + 0b = a
Lerp(a, b, 0.5) = (1-0.5)a + 0.5b = 0.5a + 0.5b
Lerp(a, b, 1) = (1-1)a + 1b = b
To give you a general idea:
public class MoveToTarget : MonoBehaviour
{
public Transform target;
public float duration;
float distance;
float t;
private void Start()
{
distance = Vector3.Distance(transform.position, target.position);
}
private void Update()
{
transform.position = Vector3.MoveTowards(transform.position, target.position,
(distance/duration) * Time.deltaTime);
}
}
For sure!
There are a lot of ways to accomplish this in Unity.
I am going to assume that you are making a 3D experience and using RigidBody components.
FixedUpdate is a special method that Unity calls every 20ms - no matter what is going on with rendering, or performance - this is so you can do you physics simulations reliably and smoothly.
Remember the classic formula: rate * time = distance?
private void UpdateRigidBody()
{
Vector3 targetDestination = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime);
var rb = transform.GetComponent<Rigidbody>();
rb.MovePosition(destination);
}
Where speed is calculated and with destination set on the object (below).
In your case, you know the distance (destination - current position), and you know the time = 2 seconds.
Your unknown is the rate (speed).
Speed = distance / time.
So you will need some other function to setup the movement - like ChaseTarget?
private void ChaseTarget(Vector3 target, float timeToReach)
{
destination = target;
var distance = (destination - transform.position);
speed = distance / timeToReach;
}
So, somewhere in your game controls logic you would call ChaseTarget and give it a target (a Vector3) and a time to get there. You setup these member variables on your object (targetDestination and speed) and the UpdateRigidBody function will smoothly get you there.
Typically, when you are close enough to the target you do some sort of new game logic and then reset the target destination (inside of UpdateRigidBody:
var destXZ = destination;
var posXZ = transform.position;
var dir = destXZ - posXZ;
var arrived = dir.magnitude < arrivedRadiusMagnitude;
if (arrived) // If I have arrived
{
Arrived();
}
Where the arrivedRadiusMagnitude is a game design question of how close can something get before it is considered arrived? For example some sort of tracking missile might explode when it is near a target, not necessarily right on top of it.
Ok, so, i've been stuck on this for ages. Im working on an AI that will navigate a tank to a waypoint, defined as a Vector3. the position of the tank is also defines as a Vector3, both these have their Y position set to 0, as to ignore terrain elevation, the current rotation of the tank is also a Vector3, though only the Y rotation is needed, as i'm effectively projecting the 3d position onto a 2d navigational grid.
The AI passes anywhere between -1 and 1 into the control for the tank, which then handles the physics operations. so, i need to somehow calculate the angle, positive or negative in relation to the current heading angle of the tank to the position of the waypoint, then send the rotation value to the controls. At the moment I simply cant get it working, I feel like iv'e pretty much tried everything.
This is my code currently, it doesn't work, at all, and is about the 20th revision:
void driveToTarget()
{
Vector3 target0 = driveTarget;
target0.y = 0;
GameObject current0Obj = new GameObject();
Vector3 current0 = this.transform.position;
current0.y = 0;
print(current0);
print(target0);
Vector3 current0Angle = this.transform.eulerAngles;
print(current0Angle.y);
current0Angle.x = 0;
current0Angle.z = 0;
Vector3 heading = target0 - current0;
Quaternion headingAngle = Quaternion.LookRotation(heading);
print("headingAngle" + headingAngle);
print("heading direction, allegidly: " + Quaternion.Euler(heading).ToEulerAngles());
Quaternion distanceToGo = Quaternion.Lerp(Quaternion.Euler(current0Angle), headingAngle, 0.01f);
float angle = Vector3.SignedAngle(current0, target0, Vector3.up);
float difference = Mathf.Abs(angle - current0Angle.y);
print("heading angle " + angle);
if (current0 != driveTarget)
{
steeringVal = Mathf.Abs(1.5f-(1f/Mathf.Abs(distanceToGo.y))) * -Mathf.Sign(distanceToGo.y); ;
throttleVal = 0f;
} else
{
throttleVal = 0;
}
}
--EDIT--
So, I've partially solved it, and now encountered another problem, I've managded to get the tank to detect the angle between itself and the waypoint, BUT, rather than orienting forward towards the waypoint, the right side of the tank orients towards it, so it orbits the waypoint. I actually know why this is, becasue the forward vector of the tank is technically the right vector because of unity's stupid axis ruining my blender import, anyway, heres the updated code:
void driveToTarget()
{
Vector3 target0 = driveTarget;
target0.y = 0;
Vector3 current0 = this.transform.position;
current0.y = 0;
print("Current: " + current0);
print("Target: " + target0);
Vector3 current0Angle = this.transform.rotation.eulerAngles;
print("Curret rotation:" + current0Angle.y);
current0Angle.x = 0;
current0Angle.z = 0;
Vector3 heading = target0 - current0;
Quaternion headingAngle = Quaternion.LookRotation(heading);
print("heading angle: " + headingAngle.ToEuler());
float distanceToGo = (current0Angle.y) - headingAngle.eulerAngles.y;
print("DistanceToGo: " + distanceToGo);
if (current0 != driveTarget)
{
steeringVal = 1 * -Mathf.Sign(distanceToGo);
throttleVal = 0f;
} else
{
throttleVal = 0;
}
Debug.DrawRay(current0, heading, Color.red, 1);
Debug.DrawRay(current0, this.transform.up, Color.red, 1);
}
I'm not sure exactly how your code is setup or how the steering works. You may want to look into using the Unity NavMeshAgent to simplify this.
Regardless here is some code I wrote up that takes a destination and rotates an object towards it. All you'd have to do from there is move the object forwards.
Vector3 nextDestination = //destination;
Vector3 direction = nextDestination - transform.position;
direction = new Vector3(direction.x, 0, direction.z);
var newRotation = Quaternion.LookRotation(direction);
var finalRotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime); //smoothes out rotation
transform.rotation = finalRotation;
Sorry if this isn't what you needed. Have you been able to figure out which part of the code is behaving unexpectedly from your print statements?
I have a simple board game where tokens get moved from square to square. I am using a coroutine to move the tokens. It does something like below
IEnumerator MoveTokenCoRoutine(int steps)
{
while (steps > 0)
{
transform.position = Vector3.Lerp(transform.position, newPos, Time.deltaTime * speed);
yield return null;
--steps;
}
}
The clip is a sliding sound for 2 seconds.
Steps, is how many squares a token should move using Lerp. The only time I could get it synced is with below parameters.
1) Set the lerp speed to 10 which is default speed i use to move
2) Step = 1 (move one square)
3) Call Play() just before while
With this scenario movement and sound effect stay pretty much in sync.
However, if steps get more than 1 and I put the Play() inside loop it just plays one time and stops. But the token keeps moving until while ends.
What approaches do I have to keep this in sync?
There is not much salvagable from your code, unfortunately.
A better working variant would look like this:
IEnumerator MoveTokenCoRoutine()
{
float currentTime=0.0f; // note: NOT in seconds, 1.0f = end of sound sample
Vector3 oldPosition = transform.position;
float startTime = Time.time;
while (currentTime < 1.0f) {
currentTime = (Time.time - startTime)/ DurationInSeconds ;
transform.position = Vector3.Lerp(oldPosition, newPos, currentTime );
yield return null;
}
}
Required variables:
Vector3 newPos Target position at animation end
float DurationInSeconds Length of the sound sample in seconds
I a new here and i try to start working with Unity Engine.
Could somebody explain me, how works Quaternion.Slerp? Because I want to rotate some object in different angles 90, 180 and 270. My code you can see below. Unfortunately when I add 180 degrees, object make crazy things and than put rotation to (0, 180, 180) for this game object. I would like to get (180,0,0)
public float speed = 0.1F;
private float rotation_x;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
rotation_x = transform.rotation.eulerAngles.x;
rotation_x += 180;
}
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotation_x, transform.eulerAngles.y, transform.eulerAngles.z), Time.time * speed);
}
Most examples out there including Unity examples from their official website are using Lerp in the wrong way. They didn't even bother to describe how it works in the API documentation. They just starch it in the Update() function and call it a day.
Mathf.Lerp, Vector3.Lerp, and Quaternion.Slerp work by changing from one position/rotation to another with the t value(last parameter) being passed in.That t value is also know as time.
The min of the t value is 0f and the max is 1f.
I will explain this with Mathf.Lerp to make it easier to understand. The Lerp functions are all the-same for both Mathf.Lerp, Vector and Quaternion.
Remember that Lerp takes two values and returns values between them. If we have a value of 1 and 10 and we do Lerp on them:
float x = Mathf.Lerp(1f, 10f, 0f); will return 1.
float x = Mathf.Lerp(1f, 10f, 0.5f); will return 5.5
float x = Mathf.Lerp(1f, 10f, 1f); will return 10
As you can see, the t(0) returns the min of the number passed in, t(1) returns the max value passed in and t(0.5) will return mid point between the min and the max value. You are doing it wrong when you pass any t value that is < 0 or > 1. That code in you Update() function is doing just that. Time.time will increase every second and will be > 1 in a second, so you have problems with that.
It recommended to use Lerp in another function/Coroutine instead of the Updated function.
Note:
Using Lerp has a bad side of it when it comes to rotation. Lerp does not know how to rotate Object with the shortest path. So bear that in mind. For example, you have an Object with 0,0,90 position. Lets say you want to move the rotation from that to 0,0,120 Lerp can sometimes rotate left instead of right to reach that new position which means it take longer to reach that distance.
Let's say we want to make the rotation (0,0,90) from whatever the current rotation is. The code below will change the rotation to 0,0,90 in 3 seconds.
ROTATION OVER TIME:
void Start()
{
Quaternion rotation2 = Quaternion.Euler(new Vector3(0, 0, 90));
StartCoroutine(rotateObject(objectToRotate, rotation2, 3f));
}
bool rotating = false;
public GameObject objectToRotate;
IEnumerator rotateObject(GameObject gameObjectToMove, Quaternion newRot, float duration)
{
if (rotating)
{
yield break;
}
rotating = true;
Quaternion currentRot = gameObjectToMove.transform.rotation;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
gameObjectToMove.transform.rotation = Quaternion.Lerp(currentRot, newRot, counter / duration);
yield return null;
}
rotating = false;
}
INCREMENTAL ANGULAR ROTATION OVER TIME:
And to just rotate the Object to 90 in z axis, the code below is a great example of that. Please understand there is a difference between moving Object to new rotational point and just rotating it.
void Start()
{
StartCoroutine(rotateObject(objectToRotate, new Vector3(0, 0, 90), 3f));
}
bool rotating = false;
public GameObject objectToRotate;
IEnumerator rotateObject(GameObject gameObjectToMove, Vector3 eulerAngles, float duration)
{
if (rotating)
{
yield break;
}
rotating = true;
Vector3 newRot = gameObjectToMove.transform.eulerAngles + eulerAngles;
Vector3 currentRot = gameObjectToMove.transform.eulerAngles;
float counter = 0;
while (counter < duration)
{
counter += Time.deltaTime;
gameObjectToMove.transform.eulerAngles = Vector3.Lerp(currentRot, newRot, counter / duration);
yield return null;
}
rotating = false;
}
All my examples are based on frame-rate of the device. You can use real-time by replacing Time.deltaTime with Time.delta but more calculation is required.
Before anything, you can't add 180 on euler angles like that, and that's mainly what is causing your problem. You'd better use quaternion directly instead, or work on the transform itself.
You can think of a quaternion as an orientation in space. In contrary to what have been said, I do recommend learning how to use them if you can. However, I don't recommend using euler angles at all... as they're suject to different writing conventions, and will fail sometimes. You can look at 'gimbal lock' if you want details about that.
Simply a slerp or lerp (standing for spherical linear interpolation, or linear interpolation respectively) is a way to interpolate (go from one orientation to another, by increasing t from 0 to 1, in a coroutine or anywhere else) between orientation A and B. The difference between the two is that the slerp is giving you the shortest path from A to B.
In the end, when t = 1, lerp(A,B,t) and slerp(A,B,t) will give you B.
In your case, if you want to instantly rotate an object in space to a specific orientation, I suggest you use Quaternion.AngleAxis which is the most forward way to describe mathematically a quaternion.
If you want to add a rotation, say 90° to you actual orientation (without animation between the two), you can do something like this :
transform.rotation *= Quaternion.AngleAxis(axis_of_rotation, angle)
or use transform.rotate (depending on the parameters, it can be a right multiply, or left : local, or world transform).
Programmers' answer is detailling how to animate your transform. But I do suggest you to investigate quaternion themselves, as it will give you global understanding of space transforms.