Near the end of the year, I made an H5 activity page in the form of a game, and tried to write a small game with JS for the first time. It was a very interesting process and valuable experience.

rendering

Direct last effect GIF, a small part of the game effect, recorded out of the point card

The results page:

The cause of

Product sister suddenly pulled me in a group, told us to do so long production platform (users make mobile phone theme platform), we should give feedback to the user point something, like before the special fire wechat year-end summary. It’s all about impressing people and being really cool. She turned and smiled at me when she said it was so cool, and there was a little bit of, um, killing in that smile. The form of the activity, the way of presentation, what the data was just not worked out, the whole process was hotly discussed. At that time I do not know why the brain a heat, said to her: “nothing, do it, you can think out I will give you to do.” And I got myself in hot water for saying that. The result of the discussion is that everyone’s idea is not particularly cool, and not fun, just make a game form! Everyone turned to look at me, and I thought about what I had said. All I could say was, “Fuck.” “Games? Interesting? Make! Never had sex? Can you handle it? Make!” . Finally finalized, two weeks, game mode, show users in the magic show dribs and drabs.

The preparatory work

The form of the game is probably similar to a combination of skiing adventure and racing car, pseudo 3D effect display in the form of racing car, skiing adventure style as our theme, at the same time we gave our game a cool name —- magic show time path.

The game engine

After the presentation form of the game was determined, my intuition told me that I needed a JS game engine in order to present the game quickly and stably without complicated processing such as image loading control and animation control. Finally, I selected PixiJS from EgretPhaserPixiJS. Although it does not have complete Chinese documents like Egret, it provides clear and easy to understand examples for quick use. There is no complex ecology, and a few lines of simple code can be used to achieve the following functions:

Container rendering and background rendering

I need to customize the size and background of the entire canvas, I need to use different containers to hold different content, and have flexible control over the properties of each container:



/ / the canvas
var app = new PIXI.Application(800.600, {backgroundColor : 0x1099bb});
document.body.appendChild(app.view);

/ / custom container
var container = new PIXI.Container();

container.x = (app.renderer.width - container.width) / 2;
container.y = (app.renderer.height - container.height) / 2;

app.stage.addChild(container);Copy the code

Image loading and animation processing

As we all know, when using Canvas to draw pictures, we need to make sure that the pictures have been loaded successfully, and there are a lot of picture resources in the game that need to be maintained. PixiJS has provided us with this service:



var bunny = PIXI.Sprite.fromImage('the required/assets/basics/bunny. PNG'); bunny.x = app.renderer.width / 2; bunny.y = app.renderer.height / 2; app.stage.addChild(bunny);Copy the code

At the same time, we need an animation controller to control the movement and redraw of each Sprite, rather than simply reworking the properties:



app.ticker.add(function(delta) {
  bunny.rotation += 0.1 * delta;
});Copy the code

Note that the Sprite animation controls add moving animation queues and implement transformJs-like operations on instance properties. When I was writing the project, the official example was to animate the frame with a unified animate function, and to animate the frame with a requestAnimationFrame.



function animate (a) {
  requestAnimationFrame(animate);
  
  bunny.rotation += 1;
  renderer.render(stage);
}Copy the code

The event processing

The most important part of the game is the user interaction, which is called event handling. Adding event listeners to Sprite is as simple as this:



// The element is clickable
sprite.interactive = true;

// Move cursor over cursor
sprite.buttonMode = true;

sprite.on('click', onClick); // mouse-only
prite.on('tap', onClick); // touch-only

function onClick (a) {
  sprite.scale.x *= 1.25;
  sprite.scale.y *= 1.25;
}Copy the code

The design

The blueprints were important, of course, in how we implemented the game, and when I got the blueprints and they looked like this, I was devastated inside. What can I do, I also very helpless ah ~ do it!

Implementation approach

According to the above, PixiJS has basically met our needs, that is to say, tool preparation and material preparation have been completed. Before starting to write, we need to have a good idea of implementation to ensure that the writing process is clear and avoid unnecessary trouble.

Background sliding effect implemented

Like we usually play racing games, we feel the car on the track for the game, in fact the car only to move around, and the movement is background, how to plan a good course, let the background according to the given scenario to sports, and show a different perspective, specifically to the epicenter of beautiful compatriots consulted, they are with a man named “camera”. For us, there is no need for such a complex scene, just let the background like the previous regular “translation”, resulting in the visual effect of “tree moving, I do not move”. At the same time, we use the principle of “perspective”, let the background change in the way of “near big far small”, will produce a low low three-dimensional effect.

Key words: perspective near big far small (offset, size, speed)

Migration routes

For the background and object movement, the general route planning is as follows:

After determining the visual focus, we only need to randomly generate the position of the object, calculate that A and B are relatively fixed, so that y can increase the corresponding speed, and X can be offset according to the movement track, then the effect of running closer can be realized. For the motion trajectory, assuming that the downward offset distance of the object is N, then the corresponding horizontal offset against the central axis is:

The size of the

At the same time, we also need to display objects near large and far small, this is relatively simple, focus is 0, the bottom of the page is 1, the corresponding scale can be enlarged:



scale = (curY - startY) / ( endY - startY);Copy the code

Movement speed

For the speed of motion of objects, there should also be different manifestations in the near and far.

Difference between background tree and colliding object

For the background tree, we need to display all the trees initially, covering both sides of the background. Each column of tree has the same movement path, so it can be displayed in a loop directly. When the tree moves to the bottom, it can appear at the top. So you just need to determine how many rows and columns there are in the tree, set its boundaries, determine its initial uniqueness based on the rows and move it. At the same time, the tree can carry out a small range of random offset, so that the tree is well-proportioned. As follows:



export default function Tree (row, col, direction) {
  this.cfg = {
    direction: direction, / / direction
    col: col, / / which columns
    row: row, / / how many rows
    MaxX: 440,
    minY: 210,
    maxY: 500,
    range: 10 // Coordinate floating range}};Copy the code

For the object, it is necessary to generate its initial X coordinate randomly, and calculate its movement route. In the process of movement, collision detection is carried out to detect whether it colliders with people.

Character sliding implementation

Figure sliding operation, with the simplest way to achieve: button. When the user clicks on a different direction, the character is offset in the corresponding direction. At the same time, in order to keep the characters from sliding stiffly, people should also tilt at the corresponding Angle with the movement in the process of sliding left and right, just as we usually change the center when we turn a corner while skiing. Here’s the idea:

  1. Change direction when you click the button

  2. When moving, detect the direction, if left, then x decreases, to the right, then increase

  3. The character also increases (decreases) the rotation when moving to the right (left)

  4. When you release your hand, the rotation slowly returns to 0.

Collision detection

Collision detection is definitely a must, since the character has to eat. Collision detection can be done in two ways

  1. When detecting collision objects, characters need to traverse the object coordinate list in real time for detection

  2. Collision detection is carried out for each object itself to detect the corresponding difference between itself and the position of the character

I tactfully chose the second one, because the position of each object changes in real time, and the method of conducting a cycle for each collision detection is too cumbersome. Here we set the collision detection area (width and height). When the object moves, we can compare the x and Y coordinates of the person with the four boundaries formed by adding and subtracting their own X and Y coordinates. If the collision is carried out, we can perform corresponding operations, such as playing audio and scoring +1.

Architecture design

After the thought is clear, the road behind is very clear. Now we can start to design how to implement this thing. Obviously, we have so many “characters” in the game that an “object-oriented” approach is best. The general division is as follows

  • Stage, basic scene rendering, overall game control (start, stop), etc

  • Player // Player, the corresponding character

  • Sprite // Objects that appear, such as cakes, for players to eat. Including collision detection and so on, will move itself

  • Tree // Each tree is a class because the tree itself moves

  • Score // Perform score control and display

  • Cfg.js // contains the overall game configuration

Internal object partitioning

Each object contains the following attributes and functions:

1. Configure objects

Each object contains its own internal basic configuration, including positions, boundaries, images, and so on. Intuitive and easy to debug



export default function People (stage) {
  this.cfg = {
    img: require('./img/people.png'),
    anchor: {
      x: 0.5,
      y: 0.5,
    },
    position: {
      x: cfg.width / 2,
      y: 500
    },
    speed: 5,}}Copy the code

2. Other methods

Each object contains its own method, as follows:

  • Render // Render images, etc

  • Animate // animate function

  • Init // Some initial configuration

implementation

Through the design of the above ideas and structure design, I will quickly achieve this game… Yes, that’s the importance of clear thinking and structure. Of course, there are some small points that can be noted during the implementation:

Resource loader (image)

For the sake of the game, I decided to stop loading the page after loading all resources (especially images). How do you tell if everything is loaded? I wrote a little loader



var pics = [
  require('./img/bg-start.png'),
  require('./img/btn-start.png'),
  ...
];

function loadImages (pics, callback) {
  if(pics.length) {
    var img = new Image(),
      pic = pics.shift();

    img.onload = callback;
    img.src = pic;
    loadImages(pics, callback);
  } else{
    return; }} $(function(a) {
  loadImages(pics, function (a) {
    if(! pics.length) { $('.loading').hide(); }; })});Copy the code

Mandatory landscape

The game is landscape, so make landscape mandatory. This was still entangled for a long time, or their own skills are not solid brain smuggling, still want to monitor the resize event or rotating screen event, all these things ah! I’m just going to rotate it.



if(window.orientation==180||window.orientation==0) {$('#main').height(winW);
  $('#main').width(winH); $(' # main). CSS ({'transform': 'rotate(90deg)'}); }else{$(' # main). CSS ('transform'.'rotate(0)');
}Copy the code

The timer control

After sorting out thoughts, the most chaotic or all kinds of timer. In order to achieve the effect of random objects, let each object random how many seconds after the beginning of the appearance; The last object appears, how many seconds after the end of the screen and so on, need to clarify the relationship between each timer, and add a good semantic mark, timely to the end of the timer to clear, to prevent timer unexpected problems.

Write in the last

The final result of the game is basically satisfactory to everyone, it is the first time to try this aspect of development, and there are no people around who have done this thing. In the past two weeks, I felt that I had experienced a very substantial thing, from feeling uneasy and confused at the beginning, to clarifying my thoughts and structure in the process, and to various unknown pits in writing. At the same time, I have more experience in exploring and learning unknown things. Finding the right way is the king’s way!


Did this article help you? Welcome to join the front End learning Group wechat group: