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

19 篇文章 0 订阅
14 篇文章 1 订阅

 上一章讲述马里奥跳跃动作和刹车的动作,本章对Json文件改动较多,我会一一讲解,还涉及到了部分代码重构

本章的提交ID:7419c4a70c772a45795d20ceb6559c1e1e8d8e3a

github地址:ainuo5213的超级马里奥

本节目录

 

目录讲解:

        1. loaders/level.js:原loadLevelAsync方法和loadTiles方法移动到了单独的文件,用于单独生成loadLevelAsync

实现效果

 layers.js文件改动

layers.js将原本用于获取TileResolver从实例中改为了创建实例,并且使用外部传入的tiles,在redraw方法中用于清空当前临时创建的bufferContext的内容,避免重复渲染

 Level.js改动

Level.js去掉了tiles、tileCollider的初始化操作,暴露一个方法用于设置马里奥碰撞检测实例和tiles

loader.js改动

loader.js删掉了loadTiles、loadLevelAsync方法,将loadJson暴露了出去

,供loader/level.js使用 

TilCollider碰撞检测实例改动

因之前遗漏,这里改动一下name为type

 1-1关卡数据json改动

1-1.json改动都标有注释,各位可以尝试理解一下

{
    "spriteSheet": "overworld",

    // 模式,用于16x16单位的多个元素拼凑而成的图片生成
    "patterns": {
        // 云,云被划分为了6个单位,上面3个,下面三个
        "cloud-single": {
            "tiles": [
                {
                    "name": "cloud-1-1",
                    "ranges": [[0, 0]]
                },
                {
                    "name": "cloud-1-2",
                    "ranges": [[1, 0]]
                },
                {
                    "name": "cloud-1-3",
                    "ranges": [[2, 0]]
                },
                {
                    "name": "cloud-2-1",
                    "ranges": [[0, 1]]
                },
                {
                    "name": "cloud-2-2",
                    "ranges": [[1, 1]]
                },
                {
                    "name": "cloud-2-3",
                    "ranges": [[2, 1]]
                }
            ]
        },

        // 水管体,水管体被划分为了2个单位,左边一个,右边一个
        "pipe-section-vert": {
            "tiles": [
                {
                    "name": "pipe-vert-left",
                    "type": "ground",
                    "ranges": [
                        [0, 0]
                    ]
                },
                {
                    "name": "pipe-vert-right",
                    "type": "ground",
                    "ranges": [
                        [1, 0]
                    ]
                }
            ]
        },

        // 水管帽子被划分为了2个单位,左边一个,右边一个
        "pipe-cap-vert": {
            "tiles": [
                {
                    "name": "pipe-insert-vert-left",
                    "type": "ground",
                    "ranges": [
                        [0, 0]
                    ]
                },
                {
                    "name": "pipe-insert-vert-right",
                    "type": "ground",
                    "ranges": [
                        [1, 0]
                    ]
                }
            ]
        },

        // 高度为2的水管,被划分为了2个,上边1个单位是水管帽,下边1个单位是水管体
        "pipe-2h": {
            "tiles": [
                {
                    "pattern": "pipe-cap-vert",
                    "ranges": [
                        [0, 0]
                    ]
                },
                {
                    "pattern": "pipe-section-vert",
                    "ranges": [
                        [
                            0, 1,
                            1, 1
                        ]
                    ]
                }
            ]
        },

        // 高度为3的水管,被划分为了2个,上边1个单位是水管帽,下边2个单位是水管体
        "pipe-3h": {
            "tiles": [
                {
                    "pattern": "pipe-cap-vert",
                    "ranges": [
                        [0, 0]
                    ]
                },
                {
                    "pattern": "pipe-section-vert",
                    "ranges": [
                        [
                            0, 1,
                            1, 2
                        ]
                    ]
                }
            ]
        },

        // 高度为4的水管,被划分为了2个,上边1个单位是水管帽,下边3个单位是水管体
        "pipe-4h": {
            "tiles": [
                {
                    "pattern": "pipe-cap-vert",
                    "ranges": [
                        [0, 0]
                    ]
                },
                {
                    "pattern": "pipe-section-vert",
                    "ranges": [
                        [
                            0, 1,
                            1, 3
                        ]
                    ]
                }
            ]
        }
    },

    // 背景渲染部分,整合了之前的backgrounds,并加入了水管(2h、3h、4h)和云
    "layers": [
        {
            "tiles": [
                {
                    "name": "sky",
                    "ranges": [
                        [
                            0, 212,
                            0, 13
                        ]
                    ]
                },
                {
                    "name": "ground",
                    "type": "ground",
                    "ranges": [
                        [
                            0, 212,
                            13, 2
                        ]
                    ]
                },
                {
                    "name": "sky",
                    "ranges": [
                        [
                            75, 2,
                            13, 2
                        ],
                        [
                            92, 2,
                            13, 2
                        ],
                        [
                            157, 2,
                            13, 2
                        ]
                    ]
                },
                {
                    "name": "ground",
                    "type": "ground",
                    "ranges": [
                        [
                            5, 3,
                            9, 1
                        ],
                        [
                            29, 5
                        ],
                        [
                            5, 7,
                            9
                        ],
                        [
                            12, 6,
                            11, 1
                        ],
                        [
                            2, 1,
                            11, 1
                        ],
                        [
                            10, 2,
                            10, 1
                        ],
                        [
                            10, 2,
                            10
                        ],
                        [
                            9, 1,
                            0, 7
                        ]
                    ]
                }
            ]
        },
        {
            "tiles": [
                {
                    "name": "bricks",
                    "type": "ground",
                    "ranges": [
                        [
                            27, 5,
                            9
                        ],
                        [
                            83, 3,
                            9
                        ],
                        [
                            86, 6,
                            5
                        ],
                        [
                            96, 3,
                            5
                        ],
                        [
                            99, 9
                        ],
                        [
                            105, 2,
                            9
                        ],
                        [
                            123, 5
                        ],
                        [
                            126, 3,
                            5
                        ],
                        [
                            132, 4,
                            5
                        ],
                        [
                            133, 2,
                            9
                        ],
                        [
                            171, 4,
                            9
                        ]
                    ]
                },
                {
                    "name": "chance",
                    "type": "ground",
                    "ranges": [
                        [2, 2],

                        [23, 9],
                        [28, 9],
                        [30, 9],
                        [29, 5],
                        [84, 9],
                        [99, 5],

                        [114, 5],
                        [111, 9],
                        [114, 9],
                        [117, 9],

                        [133, 2, 5],

                        [173, 9]

                    ]
                },
                {
                    "name": "chocolate",
                    "type": "ground",
                    "ranges": [
                        [141, 1, 9],
                        [140, 2, 10],
                        [139, 3, 11],
                        [138, 4, 12],

                        [144, 1, 9],
                        [144, 2, 10],
                        [144, 3, 11],
                        [144, 4, 12],

                        [155, 2, 9],
                        [154, 3, 10],
                        [153, 4, 11],
                        [152, 5, 12],

                        [159, 1, 9],
                        [159, 2, 10],
                        [159, 3, 11],
                        [159, 4, 12],

                        [191, 2, 5],
                        [190, 3, 6],
                        [189, 4, 7],
                        [188, 5, 8],
                        [187, 6, 9],
                        [186, 7, 10],
                        [185, 8, 11],
                        [184, 9, 12]
                    ]
                },
                {
                    "pattern": "pipe-2h",
                    "ranges": [
                        [35, 11],
                        [167, 11],
                        [182, 11]
                    ]
                },
                {
                    "pattern": "pipe-3h",
                    "ranges": [
                        [45, 10]
                    ]
                },
                {
                    "pattern": "pipe-4h",
                    "ranges": [
                        [53, 9],
                        [64, 9]
                    ]
                },
                {
                    "pattern": "cloud-single",
                    "ranges": [
                        [2, 2],
                        [25, 2],
                        [35, 3],
                        [44, 2],
                        [64, 3],
                        [74, 2],
                        [80, 3],
                        [90, 2],
                        [108, 3],
                        [118, 2],
                        [128, 3],
                        [138, 2]
                    ]
                }
            ]
        }
    ]
}

overworld.json地图切片数据改动

 地图切片数据加入了6个单位的云和4个单位的水管,用于切不同的16x16的方格进行渲染,所以说云占6个单位,长3宽2等

loader/level.js

loader/level.js是之前loadTiles和loadAsync的整合,并进行部分优化,将每个循环拆分到了外部,降低主代码区的代码长度,利于维护和扩展

import { createBackgroundLayer, createrSpriteLayer } from "../layers.js";
import { Matrix } from "../Math.js";
import { Level } from "../Level.js";
import { loadJson, loadSpriteSheet } from "../loader.js";


export function loadLevelAsync(name) {
    return loadJson(`/src/levels/${name}.json`)
        .then(data => Promise.all([data, loadSpriteSheet(data.spriteSheet)]))
        .then(([levelJson, backgroundSprite]) => {
            const level = new Level();

            // 加载level中的matrix每一个格子的数据到tiles
            const mergedTiles = levelJson.layers.reduce((mergedTiles, layer) => {
                return mergedTiles.concat(layer.tiles);
            }, []);
        
            // 动态设置level的碰撞检测类
            const collisionGrid = createCollisionGrid(mergedTiles, levelJson.patterns);
            level.setCollisionGrid(collisionGrid);

            levelJson.layers.forEach(layer => {
                const backgroundGrid = createBackgroundGrid(layer.tiles, levelJson.patterns);
                const backgroundLayer = createBackgroundLayer(level, backgroundGrid, backgroundSprite);
                level.compositor.layers.push(backgroundLayer);
            })

            // 创建马里奥图像的回调
            const marioSpriteLayer = createrSpriteLayer(level.entities);
            level.compositor.layers.push(marioSpriteLayer);

            return level;
        })
}

// 一个range范围内的x和y对象集合
function* expandSpan(xStart, xLen, yStart, yLen) {
    const xEnd = xStart + xLen;
    const yEnd = yStart + yLen;
    for (let x = xStart; x < xEnd; x++) {
        for (let y = yStart; y < yEnd; y++) {
            yield { x, y };
        }
    }
}

// 展开一个range,原range.forEach...
function expandRange(range) {
    // 修改渲染逻辑: 当配置中的range为4位数,则其分别为x位置开始xStart、x方向渲染长度xLen、y位置开始yStart、y方向渲染长度yLen
    //             当配置中的range为2位数,则其分别为x位置开始xStart、y位置开始yStart,此时yLen、xLen均为1
    //             当配置中的range为3位数,则其分别为x位置开始xStart、x方向渲染长度xLen、y位置开始yStart,此时yLen为1
    if (range.length === 4) {
        const [xStart, xLen, yStart, yLen] = range;
        return expandSpan(xStart, xLen, yStart, yLen);
    } else if (range.length === 2) {
        const [xStart, yStart] = range;
        return expandSpan(xStart, 1, yStart, 1);
    } else if (range.length === 3) {
        const [xStart, xLen, yStart] = range;
        return expandSpan(xStart, xLen, yStart, 1);
    }
}

// 展开多个ranges(原tile.ranges.forEach...)
function* expandRanges(ranges) {
    for (const range of ranges) {
        for (const item of expandRange(range)) {
            yield item
        }
    }
}

// 展开tiles为制定格式的对象的数组(如果该元素是pattern,就继续展开pattern对应的那个对象知道展开到底)
function expandTiles(tiles, patterns) {
    const expandedTiles = [];
    function walkTiles(tiles, offsetX, offsetY) {
        for (const tile of tiles) {
            for (const { x, y } of expandRanges(tile.ranges)) {
                const derivedX = x + offsetX;
                const derivedY = y + offsetY;
                if (tile.pattern) {
                    const tiles = patterns[tile.pattern].tiles;
                    walkTiles(tiles, derivedX, derivedY);
                } else {
                    expandedTiles.push({
                        tile,
                        x: derivedX,
                        y: derivedY
                    });
                }
            }
        }
    }
    walkTiles(tiles, 0, 0);
    return expandedTiles;
}

// 循环遍历展开了的tiles,生成matrix
function createCollisionGrid(tiles, patterns) {
    const matrix = new Matrix();
    for (const { tile, x, y } of expandTiles(tiles, patterns)) {
        matrix.set(x, y, {
            type: tile.type,
            name: tile.name
        });
    }

    return matrix;
}

// 循环遍历展开了的tiles,生成matrix
function createBackgroundGrid(tiles, patterns) {
    const matrix = new Matrix();
    for (const { tile, x, y } of expandTiles(tiles, patterns)) {
        matrix.set(x, y, {
            type: tile.type,
            name: tile.name,
        });
    }

    return matrix;
}

本节代码重构较多,大家多多理解重构部分

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值