javascript
原生JS超级马里奥(第九天)
?上一章講述馬里奧跳躍動作和剎車的動作,本章對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每一個格子的數據到tilesconst 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為1if (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; }本節代碼重構較多,大家多多理解重構部分
總結
以上是生活随笔為你收集整理的原生JS超级马里奥(第九天)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CTO离职前悄悄传了我一招,和我说吃透跳
- 下一篇: SAP中外协加工收货与反冲消耗数量不一致