We can do this:
position = initial_position + velocity * t + 0.5 * acceleration * t * t;
First remember that there could be collisions. We need to detect and solve collisions. Perhaps we do, we solve the collision by picking a new
velocity for the object.
Second remember that not every object that has physical interaction follows the laws of motion. Yeah, I know, you use the formula for those which do. The issue is that there are motions that the physics engine cannot predict.
Let us take the simple example of the game asteroids. The user steers and accelerate the avatar ship. We are not only talking about an acceleration that change over time, we are talking about an acceleration that change over time in an unpredictable manner (it depends on user input). In this case you will need to compute the position of the avatar ship each frame.
That means that you will have two different pipelines for physics. One for things that the user controls or triggers, and one for thing that it does not.
For another example, platformers have some interesting challenges. Let us say, it is a bad platformer, where you cannot control the avatar midair. So, in the air, it behave as an object beyond user control, but on land it can walk, the user has control over its speed. Now you got an object that switches gears.
How about enemy agents? Perhaps we can push them as per physics, but they will move according to some form of AI. Therefore the physics engine cannot predict their motion, which means we will need the physics we created for player controlled things.
Would it not be better to have a single physics pipeline instead of two? Well, the one that is used for the player controlled things is more versatile. That one wins. So, we compute at increments, frame by frame.
Perhaps you want something like this:
position = position + velocity * dt + 0.5 * old_acceleration * dt * dt;
acceleration = compute_acceleration();
velocity = velocity + 0.5 * (old_acceleration + acceleration) * dt;
old_acceleration = acceleration;
That is a variant of Second Order Verlet Integration known as Velocity Verlet (it is similar to leapfrog integration). And, yes, some games use it. It is better than Euler integration. Many people recommended, usually it is all you need.
With that said, Velocity Verlet will have stability problems (it will drift when dt is not stable). A variant known as Time Adjusted Velocity Verlet is used to compensate for that problem. However, depending on the simulation, objects simulated with can seem to lose energy (which is hidden if you are doing drag or friction too).
- With Euler integration objects can gain energy. Which is worse.
- It is possible to make a Time Adjusted Euler Integration to be stable for common use, and it behave better than Time Adjusted Velocity Verlet in some situations.
- The Velocity Verlet algorithm assumes that acceleration depends on the updated position, but not the velocity.
There are algorithms with better properties in exchange of more computing time. Although that trade-off is less relevant for modern computers, it still is (in particular for the higher frame rates and large numbers of objects).
That is why different games use different integration methods. Being Euler and Velocity Verlet among the more popular.
This discussion often leads to Fourth order Runge-Kutta (RK4). It is more CPU expensive, and harder to understand and implement.
I will refer you to Physics for Flash Games by Richard Lord for a comparison of the common implementations.
See also Ilmari Karonen answer on How can I implement gravity?.