- Home /
Making an arrow Physics without using rigid body
I am trying to make a combat game for iPhone which might include alot of arrows shooting from different teams. I am planning to use just simple transformation and rotation calculation as using rigidbody is alot more expensive to handle like 100 arrows. Can someone helps me how to calculate the proper physics for the arrow .. Currently I am just using the below scripts to simulate arrow but I need more precise calculations. Thanks
void FixedUpdate() { transform.position += Time.deltaTime * speed * transform.forward;
rotation = rotationSpeed * Time.deltaTime;
// Rotate around our x-axis
transform.Rotate(rotation, 0, 0);
}
Answer by skovacs1 · Sep 23, 2010 at 08:15 PM
EDIT: modified the math applied to drag to more closely reflect the Drag Equation by using velocity squared and some constant for the drag. Going any further would also involve calculating the Reynold's number component to determine the drag coefficient.
I'm not entirely sure from your description how you've decided to fire and initially orient ~100 arrows, so I'll make some assumptions and describe how I would approach this.
Why an arrow flies the way it does
An object is propelled with a force in some direction. Given an initial directional force, the object moves forward and encounters wind resistance (which an arrow's design should try to minimize) proportional to the velocity, which will slow the movement. The object in flight will also descend due to gravity. This generally forms the arc of a thrown object.
An arrow will turn along the arc of its trajectory with the arrowhead at the front of the motion because the arrow is heavier at the arrowhead (higher mass and therefore the arrowhead will be less affected by the force of wind resistance(drag) than the shaft). Because of the arrowhead's slightly greater acceleration towards the ground, it will pull the front of the shaft downwards and cause the arrow to rotate.
The feathers will also generate drag to provide stability to the arrow's path for an improvement in accuracy.
How to simulate this
moving the arrow is easy enough
//I forewent the transform.forward because that would only confuse things right now static var gravity : Vector3 = Vector3.up * -9.81; //let's assume it's always down var drag : float = 0.01; // A coefficient for the amount of drag in the medium var velocity : Vector3; //The movement to make this contains direction and speed private var moving : boolean = false;
function Update() { if(moving) { velocity += gravity; velocity -= velocity.sqrMagnitude drag velocity.normalized; transform.position += velocity * Time.deltaTime; } }
Rotating it is only a little trickier. Essentially, we've calculated what direction to move in and we need to rotate so that forward is now that way. There are a bunch of ways to do this. I'll take the naive approach because it demonstrates what we're doing more easily:
static var gravity : Vector3 = Vector3.up * -9.81; //let's assume it's always down var drag : float = 0.01; // A coefficient for the amount of drag in the medium var velocity : Vector3; //The movement to make this contains direction and speed private var moving : boolean = false;
function Update() { if(moving) { velocity += gravity; velocity -= velocity.sqrMagnitude drag velocity.normalized; var amountToMove = velocity * Time.deltaTime; transform.LookAt(transform.position + amountToMove); //look where you're going transform.position += amountToMove; //go there } }
This is very rudimentary implementation overall, but generally covers everything that we really care about and does so fairly efficiently. By tuning the drag and setting the velocity when you fire, you can get any number of results you'd like that should follow physics fairly accurately. To add forces like wind, you would simply add them as another force like gravity however you like. I assume your down is always down, otherwise you would have to calculate gravity's effect every calculation. Note that terminal velocity here is when drag * (velocity + gravity) = gravity.
To get more meaningful results, I'd probably place the pivot at the tip or center of mass of the arrowhead, but that's your call.
You didn't mention how you were handling collisions, but either by doing your own raycast along transform.forward after you've rotated or using a Collider setup, it's fairly easy to simply stop moving.
Amendments.
velocity += gravity; -> velocity += gravity * Time.deltaTime;
velocity -= velocity drag; -> velocity -= velocity $$anonymous$$athf.Pov(drag, (T + Time.deltaTime) / T);
where T - period.
great.... it seems to be nice.. I will test this code in my project ... Thanks
@$$anonymous$$ey: As with any script, you can change the formulas to your liking. You are correct that for more accurate results, drag would involve the raising of a number to some power. As I said, it was rudimentary and the effect of T on the equation was meant to be fudged some by tuning of the drag variable. I have edited the post to use velocity squared in following the Rayleigh's drag equation. I mean if you want the exact calculation, you could calculate Reynold's numbers or apply the formulas from en.wikipedia.org./wiki/Trajectory_of_a_projectile, but that's a bit much.
I mean that your script will be gain different result on different FPS.
Hi, What is Pov means in there.. Is that Pivot point? Buy I can't find Pov function in $$anonymous$$athf.. What would be the other ways to do it?
Answer by Alexey Elyakov · Sep 27, 2010 at 04:05 AM
Sorry, there must be "Pow".
Did "Answer", becouse i can't add comment.
Answer by casperjeff · Dec 20, 2013 at 04:53 PM
I used this exact technique and some others for trajectory/ballistics in my Fire Arrows asset on the asset store - skovacs1 (Scott Kovacs) is smart man....
Can someone clean up this code and convert it to C#? I'm trying to do that now, but it's difficult.
Little bit late but there is the C# version with a little tweak. Now the arrow moves forward...
public class Arrow$$anonymous$$over : $$anonymous$$onoBehaviour
{
//I forewent the transform.forward because that would only confuse things right now
public Vector3 gravity = Vector3.up * -9.81f;
//let's assume it's always down
public float drag = 0.01f;
// A coefficient for the amount of drag in the medium
public Vector3 velocity;
//The movement to make this contains direction and speed
//private bool moving = false;
float lifteTime, force;
public float gravDivider = 4;
public bool is$$anonymous$$oving;
public void Init (float _force)
{
force = _force;
velocity = transform.forward * force;
is$$anonymous$$oving = true;
}
void Update ()
{
if (is$$anonymous$$oving) {
velocity += (gravity / gravDivider) * Time.deltaTime;
velocity -= velocity * $$anonymous$$athf.Pow (drag, (Time.time - lifteTime) / gravDivider);
Vector3 moveAmount = (velocity * Time.deltaTime);
transform.LookAt (transform.position + moveAmount);
transform.position += moveAmount;
}
}
}
I'm trying to digest this and wonder what is lifeTime in the amended code for the drag calculation? It is never initialized.
Also, shouldn't the drag calc use Time.deltaTime instead of Time.time?
Thanks.
Your answer
Follow this Question
Related Questions
Projectile collides, freezes, but flips to weird angle. Help! 0 Answers
OnCollisionEnter isn't working between two RigidBodies 1 Answer
Is it possible to get the physics engine to ignore calculating a rigidbody? 1 Answer
Rotating a Rigidbody with Physics 1 Answer
How do I connect multiple spheres using joints and make a character? 1 Answer