egret白鹭网格布局手势移动实现(从一个格子移动到相邻的另一个格子)
初始化布局
/** * 单元格数量 */ private cellCount: number = 16 /** * 单元格行高 */ private rowHeight: number = 10 /** * 单元格列宽 */ private colWidth: number = 10 /** * 单元格坐标点字典 */ private cellPointDic: Dictionary<Array<egret.Point>> /** * 网格区域 */ private groupGridArea: eui.Group /** * 方块容器 Group 起始标识 */ private groupIdStart: number = 1000 /** * 方块容器 Group 标识 */ private groupId: number = 1000 /** * 方块起始标识 */ private blockIdStart: number = 1000 /** * 方块标识 */ private blockId: number = 1000 /** * 当前激活的方块颜色 */ private activeBlockColor: string = '' /** * 游戏数据字典 */ private gameDatas: Array<GameData> /** * 加载游戏配置 */ private loadGameConfig(): void { const gameConfig = this.roundGameConfigs[this.currGameConfigIndex] const { RowCount, ColCount, Blocks } = gameConfig this.containerArea.removeChildren() this.groupId = this.groupIdStart this.blockId = this.blockIdStart // 生成游戏数据字典 this.gameDatas = new Array<GameData>() const validColors = Array.from(new Set(Blocks.map(x => x.Color))) const colorKeys = Object.keys(ColorEnum).filter(x => validColors.includes(x)) let colorItem: string, gameData: GameData for (let i = 0; i < colorKeys.length; i++) { colorItem = colorKeys[i] gameData = new GameData() gameData.Color = colorItem gameData.StartEndIndexs = Blocks.filter(x => x.Color === gameData.Color).map(x => x.Index) this.gameDatas.push(gameData) } // 绘制底色 let shape: egret.Shape = new egret.Shape(), grap = shape.graphics grap.beginFill(0x1E254B, 1) grap.drawRect(0, 0, this.containerArea.width, this.containerArea.height) grap.endFill() this.containerArea.addChild(shape) // 添加网格并绘制网格线 this.groupGridArea = new eui.Group() const margin = 8 this.groupGridArea.name = 'gridArea', this.groupGridArea.width = this.containerArea.width - margin * 2, this.groupGridArea.height = this.containerArea.height - margin * 2, this.groupGridArea.horizontalCenter = 0, this.groupGridArea.verticalCenter = 0, this.groupGridArea.touchEnabled = false, this.groupGridArea.touchChildren = false // 计算行高列宽 this.cellCount = RowCount * ColCount, this.rowHeight = this.groupGridArea.height / RowCount, this.colWidth = this.groupGridArea.width / ColCount shape = new egret.Shape(), grap = shape.graphics // 调试,显示网格区域 // grap.beginFill(0xECECEC, 1) // grap.drawRect(0, 0, gridArea.width, gridArea.height) // 生成网格布局 const tileLayout = new eui.TileLayout() tileLayout.requestedRowCount = RowCount, tileLayout.requestedColumnCount = ColCount, tileLayout.horizontalGap = 0, tileLayout.verticalGap = 0, tileLayout.rowHeight = this.rowHeight, tileLayout.columnWidth = this.colWidth this.groupGridArea.layout = tileLayout // 绘制网格线 grap.lineStyle(3, 0x5F7B98) for (let i = 0; i < RowCount + 1; i++) { grap.moveTo(0, this.rowHeight * i) grap.lineTo(this.groupGridArea.width, this.rowHeight * i) } for (let i = 0; i < ColCount + 1; i++) { grap.moveTo(this.colWidth * i, 0) grap.lineTo(this.colWidth * i, this.groupGridArea.height) } grap.endFill() this.groupGridArea.addChild(shape) // 添加网格格子 let points = new Array<egret.Point>() let cellGroup: eui.Group, cellImage: eui.Image, // 方块 block: Block, // 方块字典项目(存储着方块图片资源名称与描述等数据),格式:{"Desc":"","Source":""} blockDicItem: any, // 每行的列下标,每换一行,列下标重新归零 eachRow_ColIndex = 0, // 当前 Y 轴坐标(方块上或下边线的 Y 轴坐标) currYAxis = 0 for (let i = 0; i < this.cellCount; i++) { cellGroup = new eui.Group() // 格式:方块标识,方块颜色,方块下标,容器标识 cellGroup.name = `,,${i},${this.groupId}`, cellGroup.touchEnabled = false, cellGroup.touchChildren = false // 计算当前方块的四个角坐标点 points = [] // 左上角 points.push(new egret.Point(this.colWidth * eachRow_ColIndex, currYAxis)) // 右上角 points.push(new egret.Point(this.colWidth * (eachRow_ColIndex + 1), currYAxis)) // 计算右下、左下两个角坐标,临时将当前 Y 轴坐标增加一行的高度 currYAxis += this.rowHeight // 右下角 points.push(new egret.Point(this.colWidth * (eachRow_ColIndex + 1), currYAxis)) // 左下角 points.push(new egret.Point(this.colWidth * eachRow_ColIndex, currYAxis)) // 获取当前方块中心点坐标 const certreX = points[0].x + this.colWidth / 2, certreY = points[3].y - this.rowHeight / 2 // 中心点 points.push(new egret.Point(certreX, certreY)) // 将坐标数组存储到方块下标对应的字典中 this.cellPointDic.Set(i.toString(), points) // 将当前 Y 轴坐标恢复到当前行的高度,减去一行的高度,用于计算下一个单元格的上边线两个角的坐标 currYAxis -= this.rowHeight // 列下标自增 eachRow_ColIndex++ // 如果当前方块属于下一行的第一个方块,则将 eachRow_ColIndex 重置为0,当前 Y 轴增加一行的高度 if ((i + 1) % RowCount === 0) { eachRow_ColIndex = 0 currYAxis += this.rowHeight } block = Blocks.find(x => x.Index === i) if (block) { blockDicItem = this.blockDic.Get(block.Color) if (blockDicItem) { cellImage = new eui.Image(blockDicItem.Source) const attData = { Id: this.blockId, Color: block.Color, Index: block.Index } this.blockId++ // 格式:方块标识,方块颜色,方块下标,容器标识 cellGroup.name = `${attData.Id},${attData.Color},${attData.Index},${this.groupId}` cellImage.name = JSON.stringify(attData) cellImage.width = this.colWidth * 0.9, cellImage.height = this.rowHeight * 0.9, cellImage.horizontalCenter = 0, cellImage.verticalCenter = 0 cellGroup.addChild(cellImage) } } // 调试,显示颜色方块 // cellImage = new eui.Image('zylx_block_blue_png') // cellImage.percentWidth = 90, // cellImage.percentHeight = 90, // cellImage.horizontalCenter = 0, // cellImage.verticalCenter = 0 // cellGroup.addChild(cellImage) this.groupGridArea.addChild(cellGroup) this.groupId++ } this.containerArea.addChild(this.groupGridArea)this.groupGridArea.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.onGridTouchBegin, this) this.groupGridArea.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.onGridTouchMove, this) }
从一个单元格移动到上下左右相邻的单元格,不相邻则无效
/** * 单元格坐标点字典 */ private cellPointDic: Dictionary<Array<egret.Point>>/** * 单元格类型枚举 */ private cellTypeEnum = { /** * 无,空白单元格 */ None: 0, /** * 方块 */ Block: 1, /** * 路线 */ Line: 2 } /** * 单元格默认数据 */ private cellDefaultData = { /** * 单元格下标 */ Index: -1, /** * 单元格类型 */ CellType: this.cellTypeEnum.None, /** * 方块或路线的颜色 */ Color: '', /** * 单元格四个角坐标 */ Points: [], /** * 中心点坐标 */ CentrePoint: null } /** * 上一个单元格数据 */ private currCellData = { /** * 单元格下标 */ Index: -1, /** * 单元格类型 */ CellType: this.cellTypeEnum.None, /** * 方块或路线的颜色 */ Color: '', /** * 单元格四个角坐标 */ Points: [], /** * 中心点坐标 */ CentrePoint: null } /** * 上一个单元格数据 */ private prevCellData = { /** * 单元格下标 */ Index: -1, /** * 单元格类型 */ CellType: this.cellTypeEnum.None, /** * 方块或路线的颜色 */ Color: '', /** * 单元格四个角坐标 */ Points: [], /** * 中心点坐标 */ CentrePoint: null } /** * 允许触摸移动 */ private allowTouchMove: boolean = true /** * 网格触摸开始 * @param e 触摸事件参数 */ private onGridTouchBegin(e: egret.TouchEvent): void { const _this = this // 获取触摸点坐标 const { localX, localY } = e // console.log('localX', localX, 'localY', localY) // 查找当前鼠标所处位置的方块 Group const group = this.findBlockGroup(localX, localY) if (!group) return // 当前单元格颜色,当单元格包含方块或路线时才有颜色 let cellColor = group.name.split(',')[1] // 当前单元格下标 const cellIndex = parseInt(group.name.split(',')[2]) // 空白单元格(即不包含方块) if (group.numChildren === 0) { // 禁止触摸移动 this.allowTouchMove = false return }// 允许触摸移动 this.allowTouchMove = true // 当前单元格坐标 const cellPoints = this.cellPointDic.Get(cellIndex.toString()) // 更新上一个单元格数据 this.prevCellData.Index = cellIndex, this.prevCellData.CellType = this.cellTypeEnum.Block, this.prevCellData.Color = cellColor, // Value[4] 表示当前单元格中心点坐标 this.prevCellData.CentrePoint = new egret.Point(cellPoints[4].x, cellPoints[4].y), this.prevCellData.Points = [...cellPoints] // 更新当前单元格数据 this.currCellData.Index = cellIndex, this.currCellData.CellType = this.cellTypeEnum.Block, this.currCellData.Color = cellColor, this.currCellData.CentrePoint = new egret.Point(cellPoints[4].x, cellPoints[4].y), this.currCellData.Points = [...cellPoints] console.log('\n上一个单元格下标', cellIndex, '当前单元格下标', cellIndex) } /** * 网格触摸移动 * @param e 触摸事件参数 */ private onGridTouchMove(e: egret.TouchEvent): void { if (!this.allowTouchMove) { return } const _this = this // 获取触摸点坐标 const { localX, localY } = e // console.log('localX', localX, 'localY', localY) // 查找当前鼠标所处位置的方块 Group const group = this.findBlockGroup(localX, localY) if (!group) return // 当前单元格颜色,当单元格包含方块或路线时才有颜色 let cellColor = group.name.split(',')[1] // 当前单元格下标 const cellIndex = parseInt(group.name.split(',')[2]) // 当前单元格坐标 const cellPoints = this.cellPointDic.Get(cellIndex.toString()) // 如果当前单元格下标与上一个单元格下标相同,则退出 if (cellIndex === this.prevCellData.Index) return //#region 单元格相邻判断 // 获取上一个单元格相邻的单元格下标,即上下左右四个位置,相邻的单元格下标不考虑是否超出非法(例如 0 下标的相邻下标按顺时针顺序有:-4, 1, 4, -1),因为仅用于效验是否是相邻单元格即可 const adjoinCellIndexs = [] adjoinCellIndexs.push(this.prevCellData.Index - this.currCfg.GridColCount) // 上 adjoinCellIndexs.push(this.prevCellData.Index + 1) // 右 adjoinCellIndexs.push(this.prevCellData.Index + this.currCfg.GridColCount) // 下 adjoinCellIndexs.push(this.prevCellData.Index - 1) // 左 // 如果上一个单元格下标相邻的四个单元格下标不包当前单元格下标,则退出操作 if (!adjoinCellIndexs.includes(cellIndex)) return //#endregion // 更新当前单元格数据 this.currCellData.Index = cellIndex, this.currCellData.CellType = this.cellTypeEnum.Block, this.currCellData.Color = cellColor, this.currCellData.CentrePoint = new egret.Point(cellPoints[4].x, cellPoints[4].y), this.currCellData.Points = [...cellPoints] // 获取当前单元格中心点与上一个单元格中心点横坐标(x)差值、纵坐标(y)差值 const xDValue = Math.abs(this.currCellData.CentrePoint.x - this.prevCellData.CentrePoint.x), yDValue = Math.abs(this.currCellData.CentrePoint.y - this.prevCellData.CentrePoint.y) // console.log('当前单元格中心点与上一个单元格中心点横坐标(x)差值', xDValue, '当前单元格中心点与上一个单元格中心点纵坐标(y)差值', yDValue) if (xDValue <= this.colWidth / 2 && yDValue <= this.rowHeight / 2) return console.log('\n有效移动', '上一个单元格下标', this.prevCellData.Index, '当前单元格下标', cellIndex) // 更新上一个单元格数据 this.prevCellData = { ...this.currCellData } }
Dictionary是自己封装的一个字典类
namespace demo { /** * 泛型字典类 * let dictionary = new Dictionary<string>(); // new一个对象 * // 设置属性 * dictionary.Set('gandalf', 'gandalf@email.com'); * dictionary.Set('john', 'johnsnow@email.com'); * dictionary.Set('tyrion', 'tyrion@email.com'); * // 调用 * console.log(dictionary.Size()); * console.log(dictionary.Values()); * console.log(dictionary.Get('tyrion')); */ export class Dictionary<T> { /** * 字典项目 */ private Items = {} /** * 验证指定键是否在字典中 * @param key 键 * @returns 是否存在 */ public Has(key: string): boolean { return key in this.Items } /** * 设置键值 * @param key 键 * @param value 值 */ public Set(key: string, value: T): void { this.Items[key] = value } /** * 移除指定键 * @param key 键 * @returns 是否移除成功 */ public Remove(key: string): boolean { if (this.Has(key)) { delete this.Items[key] return true } return false } /** * 查找特定键的值 * @param key 键 * @returns 值 */ public Get(key: string): T { return this.Has(key) ? this.Items[key] : undefined } /** * 获取字典所有的键 * @returns 键数组 */ public Keys(): Array<string> { let values = new Array<string>()//存到数组中返回 for (let k in this.Items) { if (this.Has(k)) { values.push(this.Items[k]) } } return values } /** * 获取字典所有的值 * @returns 值数组 */ public Values(): Array<T> { // 存到数组中返回 let values = new Array<T>() for (let k in this.Items) { if (this.Has(k)) { values.push(this.Items[k]) } } return values } /** * 获取所有键值 * @returns 键值对对象 */ public GetItems(): object { return this.Items } /** * 清空字典 */ public Clear(): void { this.Items = {} } /** * 获取字典大小 * @returns */ public Size(): number { return Object.keys(this.Items).length } } }
单元格坐标点字典的初始化
/** * 场景加载完成 */ public onComplete() { this.cellPointDic = new Dictionary<Array<egret.Point>>() } /** * 加载游戏配置 */ private loadGameConfig(): void { this.sceneData = this.roundGameConfigs[this.currGameConfigIndex] const { RowCount, ColCount, Blocks } = this.sceneData this.containerArea.removeChildren() this.groupId = this.groupIdStart this.blockId = this.blockIdStart // 生成游戏数据字典 this.blockDatas = new Array<BlockData>() const validColors = Array.from(new Set(Blocks.map(x => x.Color))) const colorKeys = Object.keys(ColorEnum).filter(x => validColors.includes(x)) let colorItem: string, blockData: BlockData for (let i = 0; i < colorKeys.length; i++) { colorItem = colorKeys[i] blockData = new BlockData() blockData.Color = colorItem blockData.StartEndIndexs = Blocks.filter(x => x.Color === blockData.Color).map(x => x.Index) this.blockDatas.push(blockData) } // 绘制底色 let shape: egret.Shape = new egret.Shape(), grap = shape.graphics grap.beginFill(0x1E254B, 1) grap.drawRect(0, 0, this.containerArea.width, this.containerArea.height) grap.endFill() this.containerArea.addChild(shape) // 添加网格并绘制网格线 this.groupGridArea = new eui.Group() const margin = 8 this.groupGridArea.name = 'gridArea', this.groupGridArea.width = this.containerArea.width - margin * 2, this.groupGridArea.height = this.containerArea.height - margin * 2, this.groupGridArea.horizontalCenter = 0, this.groupGridArea.verticalCenter = 0, this.groupGridArea.touchEnabled = false, this.groupGridArea.touchChildren = false // 计算行高列宽 this.cellCount = RowCount * ColCount, this.rowHeight = this.groupGridArea.height / RowCount, this.colWidth = this.groupGridArea.width / ColCount shape = new egret.Shape(), grap = shape.graphics shape.name = 'layoutShape' // 所有颜色方块起点终点下标数组 const startEndIndexs = this.sceneData.Blocks.map(x => x.Index) // 筛选出除颜色方块单元格下标之外的空白单元格下标 this.blankCellIndexs = Array.from(new Array(16), (_, i) => i).filter(x => !startEndIndexs.includes(x)) // 调试,显示网格区域 // grap.beginFill(0xECECEC, 1) // grap.drawRect(0, 0, gridArea.width, gridArea.height) // 生成网格布局 const tileLayout = new eui.TileLayout() tileLayout.requestedRowCount = RowCount, tileLayout.requestedColumnCount = ColCount, tileLayout.horizontalGap = 0, tileLayout.verticalGap = 0, tileLayout.rowHeight = this.rowHeight, tileLayout.columnWidth = this.colWidth this.groupGridArea.layout = tileLayout // 绘制网格线 grap.lineStyle(3, 0x5F7B98) for (let i = 0; i < RowCount + 1; i++) { grap.moveTo(0, this.rowHeight * i) grap.lineTo(this.groupGridArea.width, this.rowHeight * i) } for (let i = 0; i < ColCount + 1; i++) { grap.moveTo(this.colWidth * i, 0) grap.lineTo(this.colWidth * i, this.groupGridArea.height) } grap.endFill() this.groupGridArea.addChild(shape) // 添加网格格子 let points = new Array<egret.Point>() let cellGroup: eui.Group, cellImage: eui.Image, // 方块 block: Block, // 方块字典项目(存储着方块图片资源名称与描述等数据),格式:{"Desc":"","Source":""} blockDicItem: any, // 每行的列下标,每换一行,列下标重新归零 eachRow_ColIndex = 0, // 当前 Y 轴坐标(方块上或下边线的 Y 轴坐标) currYAxis = 0 for (let i = 0; i < this.cellCount; i++) { cellGroup = new eui.Group() // 格式:方块标识,方块颜色,方块下标,容器标识 cellGroup.name = `,,${i},${this.groupId}`, cellGroup.touchEnabled = false, cellGroup.touchChildren = false // 计算当前方块的四个角坐标点 points = [] // 左上角 points.push(new egret.Point(this.colWidth * eachRow_ColIndex, currYAxis)) // 右上角 points.push(new egret.Point(this.colWidth * (eachRow_ColIndex + 1), currYAxis)) // 计算右下、左下两个角坐标,临时将当前 Y 轴坐标增加一行的高度 currYAxis += this.rowHeight // 右下角 points.push(new egret.Point(this.colWidth * (eachRow_ColIndex + 1), currYAxis)) // 左下角 points.push(new egret.Point(this.colWidth * eachRow_ColIndex, currYAxis)) // 获取当前方块中心点坐标 const certreX = points[0].x + this.colWidth / 2, certreY = points[3].y - this.rowHeight / 2 // 中心点 points.push(new egret.Point(certreX, certreY)) // 将坐标数组存储到方块下标对应的字典中 this.cellPointDic.Set(i.toString(), points) // 将当前 Y 轴坐标恢复到当前行的高度,减去一行的高度,用于计算下一个单元格的上边线两个角的坐标 currYAxis -= this.rowHeight // 列下标自增 eachRow_ColIndex++ // 如果当前方块属于下一行的第一个方块,则将 eachRow_ColIndex 重置为0,当前 Y 轴增加一行的高度 if ((i + 1) % RowCount === 0) { eachRow_ColIndex = 0 currYAxis += this.rowHeight } block = Blocks.find(x => x.Index === i) if (block) { blockDicItem = this.blockDic.Get(block.Color) if (blockDicItem) { cellImage = new eui.Image(blockDicItem.Source) const attData = { Id: this.blockId, Color: block.Color, Index: block.Index } this.blockId++ // 格式:方块标识,方块颜色,方块下标,容器标识 cellGroup.name = `${attData.Id},${attData.Color},${attData.Index},${this.groupId}` cellImage.name = JSON.stringify(attData) cellImage.width = this.colWidth * 0.9, cellImage.height = this.rowHeight * 0.9, cellImage.horizontalCenter = 0, cellImage.verticalCenter = 0 cellGroup.addChild(cellImage) } } this.groupGridArea.addChild(cellGroup) this.groupId++ } }
嘴角上扬,记得微笑

浙公网安备 33010602011771号