The first wechat mini game. Ha ha is the first one again. Because of the epidemic, staying at home, no longer looking for something to do is really fast mold, so there is this little game.

Open source

Github address: github.com/CB-ysx/bear…

Note: Open source only the first version of the code. The first version is a webpack+ Babel package. This is a reference to JetLua’s Pixi development framework and a version of colloc wechat mini game. Colloc source address: github.com/JetLua/coll… Thanks for sharing the author of pixi.js micro channel game development.

Because webpack+ Babel is used for packaging, resulting in NPM third-party package code in the packaged file, the repetition rate is too high, micro channel games identified as plagiarism… Explained also useless, does not pass to examine and verify all the time, still buckled credit score… So this edition is for reference only.

I refactored the version and removed the Webpack packaging.

Wechat small game code

Screenshots of the game















Game play

Click on the left and right sides of the screen to control the bear to avoid obstacles and jump up to the left and right sides. The higher the score is, the higher the score is when stepping on the star props, 10 points can be directly added.

The source code is introduced

Github address: github.com/CB-ysx/bear…

The framework

Packaged with WebPack + Babel, using the PiXI development framework provided by JetLua.

The directory structure

Description:

  • Never mind the readmeimg directory, this is the image I stored on Github to show some screenshots of the game.
  • The source code is mainly in the SRC directory

Game. json and project.config.json are required files for wechat mini games, which can be copied directly after creating the project through developer tools. Of course, in order to match the project structure, the content of Game. json needs to be modified. You can also use the game. Json file for this project.

The static directory stores some static resources, of course, if the resources are too large, you can choose to store them in the CDN or something like that. Cloud directory stores cloud functions. This project does not develop additional back-end projects, but directly uses cloud development provided by mini-games. The game directory is the source of the game’s primary domain. The openDataContext directory is the source of the game’s sub-domain

Primary domain: can be understood as players visible map domain subdomain: draw the canvas is not visible to players, need the primary domain for subdomains canvas to draw out, subdomains is mainly used to draw some sensitive data, such as user’s friends, groups, data, etc., the class data WeChat does not directly provide developers to use, can only be obtained from subdomains.

The main NPM package used

This game is developed by using Pixi. js. Since wechat small game has no DOM and only canvas, there will be some problems in using pixi.js directly, and multiple Adapters need to be added for compatibility.

  • @iro/ Video-adapter // adapter
  • Popmotion // Do animations
  • pixi
  • @pixi/unsafe-eval

How to develop with Pixi.js

Look at the SRC /game/core/core.js file

const ticker = PIXI.Ticker.shared;
const loader = PIXI.Loader.shared; // Used to load images
const stage = new PIXI.Container(); // Stage, all the scenes are displayed on this stage
const monitor = new PIXI.utils.EventEmitter();
const pixelRatio = Math.min(2, devicePixelRatio);

const renderer = new PIXI.Renderer({ / / using webgl
    view: canvas, // Canvas is on the window
    antialias: true.backgroundColor: 0x171a24.width: width * pixelRatio,
    height: height * pixelRatio
});

const zoom = {
    mix: [
        renderer.screen.width / design.width,
        renderer.screen.height / design.height
    ],
    get max() {
        return Math.max(... this.mix); }, get min() {return Math.min(...this.mix);
    }
};

renderer.plugins.accessibility.destroy();
renderer.plugins.interaction.mapPositionToPoint = (point, x, y) = > { // match click events
    point.set(x * pixelRatio, y * pixelRatio);
};

ticker.add((a)= > renderer.render(stage)); / / rendering
Copy the code

The entrance

App.js imports files like core.js and does some listening (page display, route redirection, etc.)

Here is a question about music playback. Suspending the mini game (returning to wechat page, etc.) will trigger the pause of music playing, but when opening the mini game again, the music will not continue to play. I checked the interface that can be used to monitor and block music playing events.

wx.onAudioInterruptionBegin((a)= > {
    // Block music playback
    console.log('onAudioInterruptionBegin');
});

wx.onAudioInterruptionEnd((a)= > {
    console.log('onAudioInterruptionEnd');
    // Now back to the game page, publish the event
    monitor.emit('wx:onAudioInterruptionEnd'); }); . monitor.on('wx:onAudioInterruptionEnd', () = > {// Listen to the event and play music
    // If you fill in this blank, the last played music will be automatically retrieved
    wx.$audio.playBgm(' '.true);
}).on('muted:bgm', (muted)=> {
    wx.$audio.muteBgm(muted);
}).on('muted:sound', (muted)=> {
    wx.$audio.mute(muted);
});
Copy the code

Routing to monitor

monitor
    .on('scene:go', (name, opt = {}) => {
        switch (name) {
        case 'preload': {// Jump to the load page
            pointer = preload;
            preload.show(opt);
            break;
        }
        case 'home': {// The first page of the game
            pointer = home;
            home.show(opt);
            break;
        }
        case 'game': {/ / game page
            pointer = game;
            game.show(opt);
            break; }}});// Load the page
monitor.emit('scene:go'.'preload');
Copy the code

The game development

Other do not introduce more, you can view the source code to understand. Here’s the game development logic.

decomposition

In order to allow for the subsequent addition of features, we will first break down the game components and separate out reusable and extensible elements. Because this game is to control the bear jump on the block, the bear and obstacles are out of each block, therefore, the block can be split out.

  • The Block class has its own container, which is used to store items. Of course, the background of the Block is also stored in the Container. In the game, you can directly add the Container to the scene without knowing the properties of the Block.
class Block {
    constructor(bg) {
        this.uid = wx.$util.uuid(); // Each square has its own id
        this.type = BLOCK_TYPE.EMPTY; // Block type
        this.sw = 0; // The size of the cube
        this.sh = 0;
        this._scale = 1;
        this.container = new PIXI.Container();

        this.bg = pixiUitl.genSprite(bg); // Block image
        this.sw = this.bg.width;
        this.sh = this.bg.height;
        this.container.addChild(this.bg);
        this.container.width = this.sw;
        this.container.height = this.sh; }... }Copy the code

Then there are blocks that function as items, inheritance and blocks

/** * blocks with obstacles */
class BarrireBlock extends Block {
    constructor(bg) {
        super(bg);
        this.type = BLOCK_TYPE.BARRIER;
	// Place obstacles on blocks
        this.barrier = new PIXI.Sprite();
        this.barrier.anchor.set(0.5.0.5);
        this.barrier.x = this.container.width / 2;
        this.barrier.y = 18;
        this.container.addChild(this.barrier);
    }

    setBarrier(name) {
	// Set the obstacle picture
        this.barrier.texture = pixiUitl.getTexture(name);
        return this;
    }

    hideBarrier() {
	// Clear obstacles
        this.barrier.texture = null; }}/** * false blocks (will drop after 0.5 seconds) */
class FakeBlock extends Block {
    constructor(bg) {
        super(bg);
        this.type = BLOCK_TYPE.FAKE;
        this.waitToFall = false;
    }

    init() {
        this.waitToFall = false;
    }

    startToFall() {
        this.waitToFall = false;
    }

    fall() {
	// False blocks that will automatically fall when you step on them
        return new Promise(resolve= > {
            if (this.waitToFall) {
                tween({
                    from: {
                        y: this.y,
                        alpha: 1
                    },
                    to: {
                        y: screen.height,
                        alpha: 0
                    },
                    ease: easing.easeIn,
                    duration: 200,
                }).start({
                    update: v= > {
                        this.y = v.y;
                        this.alpha = v.alpha;
                    },
                    complete: resolve
                });
            } else{ resolve(); }}); }}Copy the code
  • Lines with squares also need a class that manages squares in each row, because squares in each row appear at the same time and disappear after a certain number of rows. So make one more Line class to manage.

  • Pool Because the game generates blocks frequently, make an extra pool of blocks to manage, and get blocks from that pool each time you create one, or create a new one if none exists. When the cube disappears, it is automatically put back into the pool for use.

  • The Bear is similar to the cube and requires a Container, as the bear may have item effects (such as protective circles).

Block generation rule

Okay, now that we’ve split these classes, we’re going to start generating blocks from the bottom up, line by line, with the first few lines always generating blocks that don’t have any function. Const lineData = [1, 2, 3, 4, 3, 4, 3, 4, 3, 4]; And then each row is going to randomly +- one beeper over the previous row.

And then there’s the big point, how to make sure there’s no road to death. It needs to be judged by the function of the square on the previous line, which may be complicated and not clear. I can imagine the picture by myself, so I am too lazy to draw the picture.

1. If the previous block of the current block is an obstacle, then no obstacle is allowed in that position. 2, if the number of the previous line is 2.1 more than the current line, if the two blocks adjacent to the current block are not obstacles, then the position can randomly appear obstacles, otherwise the current block is not allowed to appear obstacles. 2.2. If the current block is the last one in the current row and the last one in the previous row is an obstacle, this position can also be a random obstacle. 3. If the number of the previous line is less than that of the current line, 3.1. The first and the last of the current line can be random obstacles, and the last can appear only if the previous one is not an obstacle. 3.2 The same subscript position in the previous line is an obstacle, then the block with the subscript in the line can also be a random obstacle.

Controls the number of obstacles, increasing as the number of lines increases: math.random () < (0.4 + this.linenum * 0.005)

Little bear jumping

Bear jump how to get the next box, global store a bear’s box in the row index. If jump left, get the next row of squares at index-1, otherwise get the squares at index+1.

If the block does not exist or is an obstacle, the game is judged to have failed.

Otherwise calculate where the bear will jump based on the xy coordinates of the square. The important thing to note here is that if you don’t jump one level, all the cubes fall one level, so ultimately the y value of the bear is the same when it stops jumping.

Subdomain draw

It should be noted that after drawing the leaderboard and other data in the sub-domain, the drawing method in the primary domain is as follows:

ticker.add(this.update, this);

update() {
    if (this.showEnding) {
        // Displays the end score
        canvas = wx.$open.getCanvas();
        this.endSprite.texture = PIXI.Texture.from(canvas);
        this.endSprite.texture.update(); }}Copy the code

The last

That’s about it.

The original address

Codebear. Cn/article? Id =…