鸿蒙开发案例:HarmonyOS NEXT语法实现2048

news2024/11/23 15:40:57

【实现的功能】

• 游戏逻辑:实现了2048游戏的核心逻辑,包括初始化游戏盘面、添加随机方块、处理四个方向的滑动操作等。

• UI展示:构建了游戏的用户界面,显示得分、游戏盘面,并提供了重新开始按钮。

• 用户交互:支持触摸屏上的手势识别,通过滑动手势控制游戏盘面上方块的移动。

【待实现功能】

• 方块移动动画:暂未实现 原理应该是在UI的Text上设置.translate({ x:, y: })并添加.animation({duration: 200}),然后在逻辑里通过修改x或y来实现位移动画。研究了一下操作时方块的移动动画,但效果不尽如人意(T_T)。继续努力学习如何实现动画效果。

【完整代码】

// 使用装饰器标记Cell类,可能表示该类具有可观测性
@ObservedV2
class Cell {
  // 使用Trace装饰器标记value属性,可能表示该属性的变化会被追踪
  @Trace value: number;

  // 构造函数初始化单元格的值为0
  constructor() {
    this.value = 0;
  }
}

// 使用Entry和Component装饰器标记Game2048结构体,可能表示这是程序的入口点,并且该结构体定义了一个组件
@Entry
@Component
  // 定义Game2048结构体
struct Game2048 {
  // 使用State装饰器标记状态变量,可能表示这些变量是组件的状态
  @State board: Cell[][] = []; // 游戏盘面
  @State score: number = 0; // 分数
  @State cellSize: number = 200; // 单元格大小
  @State cellMargin: number = 5; // 单元格之间的边距
  @State screenStartX: number = 0; // 触摸开始时的屏幕X坐标
  @State screenStartY: number = 0; // 触摸开始时的屏幕Y坐标
  @State lastScreenX: number = 0; // 触摸结束时的屏幕X坐标
  @State lastScreenY: number = 0; // 触摸结束时的屏幕Y坐标

  // 定义颜色数组
  colors: string[] = [
    '#CCCCCC', // 0 - 灰色
    '#FFC107', // 2 - 黄色
    '#FF9800', // 4 - 橙色
    '#FF5722', // 8 - 深橙色
    '#F44336', // 16 - 红色
    '#9C27B0', // 32 - 紫色
    '#3F51B5', // 64 - 蓝紫色
    '#00BCD4', // 128 - 蓝色
    '#009688', // 256 - 深青色
    '#4CAF50', // 512 - 绿色
    '#8BC34A', // 1024 - 浅绿色
    '#CDDC39', // 2048 - 柠檬黄
    '#FFEB3B', // 4096 - 淡黄色
    '#795548', // 8192 - 棕色
    '#607D8B', // 16384 - 深灰色
    '#9E9E9E', // 32768 - 灰色
    '#000000' // 以上 - 黑色
  ];

  // 游戏即将出现时执行的方法
  aboutToAppear() {
    this.score = 0; // 重置分数
    this.initBoard(); // 重新初始化游戏板
    this.addRandomTiles(2); // 添加两个随机方块
  }

  // 初始化游戏盘面
  initBoard() {
    if (this.board.length == 0) {
      for (let i = 0; i < 4; i++) {
        let cellArr: Cell[] = [];
        for (let j = 0; j < 4; j++) {
          cellArr.push(new Cell()); // 创建新单元格
        }
        this.board.push(cellArr); // 添加到盘面
      }
    } else {
      for (let i = 0; i < this.board.length; i++) {
        for (let j = 0; j < this.board[i].length; j++) {
          this.board[i][j].value = 0; // 清空单元格
        }
      }
    }
  }

  // 在盘面上添加指定数量的随机方块
  addRandomTiles(count: number) {
    let emptyCells: object[] = [];
    for (let row = 0; row < 4; row++) {
      for (let col = 0; col < 4; col++) {
        if (this.board[row][col].value === 0) {
          emptyCells.push(Object({ row: row, col: col })); // 记录空单元格位置
        }
      }
    }

    for (let i = 0; i < count; i++) {
      if (emptyCells.length > 0) {
        let randomIndex = Math.floor(Math.random() * emptyCells.length);
        let obj = emptyCells[randomIndex];
        this.board[obj['row']][obj['col']].value = Math.random() < 0.9 ? 2 : 4; // 随机生成2或4
        emptyCells.splice(randomIndex, 1); // 移除已使用的空单元格位置
      }
    }
  }

  // 向左滑动
  slideLeft() {
    for (let row = 0; row < 4; row++) {
      let tempRow: number[] = []; // 临时存储行数据
      let merged: boolean[] = new Array(4).fill(false); // 标记是否已经合并过

      for (let col = 0; col < 4; col++) {
        if (this.board[row][col].value !== 0) {
          tempRow.push(this.board[row][col].value); // 移动非零值
        }
      }

      let mergePos = 0;
      while (mergePos < tempRow.length - 1) {
        if (tempRow[mergePos] === tempRow[mergePos + 1] && !merged[mergePos]) {
          tempRow[mergePos] *= 2; // 合并
          this.score += tempRow[mergePos]; // 更新分数
          merged[mergePos] = true; // 标记已合并
          tempRow.splice(mergePos + 1, 1); // 移除合并过的值
        } else {
          mergePos++;
        }
      }

      while (tempRow.length < 4) {
        tempRow.push(0); // 填充空位
      }
      for (let col = 0; col < 4; col++) {
        this.board[row][col].value = tempRow[col]; // 更新盘面
      }
    }
  }

  // 向右滑动
  slideRight() {
    for (let row = 0; row < 4; row++) {
      let tempRow: number[] = []; // 临时存储行数据
      let merged: boolean[] = new Array(4).fill(false); // 标记是否已经合并过

      for (let col = 3; col >= 0; col--) {
        if (this.board[row][col].value !== 0) {
          tempRow.unshift(this.board[row][col].value); // 移动非零值
        }
      }
      let mergePos = tempRow.length - 1;
      while (mergePos > 0) {
        if (tempRow[mergePos] === tempRow[mergePos - 1] && !merged[mergePos - 1]) {
          tempRow[mergePos] *= 2; // 合并
          this.score += tempRow[mergePos]; // 更新分数
          merged[mergePos - 1] = true; // 标记已合并
          tempRow.splice(mergePos - 1, 1); // 移除合并过的值
        } else {
          mergePos--;
        }
      }

      while (tempRow.length < 4) {
        tempRow.unshift(0); // 填充空位
      }
      for (let col = 0; col < 4; col++) {
        this.board[row][col].value = tempRow[col]; // 更新盘面
      }
    }
  }

  // 向上滑动
  slideUp() {
    for (let col = 0; col < 4; col++) {
      let tempCol: number[] = []; // 临时存储列数据
      let merged: boolean[] = new Array(4).fill(false); // 标记是否已经合并过

      for (let row = 0; row < 4; row++) {
        if (this.board[row][col].value !== 0) {
          tempCol.push(this.board[row][col].value); // 移动非零值
        }
      }

      let mergePos = 0;
      while (mergePos < tempCol.length - 1) {
        if (tempCol[mergePos] === tempCol[mergePos + 1] && !merged[mergePos]) {
          tempCol[mergePos] *= 2; // 合并
          this.score += tempCol[mergePos]; // 更新分数
          merged[mergePos] = true; // 标记已合并
          tempCol.splice(mergePos + 1, 1); // 移除合并过的值
        } else {
          mergePos++;
        }
      }

      while (tempCol.length < 4) {
        tempCol.push(0); // 填充空位
      }

      for (let newRow = 0; newRow < 4; newRow++) {
        this.board[newRow][col].value = tempCol[newRow]; // 更新盘面
      }
    }
  }

  // 向下滑动
  slideDown() {
    for (let col = 0; col < 4; col++) {
      let tempCol: number[] = []; // 临时存储列数据
      let merged: boolean[] = new Array(4).fill(false); // 标记是否已经合并过

      // 从下往上遍历列
      for (let row = 3; row >= 0; row--) {
        if (this.board[row][col].value !== 0) {
          tempCol.unshift(this.board[row][col].value); // 移动非零值
        }
      }
      let mergePos = tempCol.length - 1;
      while (mergePos > 0) {
        if (tempCol[mergePos] === tempCol[mergePos - 1] && !merged[mergePos - 1]) {
          tempCol[mergePos] *= 2; // 合并
          this.score += tempCol[mergePos]; // 更新分数
          merged[mergePos - 1] = true; // 标记已合并
          tempCol.splice(mergePos - 1, 1); // 移除合并过的值
        } else {
          mergePos--;
        }
      }

      // 如果数组长度小于4,用0填充
      while (tempCol.length < 4) {
        tempCol.unshift(0); // 填充空位
      }
      // 将处理后的数组元素放回到棋盘的对应列中
      for (let row = 0; row < 4; row++) {
        this.board[3 - row][col].value = tempCol[3 - row]; // 注意反转顺序
      }
    }
  }

  // 构建游戏界面
  build() {
    // 布局容器
    Column({ space: 10 }) {
      // 显示得分
      Text(`得分: ${this.score}`)
        .fontSize(24)
        .margin({ top: 20 })

      // 底层背景布局
      Flex({ wrap: FlexWrap.Wrap, direction: FlexDirection.Row }) {
        // 遍历每个单元格
        ForEach(this.board.flat(), (cell: Cell, index: number) => {
          // 显示单元格上的数字
          Text(`${cell.value || ''}`)
            .width(`${this.cellSize}px`)
            .height(`${this.cellSize}px`)
            .margin(`${this.cellMargin}px`)
            .fontSize(`${cell.value >= 100 ? this.cellSize / 3 : this.cellSize / 2}px`) // 根据数字大小调整字体大小
            .textAlign(TextAlign.Center)
            .backgroundColor(this.colors[cell.value == 0?0:Math.floor(Math.log2(cell.value))]) // 设置背景颜色
            .fontColor(cell.value === 0 ? '#000' : '#fff') // 设置字体颜色
            .borderRadius(5) // 圆角
        })
      }
      .width(`${(this.cellSize + this.cellMargin * 2) * 4}px`) // 设置容器宽度

      // 重新开始按钮
      Button('重新开始').onClick(() => {
        this.aboutToAppear(); // 重新开始游戏
      })
    }
    .width('100%')
    .height('100%')
    .onTouch((e) => {
      if (e.type === TouchType.Down && e.touches.length > 0) { // 触摸开始,记录初始位置
        this.screenStartX = e.touches[0].x;
        this.screenStartY = e.touches[0].y;
      } else if (e.type === TouchType.Up && e.changedTouches.length > 0) { // 当手指抬起时,更新最后的位置
        this.lastScreenX = e.changedTouches[0].x;
        this.lastScreenY = e.changedTouches[0].y;
      }
    })
    .gesture(
      SwipeGesture({ direction: SwipeDirection.All }) // 支持方向中 all可以是上下左右
        .onAction((_event: GestureEvent) => {
          const swipeX = this.lastScreenX - this.screenStartX;
          const swipeY = this.lastScreenY - this.screenStartY;
          // 清除开始位置记录,准备下一次滑动判断
          this.screenStartX = 0;
          this.screenStartY = 0;
          if (Math.abs(swipeX) > Math.abs(swipeY)) {
            if (swipeX > 0) {
              this.slideRight(); // 向右滑动
            } else {
              this.slideLeft(); // 向左滑动
            }
          } else {
            if (swipeY > 0) {
              this.slideDown(); // 向下滑动
            } else {
              this.slideUp(); // 向上滑动
            }
          }
          this.addRandomTiles(1); // 添加一个随机方块
        })
    )
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2212783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6.资源《 Arduino UNO R3 proteus使用MAX7219控制多个数码管工程文件(含驱动代码)》说明。

资源链接&#xff1a; Arduino UNO R3 proteus使用MAX7219控制多个数码管工程文件&#xff08;含驱动代码&#xff09; 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;proteus工程&#xff0c;内含设计图和工程代码。 3.内容展示 4.简述 工程功能可以看这个视频…

即插即用hilo注意力机制,捕获低频高频特征

题目&#xff1a;Fast Vision Transformers with HiLo Attention 论文地址: https://arxiv.org/abs/2205.13213 创新点 HiLo自注意力机制&#xff1a;作者提出了一种新的自注意力机制&#xff0c;称为HiLo注意力&#xff0c;旨在同时捕捉图像中的高频和低频信息。该方法通过…

数据结构 ——— 顺序表oj题:有效的括号

目录 题目要求 代码实现 题目要求 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个…

深入解析网络流量回溯分析:如何有效进行网络故障排除

目录 什么是网络流量回溯分析&#xff1f; 网络流量回溯分析的核心优势 网络流量回溯分析如何助力网络故障排除&#xff1f; 1. 快速定位故障节点 真实案例&#xff1a;解决网络延迟问题 2. 精准分析流量异常 真实案例&#xff1a;识别恶意流量 3. 优化网络性能 为什么…

【Linux指令策】❤️基本必备指令❤️——打开Linux大门,带你快速上手Linux(超详细,收藏这一篇就足够啦~!!!)

【Linux入门】——基本指令 目录 一&#xff1a;认识操作系统 1.1&#xff1a;操作系统是什么&#xff1f; 1.2&#xff1a;操作系统 ——管理 1.3&#xff1a;操作系统——贯穿 二&#xff1a;Linux基本指令 2.1-指令学习&#xff08;上篇&#xff09; 2.1.1 > ls …

Chromium 前端form表单提交过程分析c++

一、本文以一个简单的 HTML 表单&#xff0c;包含两个文本输入框和一个提交按钮&#xff1a; <form action"demo_form.php">First name: <input type"text" name"fname"><br>Last name: <input type"text" name…

Unreal5从入门到精通之 如何使用事件分发器EventDispather

文章目录 前言1.创建事件分发器设置属性2.创建Bind、Unbind及Unbind All节点在蓝图类中创建在关卡蓝图中创建3.创建事件分发器事件节点4.调用事件分发器在蓝图类中进行调用在关卡蓝图中进行调用精彩推荐前言 事件分发器是 Unreal Engine(UE)中一个重要的概念,它负责在游戏运…

【C++】右值引用和移动语义(带你理解C++为何如此高效)

1.右值引用和移动语义 左值和右值的重点区分是能否取地址。 能取地址的是左值&#xff08;可以是值&#xff0c;也可以是表达式&#xff09;&#xff0c;不能取地址的是右值。 1.1 什么是左值 1.2 什么是右值 1.2.1 常见的右值 常见右值&#xff1a;常数&#xff08;10&…

【C/C++】速通某站上的经典“笔试”编程题

【C/C】速通某站上的经典“笔试”编程题 一. 题目描述&#xff1a;解题思路&#xff1a;代码实现&#xff1a; 二. 题目描述&#xff1a;解题思路&#xff1a;代码实现&#xff1a; 三. 题目描述&#xff1a;解题思路&#xff1a;代码实现&#xff1a; 一. 题目描述&#xff1a…

DS线性表之栈的讲解和实现(4)

文章目录 前言一、栈的概念及结构二、关于实现栈的分析关于栈顶指针top关于结构体栈的初始化入栈出栈获取栈顶元素获取栈元素个数判断栈是否为空栈的销毁 总结 前言 栈就是一个比较实用的数据结构了&#xff0c;且大致逻辑就是套用之前的两种线性表 具体选择哪种呢&#xff1f;…

综合布线研究实训室建设方案

1、 引言 随着信息技术的飞速发展&#xff0c;综合布线系统作为信息传输的基础设施&#xff0c;在各类建筑及信息化项目中发挥着越来越重要的作用。为了满足职业院校及企业对综合布线技术人才培养和研究的需求&#xff0c;本方案旨在建设一个集教学、实训、研究于一体的综合布…

ARM base instruction -- smull

有符号乘法运算 Signed Multiply Long multiplies two 32-bit register values, and writes the result to the 64-bit destination register. 将两个32位寄存器值相乘&#xff0c;并将结果写入64位目标寄存器。 64-bit variant SMULL <Xd>, <Wn>, <Wm>…

Linux破解root用户密码

在Linux启动菜单界面按【e】进入编辑启动菜单项 在LANGzh_CN.UTF-8&#xff08;或LANGen_US.UTF-8&#xff09;后面空出一格输入 rd.break consoletty0,再按【ctrlx】键启动Linux系统 以可读写的方式重新挂载文件系统 mount -o remount,rw /sysroot 改变根目录为/sysro…

Attention Is All You Need论文翻译

论文名称 注意力即是全部 论文地址 https://user.phil.hhu.de/~cwurm/wp-content/uploads/2020/01/7181-attention-is-all-you-need.pdf 摘要 主流的序列转导模型基于复杂的递归或卷积神经网络&#xff0c;这些网络包含编码器和解码器。性能最好的模型通过注意力机制将编码器和…

快速学习一个算法,Transformer模型架构

今天给大家分享一个超强的算法模型&#xff0c;Transformer Transformer 模型是目前自然语言处理&#xff08;NLP&#xff09;以及计算机视觉等领域中应用非常广泛的深度学习模型架构。 它由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出&#xff0c;并…

【智能大数据分析 | 实验三】Storm实验:实时WordCountTopology

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…

并查集的实现(朴素版)

这是C算法基础-数据结构专栏的第二十九篇文章&#xff0c;专栏详情请见此处。 由于作者即将参加CSP&#xff0c;所以到比赛结束前将不再发表文章&#xff01; 引入 并查集是一种可以快速合并查找集合的一种数据结构&#xff0c;这次我们将通过三道题来详细讲解并查集&#xff…

迈普pnsr2900x DOWNLOAD_FILE 任意文件读取漏洞

0x01 产品描述&#xff1a; ‌ 迈普NSR2900X系列是一款专为军队、政府、金融、中小型企业分支机构和中小型企业总部设计的信创接入路由器。‌ 该路由器采用国产核心元器件&#xff0c;基于国产操作系统运行迈普自主研发的网络操作系统及应用软件。它全面支持IPv4、IPv6、OS…

insert into values 语句优化

insert into values插入单行数据 SQL语句&#xff0c;insert into values插入单行数据&#xff0c;执行10万次&#xff0c;执行时间1279秒&#xff0c;优化总体执行耗时。 SQL文本&#xff0c;单行insert values&#xff0c;没有select部分。需要进一步分析执行过程消耗。 ins…

软考《信息系统运行管理员》- 5.1 信息系统数据资源维护体系

5.1 信息系统数据资源维护体系 文章目录 5.1 信息系统数据资源维护体系数据资源维护的管理对象数据资源维护的管理类型运行监控故障响应数据备份归档检索数据优化 数据资源维护的管理内容维护方案例行管理应急响应数据资源的开发与利用 数据是信息系统管理的对象与结果&#xf…