MathHelper.Lerp C# (Linear Interpolation) - c#

I'm having a small problem with this function, MathHelper.Lerp(float f1, float f2, float amount). What I'm trying to accomplish is this: I'm having a DataTable in my program with angles and a value correspinding towards this angle value. When you choose an angle not present in the Table I want to use Linear Interpolation to manage this. I want something to replace my first implementation of this which looked like this:
else if(angle >= 50 && marklast < 65)
{
DataRow row1 = table.Rows.Find(50);
DataRow row2 = table.Rows.Find(65);
someVariable = SomeMethod(row1, row2);
}
So now I have a lot of these If statments and would like an other way of doing this with the MathHelper.Lerp, problem is I'm having a hard time getting the function, what is amount? And would you modify this in a good way for my implementation?

Amount is a value in 0..1 range.
if it is 0 lerp return source value,
if it is 1 lerp return target value,
if it is a value between 0..1 lerp will return a linear interpolated value between the source and the target values.
I'm not sure you want to do... I think is something like this:
Amount = (angle - 50)/(65-50);
InterpolatedValue = MathHelper.Lerp(row1.Value, row2.Value, Amount);

Related

How to check if an object has a rotation in a range near the rotation of another object?

I'm not very experienced in unity C# so this may be something that is very easy that I'm over complicating.
what I'm trying to achieve is to get a variable to set to something depending on if 2 objects have similar rotations, but its outputting bullet1 every time.
if(hand1.transform.rotation.y > (hand2.transform.rotation.y + 90)
&& hand1.transform.rotation.y < (hand2.transform.rotation.y - 90))
{
bulletresult = bullet1;
}
else
{
bulletresult = bullet2;
}
You need to use hand1.tranfsform.rotation.eulerAngles.y instead of hand1.tranfsform.rotation.y. Same of course for hand2
You can you the function float Angle(Quaternion a, Quaternion b) to find out the angle between to rotation.
And please check your condition again. It will never be true. (Tell me if I am wrong)
Transform.rotation is a Quaternion (see also Wikipedia - Quaternion)!
Except you know exactly what you are doing - which you don't, no offense ;) - NEVER directly get or set the individual components of a Quaternion!
So in case you didn't know: A Quaternion has not 3 but 4 components x, y, z and w. All of them move in the range -1 to 1.
Your condition can never be true.
You could check using Quaternion.Angle
if(Quaternion.Angle(hand1.transform.rotation, hand2.transform.rotation) <= 90)
but be aware that this returns the rotation delta on any axis.
Alternatively for getting the delta only on the global Y-Axis you could rather use vectors and flatten the individual right (local X) or forward (local Z) vectors onto the XZ plane and use Vector3.Angle
// get the local right vectors in global space
var right1 = hand1.transform.right;
var right2 = hand2.transform.right;
// flatten the vectors so we don't have any difference in the global Y axis
right1.y = 0;
right2.y = 0;
// Now get the angle between these
if(Vector3.Angle(right1, right2) < 90)

error: The input string was not in the correct format

Checking for number 3 in Text
error:
The input string was not in the correct format
public Text Timer;
private void FixedUpdate()
{
if (Convert.ToDouble(Timer.text) == 3)
{
Debug.Log("w");
}
}
we don't know which string content your Time.text has but you should rather use either double.TryParse or since everything in the Unity API uses float anyway maybe rather float.TryParse. Alternatively you can also cast it to (float) since you are wanting to compare it basically to an int value anyway the precision doesn't really matter.
Because a second point is: You should never directly compare floating point type numbers via == (See How should I do floating point comparison?). It is possible that a float (or double) value logically should have the value 3 like e.g. (3f + 3f + 3f) / 3f but due to the floating point imprecision results in a value like 2.9999999999 or 3.000000001 in which case a comparing to 3 might fail unexpectedly.
Rather use the Unity built-in Mathf.Approximately which basically equals using
if(Math.Abs(a-b) <= epsilon)
where Mathf.Epsilon
The smallest value that a float can have different from zero.
So I would recommend to rather do something like
if (double.TryParse(Timer.text, out var time) && Mathf.Approximately((float)time, 3))
{
Debug.Log("w");
}
Note however that if this is a timer that is continuously increased you might never exactly hit the value 3 so you might want to either use a certain threshold range around it like
if (double.TryParse(Timer.text, out var time) && time - 3 >= someThreshold)
{
Debug.Log("w");
}
or simply use e.g.
if (double.TryParse(Timer.text, out var time) && time >= 3)
{
Debug.Log("w");
}
if you only want any value bigger or equal to 3.

Logarithmic Fade In and Out over Game Frames

I have created a static function within Unity3d that fades out music over a certain amount of frames. The function is being placed within Unity3d's FixedUpdate() so that it updates according to real world time (or at least close hopefully).
My current math for a linear fade out looks like this:
if (CurrentFrames > 0) {
AudioSourceObject.volume = ((CurrentFrames / TotalFrames) * TotalVolume);
}
if (CurrentFrames <= 0) {
AudioSourceObject.volume = 0.00f;
return 0;
}
CurrentFrames--;
This works well as a simple way to create a function that's like FadeOutBGM(NumberOfFrames);...but now I'm looking at how I would create a logarithmic fade out using this function.
Looking at the equasions online, I'm completely confused as to what I should do.
You can do this easily by using Unity's built in AnimationCurve class. Define it in your class and use the Unity inspector to plot a logarithmic curve.
Then in the fade out class, do something like this:
public AnimationCurve FadeCurve;
//...
if (CurrentFrames > 0) {
float time = CurrentFrames / TotalFrames;
AudioSourceObject.volume = FadeCurve.Evaluate(time) * TotalVolume;
}
//...
Its very useful for doing all kinds of easing effects, just try playing around with different curves.
You're more than welcome to use the builtins. Otherwise, if you'd like finer control, you could use an adjusted sigmoid function. Normally, a sigmoid function looks like this: (https://www.wolframalpha.com/input/?i=plot+(1%2F(1%2Be%5E(t)))+from+-5+to+5)
But you want your fade out function to look more like this: (https://www.wolframalpha.com/input/?i=plot+(1%2F(1%2Be%5E(3t-4))+from+-5+to+5)
Where x is your ratio of (CurrentFrames / TotalFrames) * 3, and y is the output volume.
But how did I get from the first to the second graph? Try experimenting with the scalers (i.e. 3x or 5x) and offsets (i.e. (3x - 4) or (3x - 6)) of the exponential input (e^(play with this)) in wolfram alpha to get a feel for how you want the curve to look. You don't necessarily have to line up the intersection of your curve and an axis with a particular number, as you can adjust the input and output of your function in your code.
So, your code would look like:
if (CurrentFrames > 0) {
// I'd recommend factoring out and simplifying this into a
// function, but I have close to zero C# experience.
inputAdjustment = 3.0
x = ((CurrentFrames / TotalFrames) * inputAdjustment);
sigmoidFactor = 1.0/(1.0 + Math.E ^ ((3.0 * x) - 4.0));
AudioSourceObject.volume = (sigmoidFactor * TotalVolume);
}
if (CurrentFrames <= 0) {
AudioSourceObject.volume = 0.00f;
return 0;
}
CurrentFrames--;

Normalizing an integer to pass to another value

I have an integer that updates itself from 0 - 599 which I'm trying to normalize and pass to another variable. My first integer value is just a single int. It isn't in a list or anything.
What I'm trying to do is tie in a color lerp time length based on the length of integer value. This integer value is iterating through a list of meshes to be displayed. It looks like this:
int meshNum;
public void AnimateMesh()
{
if(playAnim)
{
meshToChange.GetComponent<MeshFilter>().mesh = fluidMesh[meshNum];
if(meshNum < 599)
meshNum++;
else
meshNum = 0;
}
else
{
meshNum = 0;
}
}
And my lerp code for the color is this:
diffuse_Material.color = Color.Lerp(Color.blue, Color.red, speedCount);
What I'm wanting to change speedCount in my lerp method to a variable that is matched with the length of the animation. My lerp isn't always on screen, but the animation is, when I want the lerp to appear, I want to it be the same each time it appears no matter where the animation currently is.
Color.Lerp expects a parameter from 0 .. 1. The simplest way would be to simply give it (float)meshNum / 599f.
float number = (float)randomizedNumber / 599.0f;
since your max value is 599, anyway this color difference would'nt be noticed or event will be rounded since RGB has only 256 values for eash base color.

Looking for ideas how to refactor my algorithm

I am trying to write my own Game of Life, with my own set of rules. First 'concept', which I would like to apply, is socialization (which basicaly means if the cell wants to be alone or in a group with other cells). Data structure is 2-dimensional array (for now).
In order to be able to move a cell to/away from a group of another cells, I need to determine where to move it. The idea is, that I evaluate all the cells in the area (neighbours) and get a vector, which tells me where to move the cell. Size of the vector is 0 or 1 (don't move or move) and the angle is array of directions (up, down, right, left).
This is a image with representation of forces to a cell, like I imagined it (but reach could be more than 5):
Let's for example take this picture:
Forces from lower left neighbour: down (0), up (2), right (2), left (0)
Forces from right neighbour : down (0), up (0), right (0), left (2)
sum : down (0), up (2), right (0), left (0)
So the cell should go up.
I could write an algorithm with a lot of if statements and check all cells in the neighbourhood. Of course this algorithm would be easiest if the 'reach' parameter is set to 1 (first column on picture 1). But what if I change reach parameter to 10 for example? I would need to write an algorithm for each 'reach' parameter in advance... How can I avoid this (notice, that the force is growing potentialy (1, 2, 4, 8, 16, 32,...))? Can I use specific design pattern for this problem?
Also: the most important thing is not speed, but to be able to extend initial logic.
Things to take into consideration:
reach should be passed as a parameter
i would like to change function, which calculates force (potential, fibonacci)
a cell can go to a new place only if this new place is not populated
watch for corners (you can't evaluate right and top neighbours in top-right corner for example)
It should not be difficult to write your algorithm to search all of the cells within the reach distance of a particular cell C. Each cell that has an inhabitant would have a particular force of repulsion on cell C. This force of repulsion is based on the distance from the cell to cell C. In the example that you have given, that force of repulsion is based upon the L-1 distance and is 2^(reach-distance). Each repulsion force is then added together to create a cumulative force that dictates the direction in which to move the inhabitant in cell C.
You do not need to write an algorithm for each different reach. The magnitude of the force can be determined via a simple formula. If you change that formula to something else such as a Fibonacci number, you should still be able to calculate the magnitude as needed based upon the distance and the reach.
Here is some rough code written in pseudo-Java showing the basic ideas: http://codepad.org/K6zxnOAx
enum Direction {Left, Right, Up, Down, None};
Direction push(boolean board[][], int testX, int testY, int reach)
{
int xWeight = 0;
int yWeight = 0;
for (int xDist=-reach; xDist<=+reach; ++xDist)
{
for (int yDist=-reach; yDist<=+reach; ++yDist)
{
int normDist = abs(xDist) + abs(yDist);
if (0<normDist && normDist<reach)
{
int x = testX + xDist;
int y = testY + yDist;
if (0<=x && x<board.length && 0<=y && y<board[0].length)
{
if (board[x][y])
{
int force = getForceMagnitude(reach, normDist);
xWeight += sign(xDist) * force;
yWeight += sign(yDist) * force;
}
}
}
}
}
if (xWeight==0 && yWeight==0) return Direction.None;
if (abs(xWeight) > abs(yWeight))
{
return xWeight<0 ? Direction.Left : Direction.Right;
}
else
{
return yWeight<0 ? Direction.Up : Direction.Down;
}
}
int getForceMagnitude(int reach, int distance)
{
return 1<<(reach-distance);
}
Write a function to loop over the neighbors:
Use min/max to clamp the bounds of the matrix.
Use a for loop to loop over all neighbors.
Modify the for loop bounds to represent reach.
:
def CalculateForceOnCell(x, y):
force_on_x_y = [0,0,0,0]
for i in range(max(0, x-reach), min(WIDTH, x+reach)+1):
limited_reach = reach - abs(x-i)
for j in range(max(0, y - limited_reach), min(HEIGHT, y + limited_reach + 1)):
force_coefficient = limited_reach + 1
AddNeighborForce(force_on_x_y, (x, y), (i, j), force_coefficient)
return force_on_x_y

Categories