In this section we will add factors that will affect the bullet, such as wind and drag.
What you need to know if you are going to add realism to the bullet in Heun's method is to calculate the acceleration or velocity with the correct time. Gravity was a constant acceleration and isn't dependent on velocity or position, so we didn't need to care about it when we added gravity. If the wind is constant, we can just add it in the same way as we added gravity. So just uncomment the line "velocityFactor += new Vector3(2f, 0f, 3f);" where the vector is whatever wind you want.
//Heun's method - one iteration //Will give a better result than Euler forward, but will not match Unity's physics engine //so the bullets also have to use Heuns method public static void Heuns( float h, Vector3 currentPosition, Vector3 currentVelocity, out Vector3 newPosition, out Vector3 newVelocity) { //Init acceleration //Gravity Vector3 acceleartionFactorEuler = Physics.gravity; Vector3 acceleartionFactorHeun = Physics.gravity; //Init velocity //Current velocity Vector3 velocityFactor = currentVelocity; //Wind velocity velocityFactor += new Vector3(2f, 0f, 3f); // //Main algorithm // //Euler forward Vector3 pos_E = currentPosition + h * velocityFactor; //acceleartionFactorEuler += BulletPhysics.CalculateDrag(currentVelocity); Vector3 vel_E = currentVelocity + h * acceleartionFactorEuler; //Heuns method Vector3 pos_H = currentPosition + h * 0.5f * (velocityFactor + vel_E); //acceleartionFactorHeun += BulletPhysics.CalculateDrag(vel_E); Vector3 vel_H = currentVelocity + h * 0.5f * (acceleartionFactorEuler + acceleartionFactorHeun); newPosition = pos_H; newVelocity = vel_H; }
Drag force is more complicated to add compared with the wind, because the drag is dependent of the bullet's velocity. So we have to calculate the acceleration from drag 2 times.
//Heun's method - one iteration //Will give a better result than Euler forward, but will not match Unity's physics engine //so the bullets also have to use Heuns method public static void Heuns( float h, Vector3 currentPosition, Vector3 currentVelocity, out Vector3 newPosition, out Vector3 newVelocity) { //Init acceleration //Gravity Vector3 acceleartionFactorEuler = Physics.gravity; Vector3 acceleartionFactorHeun = Physics.gravity; //Init velocity //Current velocity Vector3 velocityFactor = currentVelocity; //Wind velocity velocityFactor += new Vector3(2f, 0f, 3f); // //Main algorithm // //Euler forward Vector3 pos_E = currentPosition + h * velocityFactor; acceleartionFactorEuler += BulletPhysics.CalculateDrag(currentVelocity); Vector3 vel_E = currentVelocity + h * acceleartionFactorEuler; //Heuns method Vector3 pos_H = currentPosition + h * 0.5f * (velocityFactor + vel_E); acceleartionFactorHeun += BulletPhysics.CalculateDrag(vel_E); Vector3 vel_H = currentVelocity + h * 0.5f * (acceleartionFactorEuler + acceleartionFactorHeun); newPosition = pos_H; newVelocity = vel_H; }
You should also create a new script called BulletPhysics where you can collect all methods that affect the bullets, and add a method that calculates drag. You should change these parameters, like mass and area, to fit your bullet.
using UnityEngine; using System.Collections; public class BulletPhysics : MonoBehaviour { //Calculate the bullet's drag's acceleration public static Vector3 CalculateDrag(Vector3 velocityVec) { //F_drag = k * v^2 = m * a //k = 0.5 * C_d * rho * A float m = 0.2f; // kg float C_d = 0.5f; float A = Mathf.PI * 0.05f * 0.05f; // m^2 float rho = 1.225f; // kg/m3 float k = 0.5f * C_d * rho * A; float vSqr = velocityVec.sqrMagnitude; float aDrag = (k * vSqr) / m; //Has to be in a direction opposite of the bullet's velocity vector Vector3 dragVec = aDrag * velocityVec.normalized * -1f; return dragVec; } }
That's all of the external factors we are going to add for now. If you press play you will notice that the bullets are no longer hitting the target. The equation we used to calculate the angle is not working if we add drag and wind.