diff --git a/main.js b/main.js index ccb5c78..7392a40 100644 --- a/main.js +++ b/main.js @@ -24,6 +24,8 @@ import ResourceTestScene from './scenes/ResourceTestScene.js'; import MapEditTestScene from './scenes/MapEditTestScene.js'; // 导入角色动画测试场景 import CharacterAnimationTestScene from './scenes/CharacterAnimationTestScene.js'; +// 导入临时场景 +import TmpScene from './scenes/TmpScene.js'; // 创建游戏的最终配置对象 const config = { @@ -45,7 +47,8 @@ const config = { ItemListTestScene, ResourceTestScene, MapEditTestScene, - CharacterAnimationTestScene + CharacterAnimationTestScene, + TmpScene ] }; diff --git a/scenes/BootScene.js b/scenes/BootScene.js index b4bac62..553a916 100644 --- a/scenes/BootScene.js +++ b/scenes/BootScene.js @@ -19,6 +19,7 @@ export default class BootScene extends Phaser.Scene { // 测试场景列表 const testScenes = [ + { key: 'TmpScene', name: '测试场景13:临时场景' }, { key: 'CharacterAnimationTestScene', name: '测试场景12:角色动画测试' }, { key: 'MapEditTestScene', name: '测试场景11:地图编辑测试' }, { key: 'ResourceTestScene', name: '测试场景10:资源包测试' }, diff --git a/scenes/MapEditTestScene.js b/scenes/MapEditTestScene.js index 56b70b9..5f646ac 100644 --- a/scenes/MapEditTestScene.js +++ b/scenes/MapEditTestScene.js @@ -14,7 +14,7 @@ export default class MapEditTestScene extends Phaser.Scene { constructor() { super({ key: 'MapEditTestScene' }); - this.tileSize = 32; // 地图瓦片大小 + this.tileSize = 16; // 地图瓦片大小 this.selectedTile = null; // 当前选中的瓦片 this.mapLayer = null; // 地图层 this.mapWidth = 50; // 地图宽度(瓦片数量) @@ -26,7 +26,7 @@ export default class MapEditTestScene extends Phaser.Scene { this.tilemapKey = ''; // 单张瓦片图的键名 this.tileCount = 234; // 总瓦片数 this.tileImageSize = 16; // 瓦片在图片中的实际大小 - this.tileSpacing = 1; // 瓦片间距 + this.tileSpacing = 0; // 瓦片间距 this.tileColumns = 18; // 瓦片图列数 this.tileRows = 13; // 瓦片图行数 } @@ -122,7 +122,7 @@ export default class MapEditTestScene extends Phaser.Scene { this.tilemapKey = tilemapKey; // 存储瓦片的位置信息,用于后续切割 this.tileImageSize = 16; // 瓦片大小16x16px - this.tileSpacing = 1; // 瓦片间距1px + this.tileSpacing = 0; // 瓦片间距0px this.tileColumns = 18; // 18列 this.tileRows = 13; // 13行 @@ -249,7 +249,7 @@ export default class MapEditTestScene extends Phaser.Scene { this.selectedTileContainer.setDepth(11); // 添加选中瓦片背景 - const selectedTileBg = this.add.rectangle(0, 0, 64, 64, 0x333333); + const selectedTileBg = this.add.rectangle(0, 0, 16, 16, 0x333333); selectedTileBg.setOrigin(0, 0); selectedTileBg.setDepth(10); this.selectedTileContainer.add(selectedTileBg); @@ -354,44 +354,57 @@ export default class MapEditTestScene extends Phaser.Scene { fullTilemap.setScale(1); this.tileSelectionContainer.add(fullTilemap); - // 计算每个瓦片在实际图片中的位置和大小 + // 根据用户提供的精确信息:图片288*208,瓦片16*16,18*13排列 const tileWidth = 16; // 瓦片大小16x16px const tileHeight = 16; - const spacing = 1; // 瓦片间距1px + 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 + spacing); - const tileY = row * (tileHeight + spacing); + // 精确计算瓦片在实际图片中的位置(无间距) + const tileX = col * tileWidth; + const tileY = row * tileHeight; - console.log(`瓦片 ${i} 位置: (${tileX}, ${tileY}), 大小: ${tileWidth}x${tileHeight}`); + console.log(`瓦片 ${i} 索引 -> 行列: (${col}, ${row}) -> 位置: (${tileX}, ${tileY}), 大小: ${tileWidth}x${tileHeight}`); // 创建透明的交互式矩形,精确对齐瓦片 - const tileRect = this.add.rectangle(tileX, tileY, tileWidth, tileHeight, 0x000000, 0); - tileRect.setOrigin(0, 0); - tileRect.setInteractive({ useHandCursor: true }); - this.tileSelectionContainer.add(tileRect); + // 使用add.zone创建透明区域,专门用于交互 + const tileZone = this.add.zone(tileX, tileY, tileWidth, tileHeight); + tileZone.setOrigin(0, 0); + tileZone.setInteractive({ useHandCursor: true }); + this.tileSelectionContainer.add(tileZone); // 瓦片点击事件 - tileRect.on('pointerdown', () => { - console.log(`点击了瓦片 ${i},位置: (${tileX}, ${tileY})`); + tileZone.on('pointerdown', () => { + console.log(`点击了瓦片 ${i},行列: (${col}, ${row})`); this.selectTile(i); }); // 悬停高亮效果 - tileRect.on('pointerover', () => { - // 创建高亮效果 - tileRect.setFillStyle(0xffffff, 0.3); + 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); + } }); - tileRect.on('pointerout', () => { + tileZone.on('pointerout', () => { // 移除高亮效果 - tileRect.setFillStyle(0x000000, 0); + if (this.highlightRect) { + this.highlightRect.destroy(); + this.highlightRect = null; + } }); } @@ -439,22 +452,37 @@ export default class MapEditTestScene extends Phaser.Scene { 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 % this.tileColumns; - const row = Math.floor(this.selectedTile / this.tileColumns); + const col = this.selectedTile % columns; + const row = Math.floor(this.selectedTile / columns); - // 计算源矩形 - const frameX = col * (this.tileSize + this.tileSpacing); - const frameY = row * (this.tileSize + this.tileSpacing); + // 计算裁剪区域 - 正确使用图块对应的左上角像素位置 + 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, this.tileSize, this.tileSize); - tile.setScale(2); // 放大显示 + + // 先设置裁剪区域,使用图块在大图中的精确位置作为起始点 + 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); @@ -645,11 +673,14 @@ export default class MapEditTestScene extends Phaser.Scene { * 放置瓦片 */ 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); @@ -676,22 +707,44 @@ export default class MapEditTestScene extends Phaser.Scene { 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 { - const tile = this.add.image(tileX * mapTileSize, tileY * mapTileSize, this.tilemapKey); - tile.setOrigin(0, 0); + // 根据用户提供的精确信息:瓦片16*16,无间距,18*13排列 + const tileWidth = 16; + const tileHeight = 16; + const columns = 18; // 计算瓦片在大图中的位置 - const col = this.selectedTile % this.tileColumns; - const row = Math.floor(this.selectedTile / this.tileColumns); + const col = this.selectedTile % columns; + const row = Math.floor(this.selectedTile / columns); - // 设置裁剪区域,只显示当前瓦片 - const frameX = col * (this.tileSize + this.tileSpacing); - const frameY = row * (this.tileSize + this.tileSpacing); - tile.setCrop(frameX, frameY, this.tileSize, this.tileSize); + // 计算裁剪区域 - 正确使用图块对应的左上角像素位置 + 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}`); - // 缩放瓦片以适应地图的32x32图块 - tile.setScale(mapTileSize / this.tileSize); tile.setDepth(2); this.mapLayer.add(tile); diff --git a/scenes/TmpScene.js b/scenes/TmpScene.js new file mode 100644 index 0000000..ecb9d9c --- /dev/null +++ b/scenes/TmpScene.js @@ -0,0 +1,115 @@ +export default class TmpScene extends Phaser.Scene { + constructor() { + super({ key: 'TmpScene' }); + } + + preload() { + // 加载资源 + } + + create() { + // 创建场景 + // 物理世界和相机边界 + 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(); + } + + 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 tilePanelX = 10; + const tilePanelY = 10; + const chunkSize = 16; + const tilePictureSizeX = 288; + const tilePictureSizeY = 208; + + // 瓦片选择区域背景 + const tilePanel = this.add.rectangle(tilePanelX, tilePanelY, tilePictureSizeX, tilePictureSizeY+chunkSize, 0x111111, 0.8); + tilePanel.setOrigin(0, 0); + tilePanel.setScrollFactor(0, 0); + tilePanel.setDepth(10); + + // 瓦片选择区域标题 + this.add.text(tilePanelX, tilePanelY, '瓦片选择', { + fontSize: '16px', + fill: '#ffffff', + fontFamily: 'Arial', + fontWeight: 'bold' + }).setScrollFactor(0, 0).setDepth(11); + + // 瓦片选择容器 - 注意:这是一个Container对象,可以使用removeAll方法 + this.tileSelectionContainer = this.add.container(tilePanelX, tilePanelY+tilePictureSizeY+chunkSize); + this.tileSelectionContainer.setScrollFactor(0, 0); + this.tileSelectionContainer.setDepth(11); + + // 当前选中瓦片显示 - 改为使用Container容器,而不是Rectangle,这样可以使用removeAll方法 + this.selectedTileContainer = this.add.container(tilePanelX, tilePanelY+tilePictureSizeY+chunkSize*2); + 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(tilePanelX, tilePanelY+tilePictureSizeY+chunkSize, '当前选中瓦片:', { + fontSize: '16px', + fill: '#ffffff', + fontFamily: 'Arial' + }).setScrollFactor(0, 0).setDepth(11); + } +} \ No newline at end of file