I'm sitting here and trying to resolve an issue I have, with alternating between 0 and 1 of a variable.
Basicly, I want to do something like this:
float distance = 32f;
float maxDistance = 32f;
float clampedDistance = Math.ClampPresentableValue(distance, maxDistance);
The variable "clampedDistance", would receive the clamped value from the math method. "ClampPresentableValue" should in this case, be able to take the "distance" value, and calculate, where it is in the "0 to 1" timeline, in comparison to the maxDistance.
In this case, since "distance" is the same as "maxDistance", the clamped value would be 1.0f. But if we cut "distance" down to 16f, the clamped value would present 0.5f, in the "clampedDistance" variable.
What is something like this called? Does it have a name, or is it just an algorithm that i'd have to build myself?
It should probably be called 'normalize' or something like that. If I understood you correctly, you should simply do this:
float normalizedDistance = distance / maxDistance;
Related
How can I keep the diagonal speed to be the same as the horizontal and vertical speed without clamping any value or using ".normaized". I tryed to normalize the values but I lost the joystick values between 1 and 0. Here is my code :
void ListenInput()
{
Vector3 rightDirection = camera.right;
Vector3 frontDirection = camera.GetForwardFromAngleY();
move = new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
);
MoveCharacter(rightDirection * move.x);
MoveCharacter(frontDirection * move.y);
}
void MoveCharacter(Vector3 velocity)
{
transform.position += velocity * Time.deltaTime * runningSpeed;
}
Here, you should clamp the magnitude of the input Vector2.
For example with Vector2.ClampMagnitude() from the Unity API.
That will keep the input non-binary and prevent the diagonal from getting larger than purely horizontal/vertical inputs.
void ListenInput()
{
Vector3 rightDirection = camera.right;
Vector3 frontDirection = camera.GetForwardFromAngleY();
move = new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
);
move = Vector2.ClampMagnitude(move, 1f);
MoveCharacter(rightDirection * move.x);
MoveCharacter(frontDirection * move.y);
}
void MoveCharacter(Vector3 velocity)
{
transform.position += velocity * Time.deltaTime * runningSpeed;
}
If you normalize a vector you will make sure it's length is 1. This is a great way to avoid quirks like "diagonal movement is faster than normal movement".
However, the fact that the length is always 1 also means that there is no "move slowly" or "move at full speed" distinction from the joystick. When you say "I lost the joystick values between 1 and 0" is due to this fact.
One way developers get around this is by using a mathematical formula to scale the speed.
You could:
Use the largest value (horizontal or vertical) to control the speed
Use the smallest value
Use a combination of the two
Another way to do this is to store how long ago the movement started, then scale the speed based on that. This method has its own challenges, but is very familiar to players.
Examples
For instance, if I have:
horizontalInput = 1
verticalInput = 0.5
This means my normalized vector looks like this:
I could:
Use the largest value
Move at full speed (1) on the direction of my vector.
Use the smallest value
Move at half speed (0.5) on the direction of my vector.
Use a Use a combination of the two values
For this instance, lets use the following formula: (x+y)/2.
Move at 3/4 speed (0.75) on the direction of my vector.
NOTE: This formula will not "feel" as nice if you have x=0 and y=1, this is just an example. You most likely want to use Min, Max, Avg and if-clauses to control how the speed works.
You can use different formulas and different techniques to make the movement in your game feel like what you want, but take the time to analyze WHY it feels like that.
I have water being drained down from its max value to 0 in a certain time period (timeToDrain in this code). What I'm wonder is why I can't modify this value (water) at all when I do something like
water += 1;
My code:
public float water,waterMax,w;
void ddrainWater() {
float timeToDrain = 160; //seconds
float timeRemaining = timeToDrain - w;
w += Time.deltaTime;
water = Mathf.Lerp(waterMax, 0, w / timeToDrain);
}
Again, I am not exactly sure how to solve something like this.
Expected: being able to do
water += 0.2f;
But water is constantly being set back to the value that was given to it by Mathf.Lerp(). Is there any way I can add/subtract a value from this variable? Maybe something to do with the variable 'w'?
Because of the Lerp
That Lerp call does not in any way care what the current value of water is, it will overwrite it based on w.
If you want to add water, you need to subtract from w or not use Lerp and instead manage the draining speed yourself.
I can't provide an example fix, because how you want to handle things is how you want to handle things (and I don't have all your code).
Currently you are setting water to a new value through water += value, but then setting it to another value through the Lerp function which varies independently of the current value for water.
Your choices are to either: decrease w by an amount (perhaps replace water += value with w -= (waterMax / timeToDrain) * value), increase the timeToDrain by some value (perhaps replace water += value with timeToDrain += (timeToDrain / waterMax) * value), or to replace the Lerp function with something that uses the current water level rather than the maximum.
If you code what you say you looking for it actually would work fine - decrease current amount of water by draining happened since last tick:
var amountDrainedSinceLastCheck = waterMax * Time.deltaTime / timeToDrain;
water = water - amountDrainedSinceLastCheck;
I've been programming an ability for a Hack n Slash which needs to check Units within a pie slice (or inbetween two angles with max length). But I'm stuck on how to check whether an unit is within the arc.
Scenario (Not enough, rep for an image sorry im new)
I currently use Physics2D.OverlapSphere() to get all of the objects within the maximum range. I then loop through all of the found objects to see whether they are within the two angles I specify. Yet this has janky results, probably because angles don't like negative values and value above 360.
How could I make this work or is there a better way to do this?
I probably need to change the way I check whether the angle is within the bounds.
Thanks in advance guys! I might respond with some delay as I won't be at my laptop for a couple hours.
Here is the code snippet:
public static List<EntityBase> GetEntitiesInArc(Vector2 startPosition, float angle, float angularWidth, float radius)
{
var colliders = Physics2D.OverlapCircleAll(startPosition, radius, 1 << LayerMask.NameToLayer("Entity"));
var targetList = new List<EntityBase>();
var left = angle - angularWidth / 2f;
var right = angle + angularWidth / 2f;
foreach (var possibleTarget in colliders)
{
if (possibleTarget.GetComponent<EntityBase>())
{
var possibleTargetAngle = Vector2.Angle(startPosition, possibleTarget.transform.position);
if (possibleTargetAngle >= left && possibleTargetAngle <= right)
{
targetList.Add(possibleTarget.GetComponent<EntityBase>());
}
}
}
return targetList;
}
Vector2.Angle(startPosition, possibleTarget.transform.position);
This is wrong. Imagine a line from the scene origin (0,0) to startPosition and a line to the transform.position. Vector2.Angle is giving you the angle between those two lines, which is not what you want to measure.
What you actually want is to give GetEntitiesInArc a forward vector then get the vector from the origin to the target position (var directionToTarget = startPosition - possibleTarget.transform.position) and measure Vector2.Angle(forward, directionToTarget).
im trying to move a object in unity between 2 points, and at the moment it kinda works strange, i read the documentation and it says that the object begin point is (0,0,0) so my object goes under my other mesh that i have there, and the end point i can actually control, in my case it is 10, i want the object to move between 1.5 and 10(not 0 to 10)
i have this
void Update () {
transform.position = new Vector3(transform.position.x,Mathf.PingPong(Time.time,10.0f), transform.position.z);
}
when i try to put speed on the ball doing this:
void Update () {
transform.position = new Vector3(transform.position.x,Mathf.PingPong(Time.time,10.0f) * 10, transform.position.z);
}
the object does not colide and goes back at the end point it just stop looping and never came back how can i correct this 2 problems?
If your object has a collider, I suggest you move it via its Rigidbody rather than its Transform, to avoid potential collision issues. Try this:
public float MinY = 1.5f; // y position of start point
public float MaxY = 10f; // y position of end point
public float PingPongTime = 1f; // how much time to wait before reverse
public Rigidbody rb; // reference to the rigidbody
void Update()
{
//get a value between 0 and 1
float normalizedTime = Mathf.PingPong(Time.time, PingPongTime) / PingPongTime;
//then multiply it by the delta between start and end point, and add start point to the result
float yPosition = normalizedTime * (MaxY - MinY) + MinY;
//finally update position using rigidbody
rb.MovePosition(new Vector3(rb.position.x, yPosition, rb.position.z));
}
Here you have a better control on the distance to travel, and the speed.
Actually I didn't get exactly what are the problem you faced. But don't forget here and in your try, that you are directly modifying the position of the object, not adding forces or else.
Hope that helps you.
I think you simply misunderstood how the Mathf.PingPong method works :
first argument t is the value you want to "clamp" between 0 and the given length : this is were you want to put the Time.time as you did since this value will increase over time and therefore perpetually oscillate. If you want to increase/decrease the oscillation speed you have to multiply it.
second argument length is the max value of the "clamp" : if you want to increase/decrease the distance (in your case) you have either set it to 0 and multiply the whole Mathf.PingPong(...) by a value or directly give it the wanted value (both implementations will have a different effect.
Mathf.PingPong(Time.time * speed, 1.0f) * value : speed will affect the oscillation speed / value will affect the max value reached AND the speed / time to complete the oscillation (back and forth) will remain the same as value changes and decrease as speed increases
Mathf.PingPong(Time.time * speed, value) : speed will affect the oscillation speed / value will affect the max value reached BUT NOT the speed / time to complete the oscillation (back and forth) will increase as value increases and decrease as speed increases
About your other problems :
If you want to move your object between 1.5 and 10 you have to write something like this :
transform.position = new Vector3(transform.position.x, 1.5f + Mathf.PingPong(Time.time, 10.0f - 1.5f), transform.position.z);.
Also if you want to detect collision, avoid setting position manually as it will mess up with Physics and cause weird behaviors. Best way to move your object while keeping physic working is to do as #Heldap said using Rigidbody.MovePosition.
I am wanting to lerp the variable that controls my animations speed so it transitions fluidly in the blend tree.
void Idle()
{
_agent.SetDestination(transform.position);
//Something like the following line
_speed = Mathf.Lerp(0.0f, _speed, -0.01f);
_animationController._anim.SetFloat("Speed", _speed);
}
I'v read that you can't lerp negatives, so how do I do this?
I think you're using Lerp bad.
As written in Unity Documentation (http://docs.unity3d.com/ScriptReference/Mathf.Lerp.html), you should pass 3 floats, the minimum as first argument, the maximum as second and the time as third.
This third should be beetwen 0 and 1.
Aside from that, you can always make the number negative after lerping it.
Some examples :
In case you want from -10 to 10, lerp from 0 to 20 and then substract 10.
float whatever = Mathf.Lerp(0f, 20f, t);
whatever -= 10f;
In case you want from 0 to -50, lerp from 0 to 50 and then make it negative.
float whatever = Mathf.Lerp(0f, 50f, t);
whatever = -whatever;
The t value in a lerp function between a and b typically needs to be in the 0-1 range. When t is 0, the function returns a and when t is 1, the function returns b. All the values of t in between will return a value between a and b as a linear function. This is a simplified one-dimensional lerp:
return a + (b - a) * t;
In this context, negative values of t don't make sense. For example, if your speed variable is 4.0f, the result of lerp(0, 4, -0.01f) would be:
0 + (4 - 0) * -0.01
which returns -0.04.
The simplest way to solve this issue is to simply flip a and b instead of trying to use a negative t.
_speed = Mathf.Lerp(_speed, 0.0f, 0.01f);
Another suggestion would be to use Mathf.SmoothStep and store the original speed instead of applying the function on the constantly changing _speed to get a really smooth transition.
Well, you cannot actually.
A psuedo-codish implementation of a Lerp function would look like this:
float Lerp(float begin, float end, float t)
{
t = Mathf.Clamp(t, 0, 1);
return begin * (1 - t) + end * t;
}
Therefore, any attempt to give a t value outside of [0, 1], ie. an extrapolate attempt, would be clamped to the valid range.