MapEditor: 在线地图编辑器,目标是结合 WebGL 做个在线马造

您所在的位置:网站首页 贴图马造二下载 MapEditor: 在线地图编辑器,目标是结合 WebGL 做个在线马造

MapEditor: 在线地图编辑器,目标是结合 WebGL 做个在线马造

2024-07-10 19:02| 来源: 网络整理| 查看: 265

MapEditor

为游戏开发者设计的地图生成器,它为简化开发、提高效率而生

License Build State

在线访问

在线展示地址 https://alsritter.gitee.io/map-editor-online

⚠ 注意:本工具不对移动端进行适配

基本功能介绍 导入导出数据 💾

选择使用的砖块 🗃

选择你使用的砖块

选择工作的图层 📌

默认情况下(可以以自己的方式解析数据):

Background:背景层,不与玩家交互 Collision:碰撞层 Traps:陷阱图层 Foreground:遮挡在角色前面的图层

设置地图大小

选择绘图工具 📐

这些工具的作用:

Pen Tool:默认的笔工具,一次绘制一个方块 Draw Area Tool:绘制一个区块的方块 Fill ALL Tool:油漆桶工具,用于覆盖图层 Fill Area Tool:用于填满空隙 Replace Tiles Tool:替换砖块 Erase Tool:擦除当前方块 Erase Area Tool:擦除一个区块

设置出生点以及终点

如何工作的? 🤨

下面介绍一些工作原理,对这部分不感兴趣的可以直接跳过啦~

绘制网格

image.png

canvas { border: 1px solid black; } function draw() { const canvas = document.getElementById('testCanvas') const ctx = canvas.getContext('2d') //取得2d 画布上下文 const _cols = 16 const _rows = 16 // 先获取每个图形格子的大小 const _space = canvas.width / _cols // 绘制线条 for (let i = 0; i { let tileColsNum = 5; // 图的宽度,以列表示 let tileRowsNum = 1; // 图的高度,以行为中 let sWidth = img.width / tileColsNum; // 切图的宽度 let sHeight = img.height / tileRowsNum; // 切图的高度 for (let col = 0; col { console.log(map[Math.floor(e.offsetY / _space)][Math.floor(e.offsetX / _space)]) } 绘制方格背景

image.png

/** * 绘制背景方格 * @param {CanvasRenderingContext2D} ctx 传入 canvas 的 Context * @param {Number} width 画布的宽度 * @param {Number} height 画布的高度 */ static drawBackground(ctx, width, height) { let emptyBox = ctx.createImageData(width, height) let emptyBoxData = emptyBox.data // 通过 canvas宽高 来遍历一下 canvas 上的所有像素点 for (let i = 0; i > 2 相当于 / 4 取整, & 1相当于 % 2 emptyBoxData[point] = rgbData emptyBoxData[point + 1] = rgbData emptyBoxData[point + 2] = rgbData emptyBoxData[point + 3] = 255 } } ctx.putImageData(emptyBox, 0, 0) } 存储 Tile贴图中格子的位置

要存储该图数据,可以使用一个自定义类

/** * 单个 Tile 在图片的位置 */ class Tile { /** * Tile 在贴图里面的位置,以及保存它的路径偏移量(贴图位置和路径偏移量无关,后者是保存它显示在屏幕的位置) * @param {Number} x Tile 在贴图里的起始 x * @param {Number} y Tile 在贴图里的起始 y */ constructor(x, y) { this.x = x this.y = y } } /** * TileImage 里面的 Tile */ export class TileMap { /** * * @param {Number} cols Tile贴图的宽度(一列有多少个 Tile) * @param {Number} rows Tile贴图的高度(一行有多少个 Tile) * @param {HTMLImageElement} img 这里传入的 Tile 贴图,必须放在 onload 里面执行 */ constructor(cols, rows, img) { this.cols = cols this.rows = rows this.img = img this.tiles = [] this.sWidth = 0 // 每个单元格的宽度 this.sHeight = 0 // 每个单元格的高度 this.sWidth = this.img.width / this.cols // 切图的宽度 this.sHeight = this.img.height / this.rows // 切图的高度 for (let col = 0; col { ctx.clearRect(0, 0, canvas.width, canvas.height) DrawUtility.drawAllTile(ctx, map, posList) } // 移出画布也刷新 canvas.onmouseout = (e) => { ctx.clearRect(0, 0, canvas.width, canvas.height) DrawUtility.drawAllTile(ctx, map, posList) } // 监听鼠标事件,判断当前点击了哪个区域 canvas.onmousedown = (e) => { for (let index = 0; index $store.state.isShowAllLayer, val => { isShowAll = new Boolean(val).valueOf(); window.dispatchEvent(new CustomEvent("refreshData")); // 通知更新数据 } );

而在控制层对这个事件进行监听刷新

// 定义一个刷新事件的监听 window.addEventListener("refreshData", () => { // 这里进行刷新操作 }); 实现撤回功能

这个撤回实际上就是一个入栈和出栈的过程,因此自己维护一个栈就行了

import Grid from "./VO/Grid"; /** * 自定义的栈结构,主要用来维护 画布数据 */ export default class MapStack { private arr: Array; constructor() { this.arr = []; } /** * 压栈操作 * @param { { layer: number, map: Grid[][] }} mapInfo */ push(mapInfo: { layer: number; map: Grid[][] }): void { this.arr.push(mapInfo); } /** * 退栈操作 */ pop(): { layer: number; map: Grid[][] } { return this.arr.pop() as { layer: number; map: Grid[][] }; } /** * 获取栈顶元素 */ top(): { layer: number; map: Grid[][] } { return this.arr[this.arr.length - 1]; } /** * 清空栈 */ clear(): boolean { this.arr = []; return true; } }

每次写入后要及时入栈

然后再在控制层去监听 Ctrl + Z

// 监听撤回键(使用栈) document.onkeydown = e => { if (e.ctrlKey == true && e.key == "z") { // 如果栈内不为空才撤回 if (recallMap.size() !== 0) { // 弹栈 const temp = recallMap.pop(); gridManagerArray[temp.layer].setMap(temp.map); window.dispatchEvent(refreshEvent); // 通知更新数据 } } }; 区域更新

如果每一帧都刷新全部数据会浪费很多性能,而且有多层数据就更雪上加霜了

创建一个 cacheMap 来记录修改了的位置,它会在下一帧更新

import BasePos from "./VO/BasePos"; export default class CacheMap { private cols: number; private rows: number; private map: boolean[][]; constructor(cols: number, rows: number) { this.cols = cols; this.rows = rows; this.map = []; // 每个数组都需要先初始化 默认是 false for (let i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3