ArkTS 2048 手感调优:棋盘渲染与滑动交互

实例:2048 小游戏(Game 2048)|技术:正方形画布、方块渲染、触摸滑动判定、得分与状态提示

一、页面架构总览

复制代码
Column
├── 标题栏              // 标题 + 得分 + 新游戏按钮
├── 状态提示            // 游戏进行/胜利/失败文案
├── 棋盘画布            // Canvas:正方形,4×4 方块
└── 规则说明            // 滑动合并规则

页面结构与 34 贪吃蛇类似(标题 + 画布 + 提示),核心在正方形棋盘渲染滑动交互

二、正方形棋盘画布

typescript 复制代码
Canvas(this.ctx)
  .width('94%')
  .aspectRatio(1)          // 正方形棋盘
  .borderRadius(12)
  .border({ width: 1, color: '#E2E8F0' })
  .onReady(() => {
    this.canvasW = this.ctx.width;
    this.canvasH = this.ctx.height;
    this.draw();
  })

aspectRatio(1):宽高比 1:1------棋盘天然正方形,任何屏幕都不变形(34 贪吃蛇用过 aspectRatio,此处强调"正方形"语义)。

三、棋盘渲染 ★核心绘制

typescript 复制代码
private draw(): void {
  if (this.canvasW === 0) {
    return;
  }
  this.ctx.clearRect(0, 0, this.canvasW, this.canvasH);
  // 棋盘背景(米色)
  this.ctx.fillStyle = '#BBADA0';
  this.ctx.fillRect(0, 0, this.canvasW, this.canvasH);
  const gap = 8;
  const cellSize = (this.canvasW - gap * 5) / SIZE;   // 4 格 + 5 条间距
  for (let r = 0; r < SIZE; r++) {
    for (let c = 0; c < SIZE; c++) {
      const x = gap + c * (cellSize + gap);
      const y = gap + r * (cellSize + gap);
      const v = this.board[r][c];
      // 方块底(按数值着色)
      this.ctx.fillStyle = v === 0 ? '#CDC1B4' : (TILE_COLORS[v] ?? '#3C3A32');
      this.ctx.fillRect(x, y, cellSize, cellSize);
      // 数字(字号随位数变小)
      if (v !== 0) {
        this.ctx.font = v >= 100 ? 'bold 26px sans-serif' : 'bold 32px sans-serif';
        this.ctx.fillStyle = v <= 4 ? '#776E65' : '#F9F6F2';   // 浅底深字/深底浅字
        this.ctx.textAlign = 'center';
        this.ctx.textBaseline = 'middle';
        this.ctx.fillText(`${v}`, x + cellSize / 2, y + cellSize / 2);
        this.ctx.textAlign = 'start';        // 复位
        this.ctx.textBaseline = 'alphabetic'; // 复位
      }
    }
  }
}

棋盘几何cellSize = (canvasW - gap*5) / SIZE------画布宽减去 5 条间距(4 格之间有 3 条 + 两侧 2 条 = 5 条 gap),除以 4 得每格尺寸。方块位置gap + idx × (cellSize + gap)

方块着色的三级语义

背景 文字色
0(空) 灰 #CDC1B4 ---
2/4 浅色(#EEE4DA/#EDE0C8) 深字 #776E65
8+ 深色(TILE_COLORS) 白字 #F9F6F2

v <= 4 ? 深字 : 白字------浅底深字、深底浅字 的对比度规则。TILE_COLORS[v] ?? '#3C3A32' 兜底超 2048 的深色。

字号分级v >= 100 ? 26px : 32px------三位数以上缩小字号防溢出(128/256/512)。长数字的布局适配

文本居中 + 复位textAlign='center' + textBaseline='middle' 让数字精确居中,画完复位(全系列一致的状态泄漏防护)。

四、触摸滑动判定

typescript 复制代码
private onSwipe(e: TouchEvent): void {
  const t = e.touches[0];
  if (!t) {
    return;
  }
  if (e.type === TouchType.Down) {
    this.swipeStart = { x: t.x, y: t.y };
  } else if (e.type === TouchType.Up && this.swipeStart !== null) {
    const dx = t.x - this.swipeStart.x;
    const dy = t.y - this.swipeStart.y;
    if (Math.abs(dx) > 30 || Math.abs(dy) > 30) {   // 阈值防误触
      if (Math.abs(dx) > Math.abs(dy)) {
        this.move(dx > 0 ? 1 : 0);   // 右/左
      } else {
        this.move(dy > 0 ? 3 : 2);   // 下/上
      }
    }
    this.swipeStart = null;
  }
}

滑动判定(Up 时结算) :与 34 贪吃蛇的"Move 实时"不同,2048 用 Down 记录起点 + Up 结算方向 ------滑动完成后执行一次 move(棋盘游戏是"一次滑动一步",不是连续转向)。游戏类型决定交互粒度:贪吃蛇连续控制用 Move,2048 离散移动用 Up。

阈值 30px :位移超 30 才算有效滑动(防误触)。主导轴判定|dx| > |dy| 取水平方向------与 34 同款算法。

五、得分与状态提示

typescript 复制代码
@State score: number = 0;
@State statusText: string = '滑动棋盘开始游戏';

Text(`得分 ${this.score}`)...   // 标题栏橙色
Text(this.statusText)
  .fontSize(14)
  .fontColor(this.statusText.startsWith('💀') || this.statusText.startsWith('🎉') ? '#EF4444' : '#999999')

状态文案三态

状态 文案 颜色
进行中 (初始提示/无)
胜利 🎉 2048!你赢了! 红(警示强调)
失败 💀 游戏结束,得分 X

startsWith('💀') || startsWith('🎉') 判断终局态------emoji 前缀作为状态标志的轻量技巧。

六、新游戏

typescript 复制代码
Button('新游戏').fontSize(13).height(34).backgroundColor('#8B5CF6')
  .onClick(() => this.newGame())

newGame 完整重置 :棋盘清零 + 分数清零 + 状态复位 + 生成两个初始方块 + 绘制------一个方法完成全部初始化(34 的 startGame 同款)。

七、交互流程图

复制代码
启动 ──► aboutToAppear ──► newGame(棋盘 + 2 方块 + 绘制)
         │
    Canvas onReady ──► draw
         │
    触摸滑动 ──► onSwipe
         │        ├─ Down 记录起点
         │        ├─ Up 结算方向(阈值 + 主导轴)
         │        └─ move(方向)
         │             ├─ slideLine × 4 行
         │             ├─ 有效性判定
         │             ├─ 有效 → 更新棋盘 + 计分 + spawnTile + checkEnd
         │             └─ draw
         │
    点"新游戏" ──► newGame

八、UI 技术要点对照表

技术点 实现方式 生产价值
正方形画布 aspectRatio(1) 棋盘不变形
棋盘几何 cellSize = (W - 5gap)/4 自适应尺寸
三色层级 空/浅/深 + 字色对比 视觉分级
字号分级 >=100 缩小 长数字适配
Up 结算滑动 Down 起点 + Up 方向 离散移动
阈值防误触 30px 交互稳健
emoji 状态标志 startsWith 判断 轻量状态机
完整重置 newGame 收口 初始化一致

九、本篇小结

本篇完成了 2048 的界面与交互:aspectRatio 正方形棋盘三色层级方块渲染(背景色 + 字色对比 + 字号分级)Up 结算的滑动判定得分与终局提示 。UI 层的核心是"棋盘几何自适应"------cellSize 由画布宽推导,任何屏幕正方形棋盘都铺满。

下一篇《完整代码与运行效果》将给出 Game2048Page 全量源码解读、操作剧本演示,以及"网格棋盘游戏"通用模板抽象------与 34 贪吃蛇的模板合并,覆盖全部棋盘类游戏。


十、UI 深度扩展

1. 滑动动画

move 后不立即绘制新棋盘,而是记录每格"从哪来 → 到哪去",帧循环插值移动 + 合并缩放。插值动画是 2048 质感的来源,实现 = 动画帧 + 位移数组。

2. 最高分

preferences 存最高分(34 已演示),标题栏显示"得分 X · 最高 Y"。跨局激励

3. 撤销

历史棋盘栈(每次 move 前 push 深拷贝),撤销按钮 pop 恢复。悔棋是策略游戏标配。

4. 主题切换

深色主题 / 经典米色切换:TILE_COLORS 换一套映射。主题 = 颜色配置

5. FAQ

Q1:为什么 2048 用 Up 结算滑动而贪吃蛇用 Move?

A:贪吃蛇是"持续控制"(手指方向即蛇方向,实时响应);2048 是"离散操作"(一次滑动 = 一步)。交互粒度由游戏规则决定------连续用 Move,离散用 Up 结算。

Q2:字号分级为什么以 100 为界?

A:三位数(128/256/512)在 32px 下会溢出格子。100 是"是否三位数"的阈值。四位数(2048)用 26px 仍偏大------可再加 >=1000 ? 22px 档。字号随位数阶梯降

Q3:方块颜色表没有 4096 会怎样?

A:?? '#3C3A32' 兜底深色------超过 2048 的方块显示深灰底白字,不报错。映射表 + 兜底是配置型代码的防御。

Q4:滑动阈值 30 比贪吃蛇的 20 大,为什么?

A:2048 的滑动是"整步操作",需要更明确的意图(误触代价高------一次误滑可能毁局);贪吃蛇滑动是"方向微调",阈值小响应快。阈值随操作重要度调整

Q5:棋盘居中吗?

A:画布 94% 宽 + aspectRatio(1),在 Column 中默认水平居中(Column 子元素居中)。布局默认行为即可。


十一、下篇预告

最后一篇《完整代码与运行效果》将:给出 Game2048Page.ets 完整源码逐段解读;演示滑动合并、生成新方块、计分、胜负判定的完整操作链;抽象"网格棋盘游戏"通用模板,并与 34 贪吃蛇模板合并成"棋盘游戏全家桶"。

相关推荐
晴天163 小时前
HarmonyOS 和 React 对比-Day22
前端·华为·harmonyos
砚凝霜3 小时前
软考网络工程师|案例分析:华为全套综合实验核心知识点 & 考点总结
网络·华为
lilian2335 小时前
Harmony os 技术实战|拼豆制图20:用 finally 关闭 ImageSource、PixelMap 与文件句柄
华为·harmonyos
独守一片天17 小时前
HarmonyOS 鸿蒙碰一碰与跨端协同体验怎么设计?
华为·harmonyos
yuhulkjv33520 小时前
Gemini鸿蒙版导出word格式的终极解法:AI 导出鸭如何重构AI内容落地链路
人工智能·ai·word·harmonyos·ai导出鸭
whyutianict_vv1 天前
从 Web 前端到 HarmonyOS ArkTS:一次 AI 鸿蒙全栈智能体开发的迁移实录
前端·人工智能·harmonyos
m0_749690231 天前
【寻迹校园 HarmonyOS NEXT 实战 01】从校园痛点到可上架 MVP:失物招领应用产品设计
人工智能·深度学习·移动开发·harmonyos·arkts·arkui·产品设计
m0_749690231 天前
【寻迹校园 HarmonyOS NEXT 实战 03】NavPathStack 路由实战:18 个页面如何集中管理
华为·移动开发·harmonyos·arkui·navigation·navpathstack
m0_749690231 天前
【寻迹校园 HarmonyOS NEXT 实战 02】多模块工程拆解:entry、HAR 与 HSP 如何分工
华为·harmonyos·arkts·软件架构·har·hsp