Files
CINC/scenes/MapEditTestScene.js
T

916 lines
29 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 地图编辑测试场景
// 防御性编程原则:
// 1. 始终检查对象和方法是否存在
// 2. 检查参数类型和范围
// 3. 使用 try-catch 块捕获可能的异常
// 4. 为所有容器和对象使用明确的命名
// 5. 避免使用相同的键名,防止冲突
// 6. 始终检查纹理是否存在
// 7. 在使用方法前检查方法是否存在
// 8. 添加详细的日志和错误信息
// 9. 为复杂逻辑添加注释
// 10. 使用类型检查和断言
export default class MapEditTestScene extends Phaser.Scene {
constructor() {
super({ key: 'MapEditTestScene' });
this.tileSize = 16; // 地图瓦片大小
this.selectedTile = null; // 当前选中的瓦片
this.mapLayer = null; // 地图层
this.mapWidth = 50; // 地图宽度(瓦片数量)
this.mapHeight = 50; // 地图高度(瓦片数量)
this.isDragging = false; // 是否正在拖拽地图
this.lastDragPosition = { x: 0, y: 0 }; // 上次拖拽位置
this.zoomLevel = 1; // 缩放级别
// 瓦片图相关属性
this.tilemapKey = ''; // 单张瓦片图的键名
this.tileCount = 234; // 总瓦片数
this.tileImageSize = 16; // 瓦片在图片中的实际大小
this.tileSpacing = 0; // 瓦片间距
this.tileColumns = 18; // 瓦片图列数
this.tileRows = 13; // 瓦片图行数
}
preload() {
// 加载瓦片资源
this.loadTileAssets();
// 显示加载进度
this.createLoadingUI();
}
create() {
console.log('开始创建地图编辑场景');
// 物理世界和相机边界
const worldSize = this.mapWidth * this.tileSize;
this.physics.world.setBounds(0, 0, worldSize, worldSize);
this.cameras.main.setBounds(0, 0, worldSize, worldSize);
// 设置背景色
this.cameras.main.setBackgroundColor('#222222');
// 修复:移除可能有问题的defaultFilterMode设置,使用资源加载完成后设置过滤模式
// 创建地图编辑区域
console.log('创建地图编辑区域');
this.createMapArea();
// 创建瓦片选择区域
console.log('创建瓦片选择区域');
this.createTileSelectionArea();
// 检查资源是否已加载
if (this.assetsLoaded) {
console.log('资源已加载,调用updateTileSelection');
this.updateTileSelection();
} else {
console.log('资源尚未加载,等待加载完成');
}
// 创建控制面板
console.log('创建控制面板');
this.createControlPanel();
// 设置输入处理
console.log('设置输入处理');
this.setupInput();
// 显示提示信息
console.log('显示提示信息');
this.showInstructions();
console.log('地图编辑场景创建完成');
}
/**
* 加载瓦片资源
*/
loadTileAssets() {
console.log('开始加载瓦片资源');
// 只加载单张瓦片图,替代多张瓦片资源
const tilemapKey = 'mapedit-tilemap';
const tilemapPath = 'assets/PNG/Tiles/Tilemap/tilemap_packed.png';
console.log(`加载瓦片图: ${tilemapKey} -> ${tilemapPath}`);
this.load.image(tilemapKey, tilemapPath);
// 加载进度回调
this.load.on('progress', (progress) => {
console.log(`资源加载进度: ${Math.round(progress * 100)}%`);
});
// 文件加载完成回调
this.load.on('filecomplete', (key, type, data) => {
console.log(`文件加载完成: ${key} (${type})`);
});
// 加载完成回调
this.load.on('complete', () => {
console.log('所有资源加载完成!');
this.assetsLoaded = true;
this.loadingText.setText('资源加载完成!');
// 设置瓦片图的过滤模式为NEAREST
if (this.textures.exists(tilemapKey)) {
const texture = this.textures.get(tilemapKey);
texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
console.log(`设置纹理 ${tilemapKey} 的过滤模式为NEAREST`);
}
// 初始化瓦片集合 - 只使用单张瓦片图键名
this.tileCount = 234; // 根据Tilesheet.txt,总瓦片数为18x13=234
this.tilemapKey = tilemapKey;
// 存储瓦片的位置信息,用于后续切割
this.tileImageSize = 16; // 瓦片大小16x16px
this.tileSpacing = 0; // 瓦片间距0px
this.tileColumns = 18; // 18列
this.tileRows = 13; // 13行
console.log(`瓦片图初始化完成,共 ${this.tileCount} 个瓦片`);
// 只有在tileSelectionContainer初始化后才调用updateTileSelection
if (this.tileSelectionContainer) {
console.log('tileSelectionContainer已初始化,调用updateTileSelection');
this.updateTileSelection();
} else {
console.log('tileSelectionContainer尚未初始化,等待create方法调用');
}
});
}
/**
* 创建加载UI
*/
createLoadingUI() {
// 加载文本
this.loadingText = this.add.text(10, 10, '加载瓦片资源...', {
fontSize: '16px',
fill: '#ffffff',
fontFamily: 'Arial'
});
this.loadingText.setScrollFactor(0, 0);
this.loadingText.setDepth(100);
// 加载进度条
this.progressBar = this.add.rectangle(10, 40, 300, 20, 0x555555);
this.progressBar.setOrigin(0, 0);
this.progressBar.setScrollFactor(0, 0);
this.progressBar.setDepth(100);
this.progressFill = this.add.rectangle(10, 40, 0, 20, 0x00ff00);
this.progressFill.setOrigin(0, 0);
this.progressFill.setScrollFactor(0, 0);
this.progressFill.setDepth(100);
// 更新进度
this.load.on('progress', (progress) => {
this.progressFill.width = progress * 300;
this.loadingText.setText(`加载瓦片资源... ${Math.round(progress * 100)}%`);
});
}
/**
* 创建地图编辑区域
*/
createMapArea() {
// 创建地图容器
this.mapContainer = this.add.container(0, 0);
this.mapContainer.setDepth(1);
// 创建背景网格
this.createGrid();
// 创建地图层(用于放置瓦片)
this.mapLayer = this.add.container(0, 0);
this.mapContainer.add(this.mapLayer);
// 初始化空地图
this.mapData = [];
for (let y = 0; y < this.mapHeight; y++) {
this.mapData[y] = [];
for (let x = 0; x < this.mapWidth; x++) {
this.mapData[y][x] = -1; // -1表示空瓦片
}
}
}
/**
* 创建背景网格
*/
createGrid() {
// 创建网格线
const gridGraphics = this.add.graphics();
gridGraphics.lineStyle(1, 0x444444, 0.5);
// 绘制垂直线
for (let x = 0; x <= this.mapWidth; x++) {
gridGraphics.moveTo(x * this.tileSize, 0);
gridGraphics.lineTo(x * this.tileSize, this.mapHeight * this.tileSize);
}
// 绘制水平线
for (let y = 0; y <= this.mapHeight; y++) {
gridGraphics.moveTo(0, y * this.tileSize);
gridGraphics.lineTo(this.mapWidth * this.tileSize, y * this.tileSize);
}
this.mapContainer.add(gridGraphics);
}
/**
* 创建瓦片选择区域
*/
createTileSelectionArea() {
// 瓦片选择区域背景 - 使用固定大小,足够容纳完整瓦片图
const tilePanel = this.add.rectangle(10, 70, 300, 250, 0x111111, 0.8);
tilePanel.setOrigin(0, 0);
tilePanel.setScrollFactor(0, 0);
tilePanel.setDepth(10);
// 瓦片选择区域标题
this.add.text(20, 80, '瓦片选择', {
fontSize: '16px',
fill: '#ffffff',
fontFamily: 'Arial',
fontWeight: 'bold'
}).setScrollFactor(0, 0).setDepth(11);
// 瓦片选择容器 - 注意:这是一个Container对象,可以使用removeAll方法
this.tileSelectionContainer = this.add.container(20, 110);
this.tileSelectionContainer.setScrollFactor(0, 0);
this.tileSelectionContainer.setDepth(11);
// 移除网格,不再需要
// this.tileSelectionGrid = this.add.grid(0, 0, fullWidth, fullHeight, tileWidth, tileHeight, 0x333333, 0.5, 0x444444, 0.5);
// this.tileSelectionContainer.add(this.tileSelectionGrid);
// 当前选中瓦片显示 - 改为使用Container容器,而不是Rectangle,这样可以使用removeAll方法
this.selectedTileContainer = this.add.container(20, 340);
this.selectedTileContainer.setScrollFactor(0, 0);
this.selectedTileContainer.setDepth(11);
// 添加选中瓦片背景
const selectedTileBg = this.add.rectangle(0, 0, 16, 16, 0x333333);
selectedTileBg.setOrigin(0, 0);
selectedTileBg.setDepth(10);
this.selectedTileContainer.add(selectedTileBg);
this.add.text(20, 320, '当前选中瓦片:', {
fontSize: '14px',
fill: '#ffffff',
fontFamily: 'Arial'
}).setScrollFactor(0, 0).setDepth(11);
}
/**
* 创建控制面板
*/
createControlPanel() {
// 控制面板背景
const controlPanel = this.add.rectangle(this.sys.game.config.width - 210, 10, 200, 150, 0x111111, 0.8);
controlPanel.setOrigin(0, 0);
controlPanel.setScrollFactor(0, 0);
controlPanel.setDepth(10);
// 控制面板标题
this.add.text(this.sys.game.config.width - 200, 20, '控制面板', {
fontSize: '16px',
fill: '#ffffff',
fontFamily: 'Arial',
fontWeight: 'bold'
}).setScrollFactor(0, 0).setDepth(11);
// 创建按钮
this.createButton(this.sys.game.config.width - 200, 50, 180, 30, '清空地图', () => {
this.clearMap();
});
this.createButton(this.sys.game.config.width - 200, 90, 180, 30, '保存地图', () => {
this.saveMap();
});
this.createButton(this.sys.game.config.width - 200, 130, 180, 30, '加载地图', () => {
this.loadMap();
});
}
/**
* 创建按钮
*/
createButton(x, y, width, height, text, callback) {
// 按钮背景
const button = this.add.rectangle(x, y, width, height, 0x333333);
button.setOrigin(0, 0);
button.setScrollFactor(0, 0);
button.setDepth(10);
button.setInteractive({ useHandCursor: true });
// 按钮文本
const buttonText = this.add.text(x + 10, y + 5, text, {
fontSize: '14px',
fill: '#ffffff',
fontFamily: 'Arial'
});
buttonText.setScrollFactor(0, 0);
buttonText.setDepth(11);
// 按钮事件
button.on('pointerdown', callback);
button.on('pointerover', () => {
button.setFillStyle(0x555555);
});
button.on('pointerout', () => {
button.setFillStyle(0x333333);
});
}
/**
* 更新瓦片选择显示
*/
updateTileSelection() {
console.log('开始更新瓦片选择显示');
console.log(`当前瓦片数量: ${this.tileCount}`);
// 清空当前瓦片选择
console.log('清空当前瓦片选择');
this.tileSelectionContainer.removeAll(true);
try {
// 检查纹理是否存在
if (this.textures.exists(this.tilemapKey)) {
console.log(`纹理 ${this.tilemapKey} 存在`);
// 获取瓦片图的实际尺寸
const texture = this.textures.get(this.tilemapKey);
const frame = texture.get();
const actualWidth = frame.width;
const actualHeight = frame.height;
console.log(`瓦片图实际尺寸: ${actualWidth}x${actualHeight}`);
// 直接添加完整瓦片图,不裁剪,不缩放
const fullTilemap = this.add.image(0, 0, this.tilemapKey);
fullTilemap.setOrigin(0, 0);
fullTilemap.setScale(1);
this.tileSelectionContainer.add(fullTilemap);
// 根据用户提供的精确信息:图片288*208,瓦片16*16,18*13排列
const tileWidth = 16; // 瓦片大小16x16px
const tileHeight = 16;
const spacing = 0; // 瓦片之间没有间距(288/18=16,208/13=16)
const columns = 18; // 18列
const rows = 13; // 13行
console.log(`瓦片配置:大小${tileWidth}x${tileHeight},间距${spacing},${columns}x${rows}排列`);
// 为每个瓦片位置添加透明的交互式矩形,用于悬停高亮和点击选择
for (let i = 0; i < this.tileCount; i++) {
const col = i % columns;
const row = Math.floor(i / columns);
// 精确计算瓦片在实际图片中的位置(无间距)
const tileX = col * tileWidth;
const tileY = row * tileHeight;
console.log(`瓦片 ${i} 索引 -> 行列: (${col}, ${row}) -> 位置: (${tileX}, ${tileY}), 大小: ${tileWidth}x${tileHeight}`);
// 创建透明的交互式矩形,精确对齐瓦片
// 使用add.zone创建透明区域,专门用于交互
const tileZone = this.add.zone(tileX, tileY, tileWidth, tileHeight);
tileZone.setOrigin(0, 0);
tileZone.setInteractive({ useHandCursor: true });
this.tileSelectionContainer.add(tileZone);
// 瓦片点击事件
tileZone.on('pointerdown', () => {
console.log(`点击了瓦片 ${i},行列: (${col}, ${row})`);
this.selectTile(i);
});
// 悬停高亮效果
tileZone.on('pointerover', () => {
// 创建临时高亮矩形
if (!this.highlightRect) {
this.highlightRect = this.add.rectangle(tileX, tileY, tileWidth, tileHeight, 0xffffff, 0.3);
this.highlightRect.setOrigin(0, 0);
this.tileSelectionContainer.add(this.highlightRect);
} else {
this.highlightRect.setPosition(tileX, tileY);
}
});
tileZone.on('pointerout', () => {
// 移除高亮效果
if (this.highlightRect) {
this.highlightRect.destroy();
this.highlightRect = null;
}
});
}
console.log('瓦片选择区域已更新,直接显示完整瓦片图');
} else {
console.error(`纹理 ${this.tilemapKey} 不存在!`);
}
} catch (error) {
console.error('更新瓦片选择显示失败:', error);
}
}
/**
* 选择瓦片
* @param {number} tileIndex - 瓦片索引
*/
selectTile(tileIndex) {
// 防御性编程:检查参数类型
if (typeof tileIndex !== 'number') {
console.error('selectTile: tileIndex 必须是数字类型');
return;
}
this.selectedTile = tileIndex;
console.log(`选择瓦片索引: ${tileIndex}`);
// 更新选中瓦片显示
// 注意:使用Container对象的removeAll方法,而不是Rectangle对象
try {
// 防御性编程:检查容器是否存在
if (this.selectedTileContainer && typeof this.selectedTileContainer.removeAll === 'function') {
this.selectedTileContainer.removeAll(true);
} else {
console.error('selectTile: selectedTileContainer 不存在或没有 removeAll 方法');
return;
}
} catch (error) {
console.error('selectTile: 清空选中瓦片容器失败:', error);
return;
}
if (this.selectedTile !== null && this.selectedTile !== -1) {
try {
// 防御性编程:检查瓦片索引是否在有效范围内
if (this.selectedTile >= 0 && this.selectedTile < this.tileCount) {
// 防御性编程:检查纹理是否存在
if (this.textures.exists(this.tilemapKey)) {
// 根据用户提供的精确信息:瓦片16*16,无间距,18*13排列
const tileWidth = 16;
const tileHeight = 16;
const spacing = 0;
const columns = 18;
// 计算瓦片在大图中的位置
const col = this.selectedTile % columns;
const row = Math.floor(this.selectedTile / columns);
// 计算裁剪区域 - 正确使用图块对应的左上角像素位置
const cropWidth = tileWidth;
const cropHeight = tileHeight;
// 计算图块在大图中的精确左上角像素位置
const frameX = col * tileWidth;
const frameY = row * tileHeight;
// 创建一个新的image,专门用于显示选中的瓦片
const tile = this.add.image(0, 0, this.tilemapKey);
tile.setOrigin(0, 0);
// 先设置裁剪区域,使用图块在大图中的精确位置作为起始点
tile.setCrop(frameX, frameY, cropWidth, cropHeight);
// 然后设置缩放,放大显示
tile.setScale(2);
this.selectedTileContainer.add(tile);
// 添加选中边框,匹配放大后的瓦片大小
const border = this.add.rectangle(0, 0, 64, 64, 0x00ff00, 0);
border.setOrigin(0, 0);
border.setStrokeStyle(2, 0x00ff00, 1);
this.selectedTileContainer.add(border);
} else {
console.error(`selectTile: 纹理 ${this.tilemapKey} 不存在`);
}
} else {
console.error(`selectTile: 瓦片索引 ${this.selectedTile} 超出范围 (0-${this.tileCount-1})`);
}
} catch (error) {
console.error('selectTile: 显示选中瓦片失败:', error);
}
} else if (this.selectedTile === -1) {
// 显示删除模式
try {
const deleteText = this.add.text(0, 20, '删除模式', {
fontSize: '14px',
fill: '#ff0000',
fontFamily: 'Arial',
fontWeight: 'bold'
});
deleteText.setOrigin(0, 0);
this.selectedTileContainer.add(deleteText);
} catch (error) {
console.error('selectTile: 显示删除模式失败:', error);
}
}
}
/**
* 设置输入处理
*/
setupInput() {
// 初始化拖动绘制相关变量
this.isDrawing = false;
this.lastDrawnTile = null;
// 鼠标输入
this.input.on('pointerdown', (pointer) => {
this.handleMouseDown(pointer);
// 开始绘制
this.isDrawing = true;
this.lastDrawnTile = null;
});
this.input.on('pointerup', (pointer) => {
this.handleMouseUp(pointer);
// 停止绘制
this.isDrawing = false;
this.lastDrawnTile = null;
});
this.input.on('pointermove', (pointer) => {
this.handleMouseMove(pointer);
// 拖动绘制:如果鼠标按下且不是在拖拽地图,则绘制瓦片
if (this.isDrawing && !this.isDragging) {
this.placeTile(pointer);
}
});
// 滚轮缩放
this.input.on('wheel', (pointer, gameObjects, deltaX, deltaY, deltaZ) => {
this.handleWheel(deltaY);
});
// 键盘输入
this.setupKeyboardInput();
}
/**
* 设置键盘输入
*/
setupKeyboardInput() {
// 空格键返回启动场景
this.input.keyboard.on('keydown-SPACE', () => {
this.scene.start('BootScene');
});
// 数字键1-9选择瓦片
for (let i = 0; i < 9; i++) {
this.input.keyboard.on(`keydown-${i + 1}`, () => {
if (i < this.tileSet.length) {
this.selectTile(i);
}
});
}
// D键删除瓦片
this.input.keyboard.on('keydown-D', () => {
this.selectedTile = -1; // -1表示删除模式
});
// C键清空地图
this.input.keyboard.on('keydown-C', () => {
this.clearMap();
});
// S键保存地图
this.input.keyboard.on('keydown-S', () => {
this.saveMap();
});
// L键加载地图
this.input.keyboard.on('keydown-L', () => {
this.loadMap();
});
}
/**
* 处理鼠标按下事件
*/
handleMouseDown(pointer) {
// 检查是否点击了瓦片选择区域
const tileSelectionRect = new Phaser.Geom.Rectangle(20, 110, 200, 360);
if (Phaser.Geom.Rectangle.Contains(tileSelectionRect, pointer.x, pointer.y)) {
return; // 点击了瓦片选择区域,不处理地图交互
}
// 检查是否点击了控制面板
const controlPanelRect = new Phaser.Geom.Rectangle(this.sys.game.config.width - 210, 10, 200, 150);
if (Phaser.Geom.Rectangle.Contains(controlPanelRect, pointer.x, pointer.y)) {
return; // 点击了控制面板,不处理地图交互
}
// 检查是否点击了当前选中瓦片显示区域
const selectedTileRect = new Phaser.Geom.Rectangle(20, 490, 64, 64);
if (Phaser.Geom.Rectangle.Contains(selectedTileRect, pointer.x, pointer.y)) {
return; // 点击了选中瓦片显示区域,不处理地图交互
}
// 如果点击了地图区域
if (this.selectedTile !== null) {
// 放置或删除瓦片
this.placeTile(pointer);
} else {
// 开始拖拽地图
this.isDragging = true;
this.lastDragPosition.x = pointer.x;
this.lastDragPosition.y = pointer.y;
}
}
/**
* 处理鼠标释放事件
*/
handleMouseUp(pointer) {
this.isDragging = false;
}
/**
* 处理鼠标移动事件
*/
handleMouseMove(pointer) {
if (this.isDragging) {
// 计算拖拽距离
const deltaX = pointer.x - this.lastDragPosition.x;
const deltaY = pointer.y - this.lastDragPosition.y;
// 移动相机
this.cameras.main.scrollX -= deltaX / this.zoomLevel;
this.cameras.main.scrollY -= deltaY / this.zoomLevel;
// 更新上次拖拽位置
this.lastDragPosition.x = pointer.x;
this.lastDragPosition.y = pointer.y;
}
}
/**
* 处理滚轮事件
*/
handleWheel(deltaY) {
// 放大
if (deltaY < 0 && this.zoomLevel < 2) {
this.zoomLevel += 0.1;
}
// 缩小
else if (deltaY > 0 && this.zoomLevel > 0.5) {
this.zoomLevel -= 0.1;
}
// 更新相机缩放
this.cameras.main.setZoom(this.zoomLevel);
}
/**
* 放置瓦片
*/
placeTile(pointer) {
// 将屏幕坐标转换为世界坐标 - 确保与鼠标位置完全匹配
const worldPoint = this.cameras.main.getWorldPoint(pointer.x, pointer.y);
// 计算瓦片坐标 - 使用地图的瓦片大小32px
const mapTileSize = 32;
// 确保鼠标点击位置与绘制位置完全一致
// 使用Math.floor确保点击瓦片的哪个位置都绘制到对应瓦片
const tileX = Math.floor(worldPoint.x / mapTileSize);
const tileY = Math.floor(worldPoint.y / mapTileSize);
// 检查瓦片坐标是否在地图范围内
if (tileX < 0 || tileX >= this.mapWidth || tileY < 0 || tileY >= this.mapHeight) {
return;
}
// 检查是否已经绘制过这个位置,避免重复绘制
if (this.lastDrawnTile && this.lastDrawnTile.x === tileX && this.lastDrawnTile.y === tileY) {
return;
}
// 删除瓦片模式
if (this.selectedTile === -1) {
this.removeTile(tileX, tileY);
} else {
// 放置瓦片 - 使用单张瓦片图
// 检查该位置是否已有瓦片
const existingTile = this.getTileAt(tileX, tileY);
if (existingTile) {
// 删除现有瓦片
existingTile.destroy();
}
// 计算精确的绘制位置 - 确保与鼠标点击的瓦片完全对应
const drawX = tileX * mapTileSize;
const drawY = tileY * mapTileSize;
console.log(`鼠标位置: (${pointer.x}, ${pointer.y}) -> 世界坐标: (${worldPoint.x}, ${worldPoint.y}) -> 瓦片坐标: (${tileX}, ${tileY}) -> 绘制位置: (${drawX}, ${drawY})`);
// 创建新瓦片 - 精确放置在计算出的位置
try {
// 根据用户提供的精确信息:瓦片16*16,无间距,18*13排列
const tileWidth = 16;
const tileHeight = 16;
const columns = 18;
// 计算瓦片在大图中的位置
const col = this.selectedTile % columns;
const row = Math.floor(this.selectedTile / columns);
// 计算裁剪区域 - 正确使用图块对应的左上角像素位置
const cropX = col * tileWidth; // 图块在大图中的x坐标
const cropY = row * tileHeight; // 图块在大图中的y坐标
const cropWidth = tileWidth;
const cropHeight = tileHeight;
console.log(`选中瓦片索引: ${this.selectedTile} -> 行列: (${col}, ${row}) -> 裁剪区域: (${cropX}, ${cropY}, ${cropWidth}, ${cropHeight})`);
// 创建image并设置初始位置
const tile = this.add.image(drawX, drawY, this.tilemapKey);
tile.setOrigin(0, 0);
// 先设置裁剪区域,使用图块在大图中的精确位置
tile.setCrop(cropX, cropY, cropWidth, cropHeight);
// 然后设置缩放,确保瓦片填满地图网格
const scaleFactor = mapTileSize / cropWidth;
tile.setScale(scaleFactor);
console.log(`绘制位置: (${drawX}, ${drawY}), 缩放因子: ${scaleFactor}`);
tile.setDepth(2);
this.mapLayer.add(tile);
// 更新地图数据
this.mapData[tileY][tileX] = this.selectedTile;
} catch (error) {
console.error('放置瓦片失败:', error);
}
}
// 记录最后绘制的瓦片位置
this.lastDrawnTile = { x: tileX, y: tileY };
}
/**
* 删除瓦片
*/
removeTile(tileX, tileY) {
// 检查该位置是否已有瓦片
const existingTile = this.getTileAt(tileX, tileY);
if (existingTile) {
// 删除现有瓦片
existingTile.destroy();
// 更新地图数据
this.mapData[tileY][tileX] = -1;
}
}
/**
* 获取指定位置的瓦片
*/
getTileAt(tileX, tileY) {
const children = this.mapLayer.getAll();
for (const child of children) {
const childTileX = Math.floor(child.x / this.tileSize);
const childTileY = Math.floor(child.y / this.tileSize);
if (childTileX === tileX && childTileY === tileY) {
return child;
}
}
return null;
}
/**
* 清空地图
*/
clearMap() {
// 删除所有瓦片
this.mapLayer.removeAll(true);
// 重置地图数据
for (let y = 0; y < this.mapHeight; y++) {
for (let x = 0; x < this.mapWidth; x++) {
this.mapData[y][x] = -1;
}
}
console.log('地图已清空');
}
/**
* 保存地图
*/
saveMap() {
// 将地图数据转换为JSON
const mapJson = JSON.stringify(this.mapData);
// 创建下载链接
const blob = new Blob([mapJson], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'map.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log('地图已保存');
}
/**
* 加载地图
*/
loadMap() {
// 创建文件选择器
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
try {
const mapData = JSON.parse(event.target.result);
this.loadMapData(mapData);
} catch (error) {
console.error('加载地图失败:', error);
}
};
reader.readAsText(file);
}
};
input.click();
}
/**
* 加载地图数据
*/
loadMapData(mapData) {
// 清空当前地图
this.clearMap();
// 更新地图数据
this.mapData = mapData;
// 重新绘制地图
for (let y = 0; y < this.mapHeight; y++) {
for (let x = 0; x < this.mapWidth; x++) {
const tileIndex = this.mapData[y][x];
if (tileIndex !== -1 && tileIndex < this.tileSet.length) {
const tileKey = this.tileSet[tileIndex];
try {
const tile = this.add.image(x * this.tileSize, y * this.tileSize, tileKey);
tile.setOrigin(0, 0);
tile.setDepth(2);
this.mapLayer.add(tile);
} catch (error) {
console.error(`加载地图瓦片(${x},${y})失败:`, error);
}
}
}
}
console.log('地图已加载');
}
/**
* 显示提示信息
*/
showInstructions() {
const instructions = [
'地图编辑测试场景',
'点击瓦片选择区域选择瓦片',
'在地图上点击放置瓦片',
'选择瓦片后按D键进入删除模式',
'鼠标拖拽移动地图',
'鼠标滚轮缩放地图',
'按C键清空地图',
'按S键保存地图',
'按L键加载地图',
'按空格键返回启动场景'
];
for (let i = 0; i < instructions.length; i++) {
this.add.text(this.sys.game.config.width - 300, 180 + i * 20, instructions[i], {
fontSize: '12px',
fill: '#ffffff',
fontFamily: 'Arial'
}).setScrollFactor(0, 0).setDepth(11);
}
}
update() {
// 每帧更新
}
}