 # How does Cocos achieve smooth projectile projectiles? Starting from the derivation of the formula, the practice and application of projectile motion are explained in detail

## Introduction

There are often projectile motion effects similar to projectile launching and shooting in games. “Cocos Star Writer” Chen Pippi will deduce the formula of projectile motion in this article and apply it to achieve various interesting game effects.

Let me show you what we want to achieve:

Fixed angle and speed

Fixed angle

Fixed speed

Unfixed angle and speed

online preview:

Cocos Creator | Projectile

Projectile motion often occurs in our daily life, such as the movement of a basketball in the air after a basketball player shoots. Projectile movement can also be seen in various video games, such as the movement of shells in the air after a tank shoots in World of Tanks.

As you can see, the title of this article is “The Practice of Projectile Movement in Game Development,” We will work together to derive various formulas for projectile movement and apply these formulas in the game to achieve various interesting functions.

• Object Interaction and Raycasting in 3D Games
• Dot and Cross Product of Vectors in 3D Space (Linear Algebra)
• Calculation of projection of a vector on a plane in three-dimensional space
• Directional Angle Calculation of Vectors in 3D space
• Real-time pre-drawn projectile trajectory

## Example project

To avoid the article from being tedious and lengthy, some features in the project are not introduced in the article. At the same time, I will integrate the project code and insert it into the article so that the actual project structure will be slightly different from the code and the article.

Cocos Store: 炮弹抛射 | Cocos Store

The game engine used in this project is Cocos Creator 3.4.2.

## Scene construction

Let’s have a relaxing and pleasant experience of building blocks.

### Surroundings

Quickly build a simple scene and place some colorful obstacles (or platforms) of varying heights.

Remember to add proper Colliders to these things so we can interact with them via rays. Actually, it took most of the day to adjust the size and color of various shapes…

## Cannon

Assembled a cannon (Cannon) using a few basic shapes built-in; even though it looks like a flashlight ( ), I’d rather call it a cannon!

Cannon

Large flashlight I really tried my best, it took me a long time, but it’s actually quite pleasing to the eye after watching it for a long time…

Briefly introduce several key components of this cannon:

The yaw axis allows the gun body to rotate left and right (Yaw Axis) Cannon’s yaw axis

Pitch Axis that allows the barrel to be adjusted up and down Cannon’s Elevation Axis

Fire Point that determines the position and direction of the projectile’s firing

Cannonball firing point

### Cannonball

Make a simple cannonball (Bullet) using the built-in sphere and save it as a separate prefab.

And add a Sphere Collider and RigidBody components to the projectile so that the projectile can have physics.

Another thing to note is that the default value of the Linear Damping item of the rigid body component is 0.1. We need to set it to 0; otherwise, the shell will automatically slow down when flying.

Cannonball

### Basic function

Implement some basic functions with code.

Aim and shoot

• Cannon

Create a `Cannon` to implement the various functions of the cannon.

Let’s first implement the functions of “Aim” and “Shoot”:

Basic functions of the cannon

Currently, only the pitch angle update is implemented in the aiming function of the cannon.

• GameController

Create `GameController` a to implement the game’s control logic.

Implement the logic of “click the mouse to fire a shell”:

Game Controller Running effect:

Click the mouse to fire cannonballs

Left and right

At present, this cannon can only shoot in a fixed direction. It’s stupid. Let’s control the left and right orientation of the cannon according to the clicked position.

• Click Interaction and Raycasting

Let’s first briefly understand how to specify the target position of the cannon by tapping the screen.

Generally, in 2D games, if you want to interact with objects in the two-dimensional world through a mouse or a touch screen, you only need to use two-dimensional coordinates on a screen to determine whether to “hit” the object.

In 3D games, if you want to interact with objects in the three-dimensional world, you need to use “Raycast” to achieve it.

Simply put, it is to emit a ray (Ray) from the Near Plane of the camera (Camera). The ray length is equal to the distance from the near clipping plane to the far clipping plane (Far Plane). This ray is related to the object in the scene. Do an intersect operation; if it intersects, it counts as hitting the object.

ray casting

Most game engines provide the ability to “create rays from 2D coordinates in screen space” on the camera. For example, the Camera component of Cocos Creator provides `screenPointToRay ` functions.

The specific click function is straightforward to implement:

Code for ray casting

It should be noted that objects in the scene must have any type of Collider to participate in ray detection.

look directly at the target

Now we can get a target position, but in most cases, our target position is not on the same level as the gun body. If we let the node of the gun body look directly at the target position, we will get an abnormal performance.

Also, I sneakily made a simple cursor (white arrow and crosshair) to highlight the current target location.

The cannon looks directly at the target location

Note: In Cocos Creator 3.4.2, the front of the node points in the z-direction, so now the cannon’s butt is looking at the target node.

yaw angle

In fact, we only want to change the left and right orientation of the gun body. The “left and right orientation” mentioned here has a more professional term called “Yaw.”

Yaw

Yaw describes the movement of an object based on its yaw axis (usually the y-axis in the object’s coordinate system in game development), changing the direction it is pointing to the left or right of its direction of motion. Yaw (Wikipedia)

Note: In rotation, in addition to “Yaw,” “Pitch” and “Roll” are usually accompanied by “Pitch” and “Roll,” which respectively describe the motion based on the other two main axes.

To make the cannon face the specified position, all we need to change is the yaw angle of the gun body. The correct way is:

1. Create a direction vector pointing from the yaw axis node position of the gun body to the target position

2. Project this direction vector onto the horizontal plane where the yaw axis node is located

3. Calculate the angle between the direction vector and the forward vector of the cannon by " Vector Dot Product."

Yaw angle

Note: “Yaw axis node” is the child node of the cannon, and it carries all the nodes of the gun body. Changing the yaw angle of the yaw axis node can change the direction of the gun body.

“lost direction”

Hold on, the value obtained by calculating the included angle through the vector dot product is always between 0 and 180 degrees, which means that the dot product can tell you the minimum angle between two vectors but cannot tell you that one vector is in another vector—left or right, because “45 degrees left” and “45 degrees right” are both “45 degrees” for dot product. Vector dot product (Wikipedia)

For example, the angle between the two purple vectors and the blue vector in the following figure is 45 degrees, but they are on both sides of the blue vector:

Angles of the same degree but in different directions

Directed angle

But in the game engine, the valid range of rotation of an object is 0~360, or -180~180 degrees (we all know “90 degrees left” and “-90 degrees right”, and “270 degrees right” means the same).

In the final analysis, we just need an included angle with a positive and negative sign, " Directed Angle . "

When we mention “direction,” developers who are good at linear algebra can quickly think that we can use " vector cross product " to determine whether a vector is on the left or right of another vector. Vector cross product (Wikipedia)

In addition, the calculation of the directed angle of the vector in the three-dimensional space requires a reference plane to make sense.

Specific calculation steps:

1. Project two vectors onto the same reference plane
2. Find the normal vector of two vectors by the cross product
3. The direction is obtained by the projection length of the normal vector on the reference plane normal vector
4. Calculate the angle between two vectors using a dot product
5. Apply direction to included angle (symbol)

function to calculate the directed angle

For the function “projecting a vector onto a plane”:

function to project a vector onto a plane

Note: In the 3D world, using a direction vector as a plane normal can represent a class of planes facing the same because “plane normal” means that the direction vector must be perpendicular to the plane it represents.

Code Practice

Having solved the problem of yaw angle, the cannon is now given the code “towards the target position”:

Aiming function of the cannon

Note: The rotation of nodes in Cocos Creator 3.4.2 conforms to the right-hand rule. That is, the counterclockwise direction is the positive direction.

Then implement the logic `GameController` of “move the mouse to control the cannon aiming” in :

Game Controller Phased achievements: The orientation of the cannon

### Shooting mode

Now our cannon can follow the mouse to rotate 360 ​​degrees and fire projectiles, but the pitch angle and speed of projectile firing are fixed, which doesn’t seem to achieve all we need.

And our expectation is: that given a target position, the cannon can calculate the firing angle and velocity by itself.

For this goal, we can design three different modes:

• Fixed launch angle dynamically calculates the initial velocity of the shell
• Set the initial speed of the shell and dynamically calculate the launch angle
• Dynamic calculation of firing angle and initial velocity of shells

In addition to the current mode of “fixing the launch angle and the initial velocity of the shell,” we have a total of 4 methods.

Next, we will implement them one by one.

Fixed angle and speed

Due to the new concept of patterns, to make the subsequent coding more convenient and elegant, we slightly adjusted the current code structure.

Calculate the firing angle and velocity of the projectile based on the mode in the `Cannon` component’s function: `aim`

Aiming function of the cannon

## Projectile movement

Although there have been so many lot already said, it seems to have nothing to do with projectile movement.

### basic introduction

Projectile motion is the motion of an object thrown at an initial velocity under the action of the earth’s gravity.

Projectile motion can be divided into horizontal motion and oblique motion:

• Horizontal Projectile Motion: The angle between the outgoing direction of the object and the horizontal plane is 0, so the object only has an initial velocity in the horizontal direction (it can also be regarded as an initial velocity of 0 in the vertical direction).

flat throw

• Oblique Projectile Motion: The exit direction of the object has a certain angle with the horizontal plane, so the object not only has an initial velocity in the horizontal direction but also has an initial velocity in the vertical direction.

oblique throwing movement

Under normal circumstances, when we refer to projectile motion, we refer to oblique motion because oblique motion is “compatible” with flat motion~

In addition, projectile motion is often referred to as “parabolic motion,” which I think is a more convenient name.

### basic formula Welcome to the main pre-quest!

Before diving in, let’s learn (review) some simple prerequisites.

First, let’s get to know the members that will appear in the various formulas:

• s - Displacement
• x - Horizontal Displacement
• y - Vertical Displacement
• h - Max Height
• θ - Initial Angle
• v - Initial Velocity
• t - Time (Time)
• g- Gravitational Acceleration

Note: We default to the initial speed as directional, corresponding to the initial angle θ.

Note Standard gravitational acceleration is 9.80665, but in-game engines usually default to 9.8 or 10. The default value of gravitational acceleration in Cocos Creator 3.4.2 is 10.

Note: The projectile motions discussed in this article are “ideal projectile motions.”

free fall displacement formula

Calculating the displacement is when the object is only affected by gravity. free fall displacement formula

Horizontal displacement formula

In projectile motion, the object is only affected by its initial velocity in the horizontal direction.

That is to say, the horizontal velocity of the object is always equal to the horizontal component of the initial velocity, i.e., .θ Horizontal displacement formula

Note: In calculating horizontal displacement, we take “right” as the positive direction.

Vertical displacement formula

In projectile motion, the object is affected by initial velocity and gravitational acceleration in the vertical direction.

That is to say; the object has two vertical displacements at the same time:

Displacement is affected by the vertical component of the initial velocity

Free Fall Displacement Affected by Gravity Verticle displacement formula

Note: We take “up” as the positive direction in the calculation of the vertical displacement, so the free fall displacement is a negative value. Welcome to the main quest!

### Fixed angle

Now let’s implement the second mode: fix a firing angle and dynamically calculate the initial velocity of the shell based on the target position.

In this mode, the firing angle of the cannon is fixed and given a target point in three-dimensional space. We need to calculate the initial velocity of the projectile firing.

Calculate the horizontal and vertical displacement

With the position of the target point, and we already know the position of the launch point, we can calculate the horizontal and vertical displacement from the launch point to the target point.

Displacement of projectile motion

After projecting both points on the same horizontal plane, the distance between the two points is the horizontal distance; and the difference between the y-values ​​between the emission point and the target point is their vertical distance.

displacement

The actual calculation process is as follows:

1. Use vector subtraction to get the direction vector from the launch point to the target point
2. The y value of the direction vector is the vertical distance
3. After projecting the direction vector onto the horizontal plane, its length is the horizontal distance

function to calculate displacement

Note: In game development, the easiest way to represent a horizontal plane is to use a direction vector with a vertically upward direction as the plane normal, such as a direction vector with a value of `{ x: 0, y: 1, z: 0 }` .

Note: In Cocos Creator 3.4.2 `Vec3.UP` = `new Vec3(0, 1, 0)` .

initial velocity formula

Ahem, back to the topic.

Take a look at the information we have now:

• Horizontal displacement (x)
• Vertical displacement (y)
• initial angle (θ)

And what we want to ask for is:

• Initial speed (v)

Taking another look at the “horizontal displacement formula” and “vertical displacement formula” above, we seem to be missing a key piece of information:

• time (t)

No problem! We can try to eliminate this time term ( ).

First, we can easily get the “horizontal displacement time formula” from the “horizontal displacement formula”: Then substitute this “horizontal displacement time formula” into the “vertical displacement formula”: Good, the time (t) has been successfully eliminated, and a new vertical displacement formula has been obtained. In order to distinguish it, we will name it “Vertical Displacement Formula 2”.

Finally, we try the initial velocity term (v) again in the “isolated” formula:  Boom!

That’s right! This is the initial velocity formula we want!

Code Practice

Now, let’s turn the formula into code:

function to calculate the initial velocity

Note: For some cases that cannot be calculated, the validity judgment is added to the code.

The cannon calculates the initial velocity based on the target position when aiming:

Aiming function of the cannon Phased achievements: Fixed angle mode for cannons

### fixed speed

In the third section: the initial velocity of the shell is fixed, and the firing angle is dynamically calculated according to the target position.

In this mode, the initial velocity of the projectile fired by the cannon is fixed. Given a target point in three-dimensional space, we need to calculate the firing angle.

initial velocity formula

In the derivation of the “speed formula,” we got a “vertical displacement formula 2” without a time term (t). Here, we can use this formula to derive the angle formula directly. Vertical displacement formula

Hold on, now we’re asking for the initial angle ( θ), and in “Vertical Displacement Equation 2” both tan θ and are cos θ^2 here. That’s not good.

But the good news is that we can directly set cos θ^2 by replacing it with (since they are equal), which should help us reduce some of the difficulties. The new formula seems to be more complicated. Let’s try it out: Here you can move the item to the left of the equals sign to the right: Hey, the formula seems to conform to the characteristics of " Quadratic Equation , "so let’s sort it out a little: Hey, isn’t this just a quadratic equation in one variable! We can map several parts of the formula one by one: This is easy to handle. We can directly use the " formula method " to solve the quadratic equation in one variable.

This is the " root formula " of a quadratic equation in one variable : Substitute the unknown term, quadratic term coefficient, linear term coefficient, and constant term into the root-finding formula:  Bingo!

I finally got the “initial angle formula”!

However, it is important to note that this formula has at most two solutions. Quadratic Equation

An integer equation that contains only one unknown (unary) and the highest degree of the unknown term is 2 (quadratic) is called a quadratic equation in one variable.

Quadratic equations in one variable can be sorted into general forms. Among them is called the quadratic term, which is the coefficient of the quadratic term; the first-order term, the coefficient of the first-order term; and the constant term.

Code Practice

Turn the formula into code:

function to calculate the initial angle

Note: For some cases that cannot be calculated, the validity judgment is added to the code.

The cannon calculates the initial angle based on the target position when aiming.

Aiming function of the cannon

For the case of obtaining two results, we can directly choose the larger angle. You can also choose different angles according to the specific situation.

If no valid results can be obtained, it means that no matter what angle is used to launch the cannonball, the cannonball cannot reach the target position. In this case, we can choose to maintain the current angle. Phased achievements: Fixed Speed ​​Mode for Cannons

### Unfixed angle and speed

Previously, we implemented the solutions of fixed angle and fixed speed, respectively, which are all very good, but they don’t feel very flexible.

How is it flexible? I don’t want the cannon fixed at a certain angle or speed. I want freedom, and I don’t care about anything else!

Then we will implement the fourth mode: specify a target position and dynamically calculate the launch angle and the shell’s initial speed.

Situation Analysis

Information we have:

• Horizontal displacement (x)
• Vertical displacement (y)

What we require is:

• Initial angle ( θ)
• Initial speed (v)

Remember the “Vertical Displacement Formula” from the beginning? The one with the time term (t). There are a total of 5 items in a formula, 3 of which are unknown. This isn’t good…

It seems that another way has to be found.

maximum height formula

We all know that the throwing motion can be mainly divided into two stages. The first is the ascending stage, after reaching a maximum height, then the descending stage.

If we can determine the maximum height, is there a certain room for manipulation? When does the object reach its maximum height? The answer is when the object no longer continues to rise (the end of the ascent phase and before the start of the descent phase). That is, the vertical velocity of the object is 0 at this moment.

Maximum height of projectile motion

As we mentioned earlier, in the oblique throwing motion, the vertical displacement is affected by two velocities:

• The vertical component of initial velocity (vertically up)
• Velocity is given by gravity (vertical downwards)

When the vertical velocity of an object is 0, it means that the “vertical component of the initial velocity” is equal to the “gravity imparted velocity”: From the above formula, we can get the time formula when the object reaches the maximum height , we call it the “maximum height time formula”: We substitute the “maximum altitude time formula” into the “vertical displacement formula” and eliminate the time term (t) again: So we get the “maximum height formula.”

Initial angle formula 2

According to the “maximum height formula,” we can get the “initial angle formula 2” with the maximum height term (h) and the initial velocity term (v): #### >Initial Velocity Formula 2

And “Initial Velocity Formula 2” with maximum height term (h) and initial angle term (θ): Woohoo, buy one get two free, very cost-effective!

Don’t be too happy. Our problem is still not solved…

Judging from the existing formulas, the initial angle and initial speed must be calculated first before the other can be calculated, which is embarrassing.

Time formula

When we were at a loss, our old friend “Vertical Displacement Formula” suddenly visited:  It says: In this case, we can try to eliminate the items and minimize the unknown things in the formula, just like playing the game. I said: Good! Who doesn’t like to play matchmaking!

This substitutes the “Initial Velocity Formula 2” just obtained into the “Vertical Displacement Formula”: At this time, we found that this formula also seems to satisfy the characteristics of a “one-dimensional quadratic equation”: Remember the general form of a quadratic equation in one variable: Match several parts of the formula one by one: Or the formula for finding the root of a quadratic equation in one variable: Substitute the unknown term, quadratic term coefficient, linear term coefficient, and constant term into the root-finding formula:  Great!

Now we can find the total time (t) for the object to travel from the starting point to the destination point.

Initial angle formula 3

Things have changed, so let’s sort out the information we have now:

• Horizontal displacement (x)
• Vertical displacement (y)
• Maximum height (h)
• Time (t)

What we require is still:

initial angle ( θ)
Initial speed (v)

Repeat the old tricks. Eliminate the problem!

This time we invite the “horizontal displacement formula”: Substitute “Initial Velocity Formula 2” into it and try:  Excellent!

Now we can use the maximum height (h) and time (t) to find the initial angle (θ)!

Key formula

Huh, so many formulas are really overwhelming. Let’s take out the useful ones first.

Use the “time formula” to calculate the time (t): Use “Initial Angle Formula 3” to calculate the initial angle (θ): Use “Initial Velocity Formula 2” to calculate the initial velocity (v): Code Practice Mathematics is really “fascinating.”

Finally can write code.

Functions for calculating angle and velocity

The cannon calculates the initial angle and initial velocity based on the target position when aiming.

Aiming function of the cannon

In the `calculateAngleAndVelocity` function, we set the maximum height as `1` . Let’s take a look at the actual effect first: Cannon Free Mode 1 There still seems to be a bit of a problem though, when we position the target above the orange column, which means the vertical distance between the target point and the firing point is greater than the maximum height we’re given, the cannon shoot onto it.

We can fix this. The maximum height we define is based on the launch point. When the maximum height is less than the vertical distance between the target point and the launch point, the shell will definitely not reach the target point.

In addition, the maximum height must not be less than 0. Because the height of the launch point is 0, how can the maximum height be smaller than the height of the launch point?

Therefore, it is best not to fix the maximum height. Since we can directly find the vertical distance and horizontal distance of the target point of the launch point, why not calculate a suitable maximum height based on these two data?

Dynamic calculation of maximum height Try it again: Cannon Freemode 2 Perfect!

So far, we have successfully realized various shooting functions of the cannon!

### Shell trajectory It’s not over yet!

When we know the projectile’s launch point, target point, initial angle, and initial velocity, we can also draw the projectile’s trajectory.

like this: draw ballistics

Isn’t it great!

### track point generation

Compared with the previous content, this implementation is straightforward, directly on the formula: Yep, still them.

According to the “horizontal displacement formula” and “vertical displacement formula,” we can calculate the horizontal and vertical displacements at any time during the projectile’s movement.

A function to calculate the displacement at a specified time

According to the “horizontal displacement time formula,” we can calculate the total time of the projectile from the launch point to the target point.

Function to calculate the total time

We generate several trajectory points, calculate the time interval between trajectory points according to the total time of movement, traverse all trajectory points, calculate the displacement at the corresponding moment of each trajectory point, and finally set the position of the trajectory point.

Function to draw ballistics 1

I used a small white cuboid as the track point here. After batch processing is enabled, only one Drawcall is needed to draw the entire track, and there is no need to worry about performance issues. Check out the effect: Draw ballistic 1

It can be seen that the generated trajectory is basically correct, but there are still two problems to be solved.

### Number of track points

The first problem is that the number of trajectory points is fixed, and the farther the target point is from the launch point, the more distant the interval between the trajectory points is, which is very sparse and not very beautiful.

For this problem, we can decide the number of trajectory points according to the horizontal distance between the target and launch points.

Function to draw ballistics 2 Effects: Draw Ballistics 2

For the situation where the number of trajectory points is not fixed and changes frequently, it is recommended to use a Node Pool to optimize runtime performance and avoid creating and destroying a large number of nodes frequently.

### Track point rotation

Another problem is that although the position of each track point is correct, their rotation does not change, which looks weird.

In fact, at every moment in the projectile’s motion, the object’s direction of motion changes. So we hope that the orientation of each trajectory point should also correspond to the direction of movement at its corresponding moment.

Instantaneous motion angle of projectile motion

We mentioned at the beginning that the horizontal velocity of the object in the motion of the projectile is always equal to the horizontal component of the initial velocity, and the formula can be obtained: The vertical velocity of the object is equal to the vertical component of the initial velocity (vertically upward) minus the velocity given by gravity (vertically downward), and the formula can be obtained: With the velocity components in the horizontal and vertical directions, the direction of the actual velocity can be found: Turn the formula into code:

A function to calculate the instantaneous angle of motion

Good, now we can calculate the angle of motion at any time, so how do we apply this angle to objects in three-dimensional space?

In three-dimensional space, the order is very important for rotations between different axes, and different orders will give very different results.

In our case, we need to orient the trajectory point “towards” the target (yaw angle) before applying the instantaneous velocity direction (pitch angle).

In-game development, we can use quaternions to achieve multiple rotations:

1. Generate quaternions based on forwarding and up vectors
2. Apply pitch angle based on x-axis rotation

Actual code:

Function to draw ballistics 3 Final effect: draw ballistics 3 Wonderful!

## Aim cursor

Finally, we append a minor feature to the cursor.

This article briefly introduces how to obtain the three-dimensional world coordinates of screen clicks through ray casting in the “Click Interaction and Ray Casting” section.

In addition to the coordinates of the hit point, the result returned by ray casting also includes the normal of the hit surface .

We can use this normal as the direct up direction of the cursor so that the cursor is always perpendicular to the surface where the hit point is.

The cursor is perpendicular to the surface of the object

### Adapt to the target surface

But only a normal can’t determine the rotation of an object!

A three-dimensional Cartesian coordinate system has three mutually perpendicular axis vectors, and at least two mutually perpendicular vectors are required to construct a three-dimensional Cartesian coordinate system (the third axis can be obtained by vector cross product). So, we also need to find a vector that is perpendicular to the normal of the target surface. In theory, a vector has an infinite number of vectors that are perpendicular to it. How can this be adjusted?

Just when I was burying my head in work, I came up with a very tricky plan on a whim:

1. Generate a direction vector using the target position and the cannon position
2. Projects the direction vector onto the plane represented by the target face normal
3. After normalization, a unit vector perpendicular to the normal of the target surface is obtained
4. The object’s rotation can be determined by the unit vector and the normal of the target surface.

Quickly implement it with code:

Function to set the cursor Check out the effect:

Cursor’s fit to surface mode (cross)

Our cursor will always be perpendicular to the object’s surface, and the front of the cursor will be as far in front of the cannon as possible. After replacing the crosshair with a circle, there is no sense of issue on surfaces:  Tsk tsk tsk, I’m such a clever little dev~

The text is here. I don’t know how to summarize it. If you don’t understand it, just read it again~ ## References

Projectile motion

Projectile motion - Wikipedia