原生JS超级马里奥(第二天)

上一章主要用于绘制背景图像如天空、大地,这一章主要是绘制马里奥和绘制图像代码的部分重构,代码有点复杂,大家可以比较提交ID进行查看差异。

本章的提交ID:a338e45b76c1f4aabd06f5642d4abaa17f0d0947、4576245f764d7e0dfbcba1df1775e20fc26552a8

github地址:ainuo5213的超级马里奥

本节目录

原生JS超级马里奥(第二天)_第1张图片

 这里对新增目录文件进行解释:

        Compositor.js:组合器,将绘制图像的高阶函数进行迭代调用

        layer.js:图层模块,创建绘制图像的高阶函数,统一绘制方式,便于管理和维护

        spirtes.js:加载外部文件,并返回单位图像样式对象,用于绘制图像

入口文件

原生JS超级马里奥(第二天)_第2张图片

入口文件:

        1. 将之前的drawBackground抽离出去,并将每一个Promise放到了Promise.all

        2. 将之前绘制图像的部分代码进行重构,移动到了每一个函数里,进行功能聚合

绘制图像代码抽离和重构

// layers.js

/**
 * 绘制背景:天空、大地
 * @param {any} background 背景对象,来自于json配置
 * @param {any} context canvas上下文对象
 * @param {UnitStyleSheet} unitStyleSheet 单元图像样式对象
 */
function drawBackground(background, context, unitStyleSheet) {
    background.ranges.forEach(([x1, x2, y1, y2]) => {
        for (let x = x1; x < x2; x++) {
            for (let y = y1; y < y2; y++) {
                unitStyleSheet.drawTile(background.tile, context, x, y);
            }
        }
    })
}


/**
 * 创建绘制图像的函数:在回调中绘制图像
 * @param {any} backgrounds 背景对象,来自于json配置
 * @param {UnitStyleSheet} backgroundSprite 单元图像样式对象
 * @returns {Function} 绘制图像的回调
 */
export function createBackgroundLayer(backgrounds, backgroundSprite) {

    // 创建临时缓存区,使用闭包在外部绘制图像
    const buffer = document.createElement("canvas");
    buffer.width = 256;
    buffer.height = 240;

    // 循环将图像绘制到临时的画布
    backgrounds.forEach(background => {
        drawBackground(background, buffer.getContext("2d"), backgroundSprite);
    });

    // 返回绘制图像的回调
    return function drawBackgroundLayer(context) {
        context.drawImage(buffer, 0, 0);
    }
}

/**
 * 创建绘制图像的函数:在回调中绘制图像
 * @param {UnitStyleSheet} sprite 单元图像样式对象
 * @param {
    { x: number, y: number }}} pos 初始位置
 * @returns 绘制图像的回调
 */
export function createrSpriteLayer(sprite, pos) {
    return function drawSpriteLayer(context) {
        for (let i = 0; i < 20; i++) {
            sprite.draw('mario', context, pos.x + i * 16, pos.y);
        }
    }
}

这里将每一个绘制图像的代码移动带了回调函数里,在外部进行组合绘制

// Compositor.js

export class Compositor {
    constructor() {
        this.layers = [];
    }

    /**
     * 将每个绘制图像的回调全部执行一次
     * @param {any} context canvas上下文对象
     */
    draw(context) {
        this.layers.forEach(layer => {
            typeof layer === "function" && layer(context);
        })
    }
}

重构加载外部文件

// sprites.js

import UnitStyleSheet from "./UnitStyleSheet.js";
import { loadImageAsync } from "./loader.js";

export function loadBackgroundSprites() {
    return loadImageAsync("/src/assets/tiles.png")
        .then(image => {
            const backgroundUnitStyleSheet = new UnitStyleSheet(image, 16, 16);
            backgroundUnitStyleSheet.defineTile("ground", 0, 0);
            backgroundUnitStyleSheet.defineTile("sky", 3, 23);
            return backgroundUnitStyleSheet;
        });
}

export function loadMarioSprite() {
    return loadImageAsync("/src/assets/characters.png")
        .then(image => {
            const marioUnitStyleSheet = new UnitStyleSheet(image, 16, 16);
            marioUnitStyleSheet.define("mario", 276, 44, 16, 32);
            return marioUnitStyleSheet;
        });
}

之前将加载外部文件写在了入口文件,那样会造成入口文件过大,而且不利于阅读,这里将其拆分为单独的模块,由入口文件引用

你可能感兴趣的:(web小游戏开发,原生js,es6,小游戏,javascript,es6,前端,超级玛丽)