An overview of the

Games now seem to have become an unavoidable way of entertainment, from large-scale terminal games to mobile games, to page games, and then to H5 small games in various apps, it has invaded our life in various ways. So while enjoying the game, as a front-end developer, I also started to think about how to develop a game, what should it have in terms of technology?

In addition to basic game graphics, motion development, and rendering, one thing worth exploring is the physics engine. A good physics engine ensures that the in-game interaction experience is similar to that of the real world, providing a better experience.

Now there are a lot of good physics engines, most of them are out of the box, but the basic and underlying logic of the physics engine is what some people may not understand. Starting with this installment, we’ll cover the basics of the physics engine in several parts to give you a better understanding of it. The following is a partial reference from Game Physics Engine Development.

What is the engine

What is the engine? And of course this is extending the concept of the engine in the car. In a car, the engine, a device that converts energy into mechanical energy, is the core module for the car to move.

What is the corresponding engine in development? In my understanding, it is a core module that can quickly add one function after another into the project and ensure the operation of the function. Rendering engine, can quickly achieve content rendering. Game engine, can quickly achieve the basic development of a game. The physics engine, on the other hand, can quickly simulate real physics.

Now that we know what the engine is, we can focus on the features of the engine. The engine’s biggest characteristics are two – fast, versatile. It can quickly realize the required functions, and has a strong universality, it is not for a special business development, but for a broad category of development, so it must have a strong universality.

Fast means complete functionality, complete API packages, and easy to use. Generality means that the logic of the code itself needs to be low enough to apply the most basic logic to achieve maximum generality.

The foundation of the physics engine

What is the basis of a physics engine? That’s physics and mathematics. In fact, the representation of a physical system in the game is the position of each object in the whole physical system. Each frame needs to calculate the position of the objects so that they appear in the right place. So the mathematical operations that follow the laws of physics are the foundation of a physics engine. Everything that follows is based on this.

Math in Code

The first thing to look at is where math comes into play in the game world. In both two-dimensional and three-dimensional worlds, the position of objects is described by vectors. And vector processing, inevitably is the vector itself of some decomposition, addition and subtraction, dot product, vector product and other knowledge.

So let’s create a basic vector class:

class Vector {
  x: number
  y: number
  z: number
  constructor(x: number,y: number,z: number) {
      this.x = x
      this.y = y
      this.z = z
  }

  setX(x: number) {
    this.x = x
  }

  setY(y: number) {
    this.y = y
  }

  setZ(z: number) {
    this.z = z
  }
}
Copy the code

Vector decomposition, the application of trigonometric function content, a vector through the Angle of decomposition to the X axis, y axis, z axis, or according to the coordinates of different coaxial to calculate the corresponding Angle.

Trigonometric functions

I’m not going to elaborate on how vectors work. In the game world, everything is finally decomposed to the direction of the corresponding coordinate axis, even the dot product or the cross product. So as long as skilled use of trigonometric functions and vector calculation formula, can be vector processing.

We will add the following calculation method to the vector:

class VectorOperation {
  add (vectorA: Vector, vectorB: Vector) { // Add vectors
    return new Vector(
        vectorA.x + vectorB.x,
        vectorA.y + vectorB.y,
        vectorA.z + vectorB.z
    )
  }

  minus (vectorA: Vector, vectorB: Vector) { // Vector subtraction
    return new Vector(
        vectorA.x - vectorB.x,
        vectorA.y - vectorB.y,
        vectorA.z - vectorB.z
    )
  }

  multiply (vectorA: Vector, times: number) { // Vector scaling
    return new Vector(
        vectorA.x * times,
        vectorA.y * times,
        vectorA.z * times
    )
  }

  dotProduct (vectorA: Vector, vectorB: Vector) { // vector dot product
    return vectorA.x* vectorB.x + vectorA.y* vectorB.y + vectorA.z* vectorB.z
  }

  vectorProduct (vectorA: Vector, vectorB: Vector) { // cross product
    return new Vector(
      vectorA.y * vectorB.z - vectorA.z * vectorB.y,
      vectorA.z * vectorB.x - vectorA.x * vectorB.z,
      vectorA.x * vectorB.y - vectorA.y * vectorB.x,
      )
  }
}
Copy the code

In game physics, one of the most important mathematics is calculus.

I don’t think you’re going to understand this, but it’s basic physics, so why do you use differentials and integrals? For example, let’s look at the basic speed formula. We’ll start with average speed, which is the distance traveled divided by the time traveled:

V = s1 – s0t1 – t0v = \ frac {s_ {1} – s_ {0}} {t_ {1} – t_ {0}} v = t1 – t0s1 – s0 (average speed)

Then there is the calculation of the speed at a certain moment, which is actually to reduce the time difference to infinitesimal based on the average speed:

T – > 0 v = lim ⁡ Δ Δ Δ t = DSDTV = s \ lim_ {\ \ Delta t to 0} \ frac {\ Delta s} {t} \ Delta = \ frac {ds} {} dt v = lim Δ t – t Δ s = 0 Δ DTDS (speed)

Principle of differentiation

That’s where differentials come in. What about the application of integrals?

Let’s look at the most basic formula of speed and distance. In uniform motion, the formula is as follows, where T is the movement time:

S1 =s0+v0ts_{1} = s_{0} + v_{0}ts1=s0+v0t (uniform motion)

The essence of this formula should be:

S1 = s0 + ∫ t0t1v0dts_ {1} = s_ \ int_ {0} + {t_ {0}} ^ {t_ {1}} v_ {0} dts1 = s0 + ∫ t0t1v0dt (uniform motion)

This is just a simple example of how calculus works in games, and how it should work in code.

Physical basis

In a virtual world, if we want to have the same experience as the real world, we must also follow the physical laws of the real world, it is impossible to have apple flying in the sky. So let’s start by building an object that simulates the real world.

What properties should an object have in a physics engine? The most important information is the position information mentioned above, and the corresponding information is the information of changing position, that is, the speed. And that leads to a value, which is the information that changes the velocity, which is the acceleration. On this basis, we can obtain a most basic object should have properties:

class GameObj {
  pos: Vector
  velocity: Vector
  acceleration: Vector

  constructor(pos? : Vector, velocity? : Vector, acceleration? : Vector) {
      this.pos = pos || new Vector(0.0.0)
      this.velocity = velocity || new Vector(0.0.0)
      this.acceleration = acceleration || new Vector(0.0.0)
  }

  setPos (pos: Vector) {
    this.pos = pos
  }

  setVelocity (velocity: Vector) {
    this.velocity = velocity
  }

  setAcceleration (acceleration: Vector) {
    this.acceleration = acceleration
  }
}
Copy the code

We now have the most basic object, and in order for this object to be integrated into the physical system and manipulated by us, we need to combine the object with a force. And combining the two, it’s Newton’s three laws.

The first is Newton’s second law, which states that force can change the motion of an object. It can be expressed in a simple formula:

F⃗=ma⃗\vec F =m \vec aF =ma (Newton’s Second Law)

That is to say, if we want to combine acceleration and force, we need to give the object a variable, which is the mass m. Add a quality attribute to the above object:

class GameObj {
  mess: number // The quality must not be 0

  constructor(mess? :number) {
    if (mess > 0) {
      this.mess = mess
    }
  }

  setMess (mess: number) {
    if (mess > 0) {
      this.mess = mess
    }
  }
}
Copy the code

However, there are two problems: first, the mass of the object can not be 0, if 0 is set, it will cause the mass setting error; Second, certain objects that we need to have infinite mass, like floors and walls, we need to have them fixed in the game scene. What about zero, which is not allowed on the one hand, and infinity, which is hard to set on the other?

A concept in game physics called inverse mass solves this problem neatly. The inverse mass is actually the inverse of the mass, 1m\frac{1}{m}m1, so we can make the mass infinite by setting the inverse mass of the object that needs to be fixed to 0, and avoiding the mass setting to 0.

class GameObj {
  inverseMess: number // The quality must not be 0

  constructor(inverseMess? :number) {
    if (inverseMess >= 0) {
      this.inverseMess = inverseMess
    }
  }

  setInverseMess (inverseMess: number) {
    if (inverseMess >= 0) {
      this.inverseMess = inverseMess
    }
  }
}
Copy the code

conclusion

At this point, the basic mathematics and physics we need have been successfully injected into the physics engine, but this is only the foundation of a physics engine, on which we have to add all kinds of things like gravity, resistance, momentum, angular momentum, collisions and so on. There’s a long way to go, and I’ll show it in this series.