Writing in the front

I remember watching NBA for the first time in the summer of 1999, when I was on tour with the school team, living in a crappy hotel with a bunch of people around a black and white TV. I was young and couldn’t understand why the big brothers on the team were screaming and jumping up and down at a game. Remember the day the bulls played the 76ers, Jordan versus Iverson.

In 2002, Yao Ming was selected as the first overall pick of the NBA, and began to pay attention to the NBA, Yao Ming and the Houston Rockets. I really started watching Rockets games when I was in high school, novak’s winning streak, 22 straight wins, the magic spell of the playoffs, the memory of the whole high school, not the exam, not the school beauty, but the MOTOROLA hidden under a bunch of textbooks, 3G mobile phone portal NBA text broadcast, and the host of “BOOOOOOOM BABY!!” .

Ten years have passed. I haven’t had a chance to watch a complete game for a long time after work. I couldn’t believe it when I saw the news of Kobe leaving on wechat in the second year of the junior year.

It feels like the end of youth and an era.

Keep going

Because of the epidemic can not go out of the door, accidentally turned to a friend in kobe retired when the drawing



Popular illustrator: hibernating bears (lofter:xiangxdx.lofter.com/, weibo: weibo.com/u/217898786…)

So I want to write a simple shooting game to pay tribute, looking for a friend to paint a version of the material

That’s the game we’re going to play today:



The game theory

First let’s look at how physics games are developed

A physics game is made up of two parts:



Physics calculations usually require the use of off-the-shelf physics engines such as Box2d, p2.js, matter. Js, etc

Graphics can be rendered using a native canvas or the more powerful 2D rendering engines pixi.js, CreateJS, etc

Physics engines are usually only responsible for simulating physical motion calculations, not graphics rendering

This reduces the size of the package while allowing more flexibility to combine different rendering methods for game development

Using the physics engine alone, you can’t see anything in the interface

Physics engines are actually in the same category as tween.js, a library of commonly used slow functions

The basic concept

We chose a combination of MatterJS + PixiJS to implement the game

MattterJS: BRM. IO/matter – js /

Pixi. Js: pixijs. IO /

Refer to the official DEMO for the usage of the two libraries, which will not be described in detail here

Knowing a few basic concepts will get you started on game development

Matter will create a thing called World to simulate the physical World. Objects added to the World will have physical properties such as gravity, friction, collision and so on. These objects are called rigidbodies. Dynamic Body vs. Static Body

PIXI creates something called Stage, which is used for rendering graphics, and the entities are the Canvas nodes in the DOM, and the graphics that we add to the canvas are called sprites.

A physics game is a mapping from a physics engine (virtual environment) to a rendering engine (visual environment)



You need to make sure that the physics engine and rendering engine use the same coordinate system. Some physics engines (P2, for example) are different from the Pixi coordinate system. You need to perform global coordinate transformation first

To start developing

Initialize the physical environment and render environment

Var Engine = Matter.engine.create () var world = Engine.'canvas')
var App = new PIXI.Application({
    width: window.innerWidth,
    height: window.innerHeight,
    transparent: true}) var stage = app.stage // Render environment Canvas.appendChild (app.view) app.ticker.add ((delta) => {// update() // start the refresh});Copy the code

As mentioned above, physics engines are not usually responsible for rendering graphics, and Matter provides a simple renderer for debugging, allowing us to easily see the rigidbodies created by physics engines in wirefraction without having access to the rendering engine

var Render = Matter.Render
var render = Render.create({
  element: document.getElementById('physic'),
  engine: Engine,
  options: {
    width: window.innerWidth,    height: window.innerHeight
  }
})
Copy the code

Create a circular rigid body

Var body = Bodies. Circle (x, y, radius, {restitution: 0.6, // density:0.05, // firction: 1 // friction})Copy the code

Add to World

World.add(world, body)Copy the code

Start the engine and renderer

Matter.Engine.run(engine)
Matter.Render.run(render)Copy the code

Here we have completed the initialization of the physics and rendering engines and added our first round rigid-body DEMO to the physics world: codepen. IO/Guowc /pen/W…

Create a map

Create a basketball map with PIXI

var sprite = PIXI.Sprite.from('... ball.png'); Sprite.anchor. Set (.5) // Change anchor point to center position, convenient positioning stage.addchild (Sprite) // add map to render environmentCopy the code

The rigidbody is synchronized with the map

Synchronize the binding map with the rigidbody position and rotation Angle in the refresh

function update () {
    sprite.position.x = body.position.x
    sprite.position.y = body.position.y    
    sprite.rotation   = body.angle
}Copy the code

Once the synchronization is complete, you can remove the rigidbody test wireframes

var body = Bodies.circle(x, y, radius, {
    ...
    render: { visible: false} // Turn off wireframes})Copy the code



DEMO: codepen. IO/guowc/pen/G…

Create the basket

Although our material has a bit of perspective, we implement a 2D perspective, so the collision area of the basket only needs two static rigid bodies on the cross section

DEMO: codepen. IO/guowc/pen/y…

Note here that the basket is split into two parts so that the ball can pass through the middle of the basket



Add the nets

In Matter there are some preset complexes attached to Composites, such as Softbody, car, bridge, etc. We used Softbody to simulate the basket net

/ / parameter specification reference https://brm.io/matter-js/docs/classes/Composites.html var nets = Composites. The softBody (800, 240, 8, 5, 0, 0,false, 3.2, {firction: 1, frictionAir: 0.08, render: {visible:false },
    collisionFilter: { group: Body.nextGroup(true) }
}, {
    render: { lineWidth: 2, strokeStyle: "#fff"}, stiffness: 1.4})Copy the code

DEMO: codepen. IO/guowc/pen/r…

Launch the basketball

Set a linear velocity and angular velocity for the basketball

Body. SetVelocity (Body, {x: 1, y: -1}); SetAngularVelocity (Body, -0.1); // Set the angular speed so that the ball is slightly backspinCopy the code

DEMO: codepen. IO/guowc/pen/m…

Here is a simple 2D shooting game DEMO completed

Join the character

Next we use the skeleton system of animation software to make a shooting animation of Kobe Bryant

Specific animation production process here is not detailed, do relatively slag

Next, the PNG sequence diagram is exported

Pull into TexturePack to synthesize Sprite map, select PIXI frame format export, get a Sprite map and JSON configuration file

PIXI load Sprite map

App.loader.add('... /kobe.json').load(function(){
    const frames = [];

    for (leti = 1; i <= 37; i++) { const val = i < 10 ? ` 0${i}` : i;
        frames.push(PIXI.Texture.from(`kobe00${val}.png`)); } var Kobe = new PIXI.AnimatedSprite(frames); Kobe. AnimationSpeed = 0.4; Kobe.loop =false
})Copy the code

Play animations with Kobe. Play ()

The key problem

I met a problem when I wrote here. During the process from holding the ball to taking off, the basketball is an animation written with the palm of the hand, while after throwing it, it is a dynamic rigid body. How do these two parts connect?

I think of the plan is at the beginning, in the animation sequence does not include basketball, only a drop of action, to create a rigid body follow basketball shooting animation in the position of the palm, after trying to find it difficult to synchronize, the process of the ball is not a simple linear trajectory, shooting animations play speed and Tween control rate of basketball is not controllable

The second scheme is to complete the first half of the ball holding jump shot in the animation sequence, leave a blank frame at the moment the basketball is thrown, and create an identical rigid basketball body at the moment the basketball disappears, so as to realize the connection between the virtual and the real




The key code

Kobe. OnFrameChange = (e) => {// Animation frame callback, e is the current play frame indexif(e === 4) {var body = Bodies. Circle (...) World.add(world, body) Body.setVelocity(body, { x: 10, y: -10 }); // Create instant throw... }}Copy the code

The full version

Add some sound effects, subtitles, scores, and guidance to refine the interaction details

Github. IO /mamba/

The last

Heros comes and go, but legends are forever.