mirror of
http://junepve.top:3000/chicrobot/CINC.git
synced 2026-10-30 05:41:29 +08:00
refactor(scenes) 将测试场景移动到测试场景testScenes目录下
This commit is contained in:
1 parent
dabe9ed2ef
commit
f6874d1ee9
14 files changed
+63
-63
No files matched your search
@@ -0,0 +1,829 @@
|
||||
export default class MapEditTestScene extends Phaser.Scene {
|
||||
constructor() {
|
||||
super({ key: 'MapEditTestScene' });
|
||||
this.selectedTile = null; // 当前选中的瓦片
|
||||
this.mapLayer = null; // 地图层
|
||||
|
||||
this.mapWidth = 50; // 地图宽度(瓦片数量)
|
||||
this.mapHeight = 50; // 地图高度(瓦片数量)
|
||||
|
||||
this.tileSize = 16; // 地图瓦片大小
|
||||
this.tileSet = []; // 存储所有瓦片资源的键名
|
||||
this.tileCount = 234; // 总瓦片数(从tile_0000到tile_0233)
|
||||
|
||||
// 地形类型配置
|
||||
this.terrainTypes = {
|
||||
0: { name: '平原', color: 0x4CAF50, passable: true, speed: 1.0 },
|
||||
1: { name: '森林', color: 0x2E7D32, passable: true, speed: 0.7 },
|
||||
2: { name: '山地', color: 0x795548, passable: false, speed: 0.0 },
|
||||
3: { name: '水域', color: 0x2196F3, passable: false, speed: 0.0 },
|
||||
4: { name: '道路', color: 0x9E9E9E, passable: true, speed: 1.5 }
|
||||
};
|
||||
this.selectedTerrain = 0; // 当前选中的地形类型
|
||||
this.isTerrainMode = false; // 是否处于地形编辑模式
|
||||
}
|
||||
|
||||
preload() {
|
||||
// 加载资源
|
||||
// 加载瓦片资源
|
||||
this.loadTileAssets();
|
||||
// 显示加载进度
|
||||
this.createLoadingUI();
|
||||
// 加载完成后移除加载UI
|
||||
this.load.on('complete', () => {
|
||||
this.loadingText.destroy();
|
||||
this.progressBar.destroy();
|
||||
this.progressFill.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
// 设置输入处理
|
||||
console.log('设置输入处理');
|
||||
this.setupInput();
|
||||
|
||||
// 创建场景
|
||||
// 物理世界和相机边界
|
||||
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');
|
||||
|
||||
// 创建地图编辑区域
|
||||
console.log('创建地图编辑区域');
|
||||
this.createMapArea();
|
||||
|
||||
// 创建瓦片选择区域
|
||||
console.log('创建瓦片选择区域');
|
||||
this.createTileSelectionArea();
|
||||
|
||||
// 检查资源是否已加载
|
||||
if (this.assetsLoaded) {
|
||||
console.log('资源已加载,调用updateTileSelection');
|
||||
this.updateTileSelection();
|
||||
} else {
|
||||
console.log('资源尚未加载,等待加载完成');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadTileAssets() {
|
||||
console.log('开始加载瓦片资源');
|
||||
|
||||
// 加载Tiles目录下的多个瓦片图(从tile_0000到tile_0233)
|
||||
this.tileSet = [];
|
||||
const tileBasePath = 'assets/PNG/Tiles/Tiles/';
|
||||
|
||||
for (let i = 0; i < this.tileCount; i++) {
|
||||
const tileIndex = String(i).padStart(4, '0');
|
||||
const tileKey = `tile_${tileIndex}`;
|
||||
const tilePath = `${tileBasePath}${tileKey}.png`;
|
||||
|
||||
console.log(`加载瓦片: ${tileKey} -> ${tilePath}`);
|
||||
this.load.image(tileKey, tilePath);
|
||||
this.tileSet.push(tileKey);
|
||||
}
|
||||
|
||||
// 加载进度回调
|
||||
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
|
||||
for (const tileKey of this.tileSet) {
|
||||
if (this.textures.exists(tileKey)) {
|
||||
const texture = this.textures.get(tileKey);
|
||||
texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`瓦片图初始化完成,共 ${this.tileCount} 个瓦片`);
|
||||
// 只有在tileSelectionContainer初始化后才调用updateTileSelection
|
||||
if (this.tileSelectionContainer) {
|
||||
console.log('tileSelectionContainer已初始化,调用updateTileSelection');
|
||||
this.updateTileSelection();
|
||||
} else {
|
||||
console.log('tileSelectionContainer尚未初始化,等待create方法调用');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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)}%`);
|
||||
});
|
||||
}
|
||||
|
||||
updateTileSelection() {
|
||||
console.log('开始更新瓦片选择显示');
|
||||
console.log(`当前瓦片数量: ${this.tileCount}`);
|
||||
|
||||
// 清空当前瓦片选择
|
||||
console.log('清空当前瓦片选择');
|
||||
this.tileSelectionContainer.removeAll(true);
|
||||
|
||||
try {
|
||||
// 定义瓦片排列方式(18列13行,与原来的单张瓦片图保持一致)
|
||||
const tileColumns = 18;
|
||||
const tileRows = 13;
|
||||
|
||||
// 为每个瓦片添加图像和交互区域
|
||||
for (let i = 0; i < this.tileCount; i++) {
|
||||
const tileKey = this.tileSet[i];
|
||||
|
||||
// 检查纹理是否存在
|
||||
if (this.textures.exists(tileKey)) {
|
||||
const col = i % tileColumns;
|
||||
const row = Math.floor(i / tileColumns);
|
||||
|
||||
// 计算瓦片位置
|
||||
const tileX = col * this.tileSize;
|
||||
const tileY = row * this.tileSize;
|
||||
|
||||
console.log(`瓦片 ${i} (${tileKey}) -> 行列: (${col}, ${row}) -> 位置: (${tileX}, ${tileY})`);
|
||||
|
||||
// 添加瓦片图像
|
||||
const tileImage = this.add.image(tileX, tileY, tileKey);
|
||||
tileImage.setOrigin(0, 0);
|
||||
tileImage.setScale(1);
|
||||
this.tileSelectionContainer.add(tileImage);
|
||||
|
||||
// 创建透明的交互式矩形,用于悬停高亮和点击选择
|
||||
const tileZone = this.add.zone(tileX, tileY, this.tileSize, this.tileSize);
|
||||
tileZone.setOrigin(0, 0);
|
||||
tileZone.setInteractive({ useHandCursor: true });
|
||||
this.tileSelectionContainer.add(tileZone);
|
||||
|
||||
// 瓦片点击事件
|
||||
tileZone.on('pointerdown', () => {
|
||||
console.log(`点击了瓦片 ${i} (${tileKey}),行列: (${col}, ${row})`);
|
||||
this.selectTile(i);
|
||||
});
|
||||
|
||||
// 悬停高亮效果
|
||||
tileZone.on('pointerover', () => {
|
||||
// 创建临时高亮矩形
|
||||
if (!this.highlightRect) {
|
||||
this.highlightRect = this.add.rectangle(tileX, tileY, this.tileSize, this.tileSize, 0xffffff, 0.3);
|
||||
this.highlightRect.setOrigin(0, 0);
|
||||
this.highlightRect.setDepth(12);
|
||||
this.tileSelectionContainer.add(this.highlightRect);
|
||||
} else {
|
||||
this.highlightRect.setPosition(tileX, tileY);
|
||||
}
|
||||
});
|
||||
|
||||
tileZone.on('pointerout', () => {
|
||||
// 移除高亮效果
|
||||
if (this.highlightRect) {
|
||||
this.highlightRect.destroy();
|
||||
this.highlightRect = null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error(`纹理 ${tileKey} 不存在!`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('瓦片选择区域已更新,显示所有独立瓦片');
|
||||
} catch (error) {
|
||||
console.error('更新瓦片选择显示失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
setupInput() {
|
||||
// 初始化拖动绘制相关变量
|
||||
this.isDrawing = false;
|
||||
this.lastDrawnTile = null;
|
||||
this.isDragging = false;
|
||||
this.lastDragPosition = { x: 0, y: 0 };
|
||||
|
||||
// 鼠标输入
|
||||
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.keyboard.on('keydown-SPACE', () => {
|
||||
this.scene.start('BootScene');
|
||||
});
|
||||
|
||||
// D键进入删除模式
|
||||
this.input.keyboard.on('keydown-D', () => {
|
||||
this.selectedTile = -1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理鼠标按下事件
|
||||
*/
|
||||
handleMouseDown(pointer) {
|
||||
// 检查是否点击了瓦片选择区域
|
||||
const tileSelectionRect = new Phaser.Geom.Rectangle(10, 26, 288, 208);
|
||||
if (Phaser.Geom.Rectangle.Contains(tileSelectionRect, 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.cameras.main.scrollY -= deltaY;
|
||||
|
||||
// 更新上次拖拽位置
|
||||
this.lastDragPosition.x = pointer.x;
|
||||
this.lastDragPosition.y = pointer.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
// 初始化空地图,数据结构改为包含瓦片索引和地形ID的对象
|
||||
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] = { tileIndex: -1, terrainId: 0 }; // tileIndex: -1表示空瓦片,terrainId: 0表示默认地形
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//创建背景网格
|
||||
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 tilePanelX = 10;
|
||||
const tilePanelY = 10;
|
||||
|
||||
// 定义瓦片排列方式(18列13行,与原来的单张瓦片图保持一致)
|
||||
const tileColumns = 18;
|
||||
const tileRows = 13;
|
||||
|
||||
// 瓦片选择区域标题
|
||||
this.add.text(tilePanelX, tilePanelY, '瓦片选择', {
|
||||
fontSize: this.tileSize+'px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial',
|
||||
fontWeight: 'bold'
|
||||
}).setScrollFactor(0, 0).setDepth(11);
|
||||
|
||||
// 瓦片选择区域背景
|
||||
const tilePanel = this.add.rectangle(tilePanelX, tilePanelY+this.tileSize, tileColumns*this.tileSize, tileRows*this.tileSize, 0x111111, 0.8);
|
||||
tilePanel.setOrigin(0, 0);
|
||||
tilePanel.setScrollFactor(0, 0);
|
||||
tilePanel.setDepth(10);
|
||||
|
||||
|
||||
// 瓦片选择容器 - 注意:这是一个Container对象,可以使用removeAll方法
|
||||
this.tileSelectionContainer = this.add.container(tilePanelX, tilePanelY+this.tileSize);
|
||||
this.tileSelectionContainer.setScrollFactor(0, 0);
|
||||
this.tileSelectionContainer.setDepth(11);
|
||||
|
||||
// 当前选中瓦片显示 - 改为使用Container容器,而不是Rectangle,这样可以使用removeAll方法
|
||||
this.selectedTileContainer = this.add.container(tilePanelX, tilePanelY+(tileRows+1)*this.tileSize+16);
|
||||
this.selectedTileContainer.setScrollFactor(0, 0);
|
||||
this.selectedTileContainer.setDepth(11);
|
||||
|
||||
// 添加选中瓦片背景
|
||||
const selectedTileBg = this.add.rectangle(0, 0, 32, 32, 0x333333);
|
||||
selectedTileBg.setOrigin(0, 0);
|
||||
selectedTileBg.setDepth(10);
|
||||
this.selectedTileContainer.add(selectedTileBg);
|
||||
|
||||
this.add.text(tilePanelX, tilePanelY+(tileRows+1)*this.tileSize, '当前选中瓦片:', {
|
||||
fontSize: this.tileSize+'px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
}).setScrollFactor(0, 0).setDepth(11);
|
||||
|
||||
// 地形选择区域
|
||||
const terrainPanelY = tilePanelY+(tileRows+1)*this.tileSize+64;
|
||||
|
||||
// 地形选择标题
|
||||
this.add.text(tilePanelX, terrainPanelY, '地形类型', {
|
||||
fontSize: this.tileSize+'px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial',
|
||||
fontWeight: 'bold'
|
||||
}).setScrollFactor(0, 0).setDepth(11);
|
||||
|
||||
// 地形选择容器
|
||||
this.terrainSelectionContainer = this.add.container(tilePanelX, terrainPanelY+this.tileSize);
|
||||
this.terrainSelectionContainer.setScrollFactor(0, 0);
|
||||
this.terrainSelectionContainer.setDepth(11);
|
||||
|
||||
// 添加地形选择按钮
|
||||
let terrainX = 0;
|
||||
let terrainY = 0;
|
||||
const terrainButtonSize = 24;
|
||||
const terrainSpacing = 8;
|
||||
|
||||
for (const [id, terrain] of Object.entries(this.terrainTypes)) {
|
||||
// 地形按钮背景
|
||||
const terrainButton = this.add.rectangle(terrainX, terrainY, terrainButtonSize, terrainButtonSize, terrain.color, 0.8);
|
||||
terrainButton.setOrigin(0, 0);
|
||||
terrainButton.setInteractive({ useHandCursor: true });
|
||||
terrainButton.setData('terrainId', parseInt(id));
|
||||
this.terrainSelectionContainer.add(terrainButton);
|
||||
|
||||
// 地形按钮文本
|
||||
this.terrainSelectionContainer.add(this.add.text(
|
||||
terrainX + 4,
|
||||
terrainY + 2,
|
||||
id,
|
||||
{
|
||||
fontSize: '12px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
).setOrigin(0, 0));
|
||||
|
||||
// 地形按钮点击事件
|
||||
terrainButton.on('pointerdown', () => {
|
||||
this.selectTerrain(terrainButton.getData('terrainId'));
|
||||
});
|
||||
|
||||
// 更新位置
|
||||
terrainX += terrainButtonSize + terrainSpacing;
|
||||
if (terrainX >= 200) {
|
||||
terrainX = 0;
|
||||
terrainY += terrainButtonSize + terrainSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// 当前选中地形显示
|
||||
this.selectedTerrainText = this.add.text(
|
||||
tilePanelX,
|
||||
terrainPanelY+this.tileSize+terrainY+20,
|
||||
`当前地形: ${this.terrainTypes[this.selectedTerrain].name}`,
|
||||
{
|
||||
fontSize: '12px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
}
|
||||
).setScrollFactor(0, 0).setDepth(11);
|
||||
|
||||
// 地形模式切换按钮
|
||||
const terrainModeY = terrainPanelY+this.tileSize+terrainY+40;
|
||||
this.terrainModeButton = this.add.rectangle(tilePanelX, terrainModeY, 120, 24, 0x333333, 0.8);
|
||||
this.terrainModeButton.setOrigin(0, 0);
|
||||
this.terrainModeButton.setInteractive({ useHandCursor: true });
|
||||
this.terrainModeButton.setDepth(11);
|
||||
|
||||
// 地形模式按钮文本
|
||||
this.terrainModeText = this.add.text(
|
||||
tilePanelX + 10,
|
||||
terrainModeY + 4,
|
||||
'切换到地形模式',
|
||||
{
|
||||
fontSize: '12px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
}
|
||||
).setScrollFactor(0, 0).setDepth(12);
|
||||
|
||||
// 地形模式切换事件
|
||||
this.terrainModeButton.on('pointerdown', () => {
|
||||
this.toggleTerrainMode();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择地形
|
||||
*/
|
||||
selectTerrain(terrainId) {
|
||||
this.selectedTerrain = terrainId;
|
||||
this.selectedTerrainText.setText(`当前地形: ${this.terrainTypes[this.selectedTerrain].name}`);
|
||||
console.log(`选择了地形: ${this.terrainTypes[this.selectedTerrain].name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换地形模式
|
||||
*/
|
||||
toggleTerrainMode() {
|
||||
this.isTerrainMode = !this.isTerrainMode;
|
||||
|
||||
if (this.isTerrainMode) {
|
||||
this.terrainModeButton.setFillStyle(0x00ff00, 0.8);
|
||||
this.terrainModeText.setText('地形模式: 开启');
|
||||
this.terrainModeText.setFill('#00ff00');
|
||||
} else {
|
||||
this.terrainModeButton.setFillStyle(0x333333, 0.8);
|
||||
this.terrainModeText.setText('切换到地形模式');
|
||||
this.terrainModeText.setFill('#ffffff');
|
||||
}
|
||||
|
||||
console.log(`地形模式已${this.isTerrainMode ? '开启' : '关闭'}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择瓦片
|
||||
* @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) {
|
||||
const tileKey = this.tileSet[this.selectedTile];
|
||||
|
||||
// 防御性编程:检查纹理是否存在
|
||||
if (this.textures.exists(tileKey)) {
|
||||
// 创建一个新的image,专门用于显示选中的瓦片
|
||||
const tile = this.add.image(0, 0, tileKey);
|
||||
tile.setOrigin(0, 0);
|
||||
|
||||
// 放大显示
|
||||
tile.setScale(2);
|
||||
|
||||
this.selectedTileContainer.add(tile);
|
||||
|
||||
// 添加选中边框,匹配放大后的瓦片大小
|
||||
const border = this.add.rectangle(0, 0, this.tileSize*2, this.tileSize*2, 0x00ff00, 0);
|
||||
border.setOrigin(0, 0);
|
||||
border.setStrokeStyle(2, 0x00ff00, 1);
|
||||
this.selectedTileContainer.add(border);
|
||||
|
||||
// 显示瓦片索引和行列信息
|
||||
const columns = 18; // 瓦片排列列数
|
||||
const row = Math.floor(this.selectedTile / columns);
|
||||
const col = this.selectedTile % columns;
|
||||
|
||||
// 瓦片索引文本
|
||||
this.selectedTileContainer.add(this.add.text(
|
||||
40, 0,
|
||||
`索引: ${this.selectedTile}`,
|
||||
{
|
||||
fontSize: '12px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
}
|
||||
).setOrigin(0, 0));
|
||||
|
||||
// 瓦片行列文本
|
||||
this.selectedTileContainer.add(this.add.text(
|
||||
40, 16,
|
||||
`行列: (${col},${row})`,
|
||||
{
|
||||
fontSize: '12px',
|
||||
fill: '#ffffff',
|
||||
fontFamily: 'Arial'
|
||||
}
|
||||
).setOrigin(0, 0));
|
||||
} else {
|
||||
console.error(`selectTile: 纹理 ${tileKey} 不存在`);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 放置瓦片或设置地形
|
||||
*/
|
||||
placeTile(pointer) {
|
||||
// 将屏幕坐标转换为世界坐标
|
||||
const worldPoint = this.cameras.main.getWorldPoint(pointer.x, pointer.y);
|
||||
|
||||
// 计算瓦片坐标
|
||||
const tileX = Math.floor(worldPoint.x / this.tileSize);
|
||||
const tileY = Math.floor(worldPoint.y / this.tileSize);
|
||||
|
||||
// 检查瓦片坐标是否在地图范围内
|
||||
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.isTerrainMode) {
|
||||
// 更新地图数据中的地形ID
|
||||
this.mapData[tileY][tileX].terrainId = this.selectedTerrain;
|
||||
console.log(`已设置瓦片(${tileX},${tileY})的地形为: ${this.terrainTypes[this.selectedTerrain].name}`);
|
||||
}
|
||||
// 瓦片模式:放置或删除瓦片
|
||||
else if (this.selectedTile === -1) {
|
||||
this.removeTile(tileX, tileY);
|
||||
} else {
|
||||
// 放置瓦片
|
||||
const tileKey = this.tileSet[this.selectedTile];
|
||||
|
||||
// 检查该位置是否已有瓦片
|
||||
const existingTile = this.getTileAt(tileX, tileY);
|
||||
if (existingTile) {
|
||||
// 删除现有瓦片
|
||||
existingTile.destroy();
|
||||
}
|
||||
|
||||
// 计算精确的绘制位置
|
||||
const drawX = tileX * this.tileSize;
|
||||
const drawY = tileY * this.tileSize;
|
||||
|
||||
console.log(`鼠标位置: (${pointer.x}, ${pointer.y}) -> 世界坐标: (${worldPoint.x}, ${worldPoint.y}) -> 瓦片坐标: (${tileX}, ${tileY}) -> 绘制位置: (${drawX}, ${drawY})`);
|
||||
|
||||
// 创建新瓦片
|
||||
try {
|
||||
const tile = this.add.image(drawX, drawY, tileKey);
|
||||
tile.setOrigin(0, 0);
|
||||
tile.setDepth(2);
|
||||
this.mapLayer.add(tile);
|
||||
|
||||
// 更新地图数据,包含瓦片索引和地形ID
|
||||
this.mapData[tileY][tileX] = {
|
||||
tileIndex: this.selectedTile,
|
||||
terrainId: this.selectedTerrain
|
||||
};
|
||||
} 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] = {
|
||||
tileIndex: -1,
|
||||
terrainId: this.mapData[tileY][tileX].terrainId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定位置的瓦片
|
||||
*/
|
||||
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] = { tileIndex: -1, terrainId: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
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 tileData = typeof this.mapData[y][x] === 'object' ? this.mapData[y][x] : { tileIndex: this.mapData[y][x], terrainId: 0 };
|
||||
const tileIndex = tileData.tileIndex;
|
||||
|
||||
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('地图已加载');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user