问题
I'm making simple game in which the player is moved by adding force to him. However, I don't want his acceleration to be constant - I want it to vary depending on the current speed. I made simple acceleration script to do this but it doesn't achieve the desired effect:
float acceleration
{
get { return speed/inversedAcceleration; }
}
void FixedUpdate () {
rb.AddForce(transform.forward * speed);
if (speed < maxSpeed)
speed += acceleration * Time.deltaTime;
}
New way that I also tried:
float timer = 1.0f;
public float velocity { get { return Mathf.Sqrt(timer)*10; } }
void FixedUpdate()
{
timer += Time.deltaTime;
rb.AddForce(transform.forward * velocity);
}
The logic is a bit convoluted, because I have experimented unsuccessfully with it for a while. Now, I think I should change it to use the mathematical formula f(x)=sqrt(x)
as a model for my velocity, rather than my current one which is some form of rational function. How can I change the code to do this, while still using AddForce()
so the player will correctly interact physically with other objects?
回答1:
As mentioned in the comments, my first suggestion would be to avoid manually tracking the speed of an object - Unity's physics system makes this easy to access accurately, through Rigidbody.velocity.magnitude
. You can use this to compare against maxSpeed
, to determine whether additional force should be added or not.
Regarding your desire to have velocity match the curve of f(x)=sqrt(x)
, you're going to need to do some basic calculus for this. Since you don't want to constrain velocity artificially (because you still want physical interactions to occur), you should instead constrain acceleration to a function.
To determine the function to define the player's acceleration, you'll need to derive the function you want velocity to (ideally) match. This will give you the rate of change of the velocity at any given point - which, by definition, is the acceleration.
So let's say we use the function f(x)=sqrt(x)
as a model for the ideal velocity. The derivative of sqrt(x)
is 1/(2 * sqrt(x))
- so this is the function that defines our acceleration. Now, we need to be able to determine the acceleration for any given velocity, since this is the relationship we'll be using in the code. This takes a little simple algebra - we'll need to solve for x
given y
:
y = 1/(2 * sqrt(x))
sqrt(x) * y = 1 / 2
sqrt(x) = 1 / (2 * y)
x = (1 / (2 * y))^2
Now we have an equation that provides us with the required acceleration for any given speed. We can now put this into code - accelerating according to the square root function up to maxSpeed
:
float maxAcceleration = 10;
// Basically x = (1 / (2 * y))^2, but in code
float CalculateAccGivenSpeed(float speed)
{
// Early exit so we don't bother with undefined results from dividing by 0
if (speed == 0)
{
return Mathf.Infinity;
}
float rootAcc = 1 / (2 * speed);
return rootAcc * rootAcc;
}
void FixedUpdate()
{
// Only accelerate if speed is lower than maximum allowed
if (rb.velocity.magnitude < maxSpeed)
{
float allowableAcc = CalculateAccGivenSpeed(rb.velocity.magnitude);
// Constrain acceleration here so rigidbody doesn't explode from stationary
allowableAcc = Mathf.Min(maxAcceleration, allowableAcc);
// Using ForceMode.Acceleration so we don't have to worry about mass
rb.AddForce(transform.forward * allowableAcc, ForceMode.Acceleration);
}
}
If you find the acceleration goes too quickly/slowly, you can multiply the result of CalculateAccGivenSpeed()
with a scalar value. Mathematically, this will scale the square root function along the y-axis, preserving the square root relationship, but changing the rate at which is reaches a given y-value (speed).
Hope this helps! Let me know if you have any questions.
回答2:
Since you want to keep all the physics formulae consistent (reinventing kinematics is tricky), one physics solution could be to make an objects mass a function of its velocity (e.g. m=m_0+k*v^2
to get something like you sqrt approach).
As a result, a force F=ma
will result in a lower acceleration when an object is more massive (i.e. is travelling faster).
Sound familiar-ish? Well that's what E=mc^2
means for objects travelling very fast. I don't recommend implementing other relativistic effects however.
来源:https://stackoverflow.com/questions/36315622/using-a-mathematical-formula-to-define-player-speed