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.
Related
Struggling with the implementation of character rotation animation by 180 degrees.
For clarity, I made a Pivot, which indicates the target of the direction, then compares the angle between the direction of the character and the direction of the target, calculates the difference in the nearest angles and, if the difference is greater than 179, plays the Turn180 animation.
Works, but crooked.
Screenshot
Problem:
Since the control of the character and the target are identical, the script does not have time to calculate the difference and gives out values at full turn are not always needed. Like: (-178.6661), (169.8465), (168.1936) and so on.
I'm sure there is an easier way. The only thing that comes to mind is to compare the TargetPisition with the -transform.forward and then play the reversal animation. But I can't figure out how to do it. I need help with Movement and Target.
UPDATE
I rewrote the code from scratch more carefully, but the issue with the turn remains relevant. The target and the Player are turning at the same time, how do I tell the program that I'm going to turn in the opposite direction and play the animation?
void Movement() {
// WASD
float Horizontal = Input.GetAxis("Horizontal");
float Vertical = Input.GetAxis("Vertical");
Vector3 move = Quaternion.Euler (0, playerCamera.transform.eulerAngles.y, 0) * new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
//Movement
controller.Move(move * Time.deltaTime * playerSpeed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
//
//Pivot
Pivot.transform.position = gameObject.transform.position;
PivotDirection.transform.rotation = gameObject.transform.rotation;
PivotTarget.transform.position = gameObject.transform.position + move;
Vector3 PivotTargetDirection = Vector3.RotateTowards(PivotTarget.transform.forward, move, 10, 0);
PivotTarget.transform.rotation = Quaternion.LookRotation (PivotTargetDirection);
PivotArrow.transform.rotation = Quaternion.Euler (0, playerCamera.transform.eulerAngles.y, 0);
//
// ReceivedAngle
var PlayerDirection = new Vector3(0, transform.eulerAngles.y, 0);
var TargetDirection = new Vector3(0, PivotTarget.transform.eulerAngles.y, 0);
var ReceivedAngle = Mathf.DeltaAngle(PlayerDirection.y, TargetDirection.y);
print(Mathf.RoundToInt(ReceivedAngle));
//
if (ReceivedAngle >= 180)
{
animator.Play("Turn 180");
}
}
P.S. Sorry for my English.
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.
I am trying to automate a random rotation of a 3rd person character in Unity and I'd like the rotation to be animated as if I were turning the player myself using the out of the box controller and the WASD keys. The goal is an NPC that randomly rotates, looking for someone in a crowd.
Here is what I've attempted thus far, within a coroutine in update.
float xDegress = Random.Range(10f, 75f);
float yDegress = Random.Range(10f, 75f);
float zDegress = Random.Range(10f, 75f);
// Works but immediate
this.transform.Rotate(0f, yDegress, 0f);
// Works but immediate
this.transform.LookAt(new Vector3(xDegress, 0f, zDegress));
// Doesn't work
rB.rotation = Quaternion.Lerp(transform.rotation, new Quaternion(0, yDegress, 0, 0), 0.5f);
// Doesn't work
rB.MoveRotation(new Quaternion(0, yDegress, 0, 1).normalized);
// Works but immediate
Vector3 newPosition = new Vector3(xDegress, 0f, zDegress);
transform.rotation = Quaternion.Lerp(
transform.rotation,
Quaternion.LookRotation(newPosition, Vector3.up),
0.5f);
yield return new WaitForSeconds(_pauseSeconds);
Here's the inspector for the NPC, which is Ethan from the standard assets.
First of all since it is a RigidBody you shouldn't use transform.rotation = nor any transform. method at all but stick to rb.MoveRotation or rb.rotation.
Than you used Lerp in a "wrong" way. What you want is a value that grows from 0 to 1. Calling it only once with a factor of fixed 0.5f allways results in a rotation halfway inbetween the first and the second
one - immediately.
First you need a desired duration for the rotation.
// How long in seconds should the rotation take?
// might be a constant or set via the inspector
public float rotationDuration = 1.0f;
Than before you start rotating get the start and end rotation
float xDegress = Random.Range(10f, 75f);
float yDegress = Random.Range(10f, 75f);
float zDegress = Random.Range(10f, 75f);
var currentRotation = transform.rotation;
var targetRotation = currentRotation * Quaternion.Euler(xDegress, yDegress, zDegress);
// or
Vector3 newPosition = new Vector3(xDegress, 0f, zDegress);
var targetRotation = Quaternion.LookRotation(newPosition, Vector3.up);
// or whatever your target rotation shall be
Now since you already are in a Coroutine you can simply add a while loop performing the rotation within the desired duration (don't forget the yield though)
var passedTime = 1.0f;
while(passedTime < rotationDuration)
{
// interpolate the rotation between the original and the targetRotation
// factor is a value between 0 and 1
rb.MoveRotation = Quaternion.Lerp(currentRotation, targetRotation, passedTime / rotationDuration);
// add time passed since last frame
passedtime += Time.deltaTime;
yield return null;
}
// to avoid overshooting set the target rotation fix when done
transform.rotation = targetRotation;
yield return new WaitForSeconds(_pauseSeconds);
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 want to lerp the start color of two particle systems from one color to another in Unity if the player enters a triggerzone. I tried to do it with Color.Lerp but the result is that it lerps "laggy", meaning it has only 3 colors inbetween. My code:
public IEnumerator animateTriggerEnter(float duration = 0.1f)
{
float elapsedTime = 0f;
float lerp = 0f;
while (lerp <= 1f)
{
elapsedTime += Time.deltaTime;
lerp = elapsedTime / (float) duration;
topParticle.startColor = Color.Lerp(standardColor, triggerColor, lerp);
botParticle.startColor = Color.Lerp(standardColor, triggerColor, lerp);
yield return null;
}
}
For the value lerp, I always get the same 6 values, but should it not be more? It also remains laggy with a higher duration.
First of all I'd try isolating
Color.Lerp(standardColor, triggerColor, lerp);
and testing it's speed Stopwatch?
If I am right lerp is noting more than
result=startValue + (endValue - startValue) * lerpValue;
In that case + 1 constructor execution.
According to MSDN
math itself will should take less than
lerp = elapsedTime / (float) duration;
Are you sure it's lerp problem?