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++
  }
}

 

posted @ 2021-06-09 11:06  jardeng  阅读(357)  评论(0)    收藏  举报