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--;
Related
I'm working on a game for game jam and part of it is to make platforms that move smoothly. They slow down at the ends of their movement before turning around. The platforms simply move side to side or up and down between two waypoints(which are just empty transforms). I have code that uses cosine to determine the speed which works well except it doesn't align with the waypoints, the platforms tend to slow and change direction before ever reaching the waypoints. I need a way to use the distance between the waypoints as a variable in determining how the cosine equation changes speed so that the platforms slow and reverse direction exactly at the waypoints.
Here is what I have so far:
void Side_to_side()
{
if (waypointIndex < horWaypoints.Length)
{
platformSpeed = (1f * (float)Mathf.Cos(2f * (float)Mathf.PI * 1f * totalTime));
Vector3 targetPosition = horWaypoints[waypointIndex].position;
float delta = platformSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, targetPosition, delta);
if (transform.position.x == targetPosition.x && transform.position.y == targetPosition.y)
{
if (waypointIndex + 1 == horWaypoints.Length)
waypointIndex = 0;
else
waypointIndex++;
}
}
else
{
waypointIndex = 0;
}
//Translate platform back and forth between two waypoints
}
As I have said this code moves the platforms in the motions i want but they don't use the waypoints as turn around points. I understand I could do away with the waypoints and just calculate how far I would like each platform to go before turning around individually but that would take time to do it for each platform whereas I'd like to quickly put down waypoint pairs for them to use and the script calculates what the perfect values would be to match the waypoint locations.
If I understand you correctly you want to move an object forth and back between exactly two positions and apply some smoothing to the movement.
I would rather use a combination of Vector2.Lerp with a Mathf.PingPong as factor and you can then apply ease in and out using additionally Mathf.SmoothStep.
This could look like e.g.
public Transform startPoint;
public Transform endPoint;
// Desired duration in seconds to go exactly one loop startPoint -> endPoint -> startPoint
public float duration = 1f;
private void Update ()
{
// This will move forth and back between 0 and 1 within "duration" seconds
var factor = Mathf.PingPong(Time.time / (2f * duration), 1f);
// This adds additional ease-in and -out near to 0 and 1
factor = Mathf.SmoothStep(0, 1, factor);
// This interpolates between the given positions according to the given factor
transform.position = Vector2.Lerp(startPoint, endPoint, factor);
}
you could of course still use cosine if necessary, basically any function that returns a value between 0 and 1. You just have to use the correct multiplier in order to achieve the desired duration in seconds.
Note: Typed on the phone and not 100% sure on the math but I hope the idea gets clear
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)
In a Unity C# project involving human cells, I want to achieve an effect whereby a group of cells spread out to form a crescent-like formation like so:
Desired formation of cells. (Sorry for the inconvenience, I'm currently a new user to this website).
I tried to adopt Conrad Parker's set-up in Java of Reynolds' group steering behaviour, specifically the Group Separation, then I modified the weighting of x and y axis of the separation in an attempt to get that crescent-like formation.
//Conrad Parker's setup in Java
PROCEDURE rule2(boid bJ)
Vector c = 0;
FOR EACH BOID b
IF b != bJ THEN
IF |b.position - bJ.position| < 100 THEN
c = c - (b.position - bJ.position)
END IF
END IF
END
RETURN c
END PROCEDURE
//My adoption of Conrad Parker's setup without modification
Vector2 Steering = new Vector2(0f,0f);
foreach(GameObject GO in _SameGOType)
{
if(GO != _Agent)
{
Vector2 difference = new Vector2(GO.transform.position.x - _Agent.transform.position.x, GO.transform.position.y - _Agent.transform.position.y);
float distance = difference.magnitude;
if(distance <= 1f)
{
Steering.x -= difference.x;
Steering.y -= difference.y;
}
}
}
return Steering;
//My adoption with modification in an attempt to achieve the formation
Vector2 Steering = new Vector2(0f,0f);
foreach(GameObject GO in _SameGOType)
{
if(GO != _Agent)
{
Vector2 difference = new Vector2(GO.transform.position.x - _Agent.transform.position.x, GO.transform.position.y - _Agent.transform.position.y);
float distance = Mathf.Sqrt(0.5f * Mathf.Pow(difference.x,2f) + 1.8f * Mathf.Pow(difference.y,2f));//difference.magnitude;//Mathf.Sqrt(1f * Mathf.Pow(difference.x,2f) + Mathf.Pow(difference.y,2f));
if(distance <= 1f)
{
Steering.x -= difference.x;
Steering.y -= difference.y;
}
}
}
return Steering;
The attempt only resulted in a behaviour that create a rectangular-like formation. (I can provide a link to my attempt of the formation, if you need !)
Additionally, the cells started to twitch as it get closer to it's position and stop when it reached. So I'm curious as to is my idea of using Group Separation Behaviour to attain the desired crescent-like formation is fundamentally wrong or I simply taken a wrong approach of using it ?
Thank you for reading my question !
I wrote some code today. I can't figure out how to reduce the length of this code, although it seems repetitive, every part is different.
try {
totalVerts.Add(verts[i]);
if (verts[i].x > maxXvert)
{
maxXvert = verts[i].x;
}
if (verts[i].x < minXvert)
{
minXvert = verts[i].x;
}
if (verts[i].y > maxYvert)
{
maxYvert = verts[i].y;
}
if (verts[i].y < minYvert)
{
minYvert = verts[i].y;
}
if (verts[i].z > maxZvert)
{
maxZvert = verts[i].z;
}
if (verts[i].z < minZvert)
{
minZvert = verts[i].z;
}
}
In this code I am adding the Vector3 position vertices (x,y,z) to the totalVerts Array. I am also testing each x,y,z position whether it is the maximum or minimum of all vertices, if it is, I then set the variables maxXvert, maxYvert... etc to the value that is higher or lower.
If anyone can think of a way to reduce, that would be great. Thank you.
You could use Math.Min and Math.Max.
minXvert = Math.Min(verts[i].x, minXvert);
maxXvert = Math.Max(verts[i].x, maxXvert);
That would make your code more concise and readable, but won't make it any faster.
To make it somewhat faster, you could store x, y, z values in local variables, so they only have to be looked up once instead of 2-4 times. But, the compiler is probably doing this for you anyway. int x = verts[i].x; etc.
You could remove all of the brackets: (No refactoring, just less lines!)
try {
totalVerts.Add(verts[i]);
if (verts[i].x > maxXvert)
maxXvert = verts[i].x;
if (verts[i].x < minXvert)
minXvert = verts[i].x;
if (verts[i].y > maxYvert)
maxYvert = verts[i].y;
if (verts[i].y < minYvert)
minYvert = verts[i].y;
if (verts[i].z > maxZvert)
maxZvert = verts[i].z;
if (verts[i].z < minZvert)
minZvert = verts[i].z;
}
Performance wise, this is fine. The code just looks ugly.
unfortunately the Array.max() function in LINQ is only for .net 3.5 and unity is .net 2.0, so I cannot think of a better way.
If the LINQ where available (which it is not), you could do.
float minX=totalVerts.min(v => v.x);
Or similar which would be a lot neater (I would have to check performance)
It's hard to guess the context of this, but in my experience having different floats represent a vector is an unnecessary pain. If you create two Vetor3 instead of six float, you can still access the individual values (eg. myVector3.x += 1f;). And, by using the higher abstraction, you both make the code more readable and incorporate Vector3 functionalities, like Max and Min methods, that serve the very purpose of simplifying code:
Vector3 upperBound = Vector3.one * Mathf.NegativeInfinity,
lowerBound = Vector3.one * Mathf.Infinity;
foreach (Vector3 vert in verts) {
totalVerts.Add(vert);
upperBound = Vector3.Max(upperBound, vert);
lowerBound = Vector3.Min(lowerBound, vert);
}
As a side note, if you are doing procedural meshes and this is to calculate the bounds, be aware of the RecalculateBounds() method. Most of the times, when I need the bounds of a procedural mesh I read it from mesh.bounds after creating and recalculating the mesh, because I had to do that anyways and just reading if afterwards saves me the trouble.
I have a collision resolution method in my physics engine, that goes like this:
Vector2 n1pos = n1.NonLinearSpace != null ? n1.NonLinearPosition : n1.Position;
Vector2 n2pos = n2.NonLinearSpace != null ? n2.NonLinearPosition : n2.Position;
Vector2 posDiff = n2pos - n1pos;
Vector2 posDiffNormal = posDiff;
posDiffNormal.Normalize();
float totalRadius = n1.Radius + n2.Radius;
float posDiffLength = posDiff.Length();
float interPenetration = totalRadius - posDiffLength;
float averageRestitution = (n1.RestitutionCoefficient + n2.RestitutionCoefficient) / 2;
Vector2 forceAmount = Vector2.Multiply(posDiffNormal, interPenetration);
Vector2 n1force =
(
(n1.Velocity * n1.Mass) +
(n2.Velocity * n2.Mass) +
n2.Mass * averageRestitution * (n2.Velocity - n1.Velocity)
) /
(n1.Mass + n2.Mass);
Vector2 n2force =
(
(n1.Velocity * n1.Mass) +
(n2.Velocity * n2.Mass) +
n1.Mass * averageRestitution * (n2.Velocity - n1.Velocity)
) /
(n1.Mass + n2.Mass);
n1.ApplyForce(???);
if (!n1.IsStatic)
{
n1.Position += ???;
}
n2.ApplyForce(???);
if (!n2.IsStatic)
{
n2.Position += ???;
}
Now, i can't figure out what to apply to the bodies in my engine in order to get proper coefficient of restitution working. (the ??? parts). Can someone help?
Judging by this and your other questions, you are trying to run before you can walk.
You're trying to code several unfamiliar things at once, when you should be tackling them one at a time. Try setting the coefficient of restituion to 0, so that your objects act like lumps of putty. That'll be easier to code, and once you have that working you can try elastic collisions.
No offense, but trying to write a physics engine when you haven't studied basic physics is just masochistic. You can either sit down with a textbook or experiment, but there's simply no way to get the engine working without understanding its parts.
I realize this is an old question, but I ran into the same issue and Google turned up this page. I figured I might share my findings. First, you must realize that the coefficient of restitution is a property of the collision, not of either of the bodies involved in the collision. That is, for n objects, you need to define n(n-1)/2 coefficients of restitution (one for each pair of bodies).
However, the physics engines I have looked into (Bullet, Chipmunk, and Box2d) all define the restitution as a property of the bodies. Upon the time of the collision, they combine the two bodies' coefficients of restitution into a single value and use that in the collision resolution. Obviously, this isn't physically correct. But that doesn't matter much for games: it just needs to behave in an intuitive manner. Here are the restitution functions that those physics engines use:
Bullet: restitution = body1->restitution * body2->restitution
Chipmunk: restitution = body1->restitution * body2->restitution
Box2d: restitution = max(body1->restitution, body2->restitution)
Box2d allows the users to customize the restitution function in a configuration file. Bullet and Chipmunk do not.
I recommend you select whatever restitution mixing function feels best. Just play around with it a bit and see what you like.