鸿蒙版(ArkTs) 贪吃蛇,包含无敌模式 最高分 暂停和继续功能

news2025/4/18 7:56:08

鸿蒙版(ArkTs) 贪吃蛇,包含无敌模式 最高分 暂停和继续功能;
效果图如下:请添加图片描述
代码如下:

// 所有import语句必须放在文件开头
import router from '@ohos.router';
import promptAction from '@ohos.promptAction';
// Add this import at the top with other imports
// Remove the problematic import
// import { Gradient, GradientDirection } from '@ohos.arkui.graphics';

// 在文件开头添加Preferences导入
import preferences from '@ohos.data.preferences';

// 移除@Entry装饰器
@Entry
@Component
struct Tsc {
  @State snake: Array<[number, number]> = [[5, 5], [5, 6], [5, 7]];
  @State food: [number, number] = [10, 10];
  @State private _moveDirection: number = 3;
  @State score: number = 0;
  @State highScore: number = 0;
  private prefs?: preferences.Preferences; // Use optional type instead of undefined

  @State isInvincible: boolean = false;
  @State foodColor: Color = Color.Red;
  @State snakeHeadColor: Color = Color.Green;
  private gridSize: number = 20;
  private timer: number = 0;
  @State isPlaying: boolean = false;

  // 添加generateFood方法
  generateFood() {
    const gridCells = 12;
    let newFood: [number, number] = [0, 0];
    let validPositionFound = false;
    
    const allPositions: Array<[number, number]> = [];
    for (let x = 0; x < gridCells; x++) {
      for (let y = 0; y < gridCells; y++) {
        allPositions.push([x, y]);
      }
    }
    
    allPositions.sort(() => Math.random() - 0.5);
    
    for (const pos of allPositions) {
      const isOverlap = this.snake.some(segment => 
        segment[0] === pos[0] && segment[1] === pos[1]
      );
      
      if (!isOverlap) {
        newFood = pos;
        validPositionFound = true;
        break;
      }
    }
    
    this.food = newFood;
    this.foodColor = Color.Red; // 设置默认食物颜色
  }

  // 重置游戏状态
  resetGame() {
    this.snake = [[5, 5], [5, 6], [5, 7]];
    this._moveDirection = 3;
    this.score = 0;
    this.generateFood();
  }

  startGame() {
    // 先清除之前的定时器
    if (this.timer) {
      clearInterval(this.timer);
    }
    
    this.resetGame();
    this.isPlaying = true;
    this.timer = setInterval(() => {
      this.moveSnake();
    }, 200);
  }

  // 添加生命周期方法
  aboutToAppear() {
    this.loadHighScore();
  }

  // 加载历史最高分
  async loadHighScore() {
    try {
      this.prefs = await preferences.getPreferences(getContext(this), 'snakeGamePrefs');
      const score = await this.prefs.get('highScore', 0);
      this.highScore = Number(score);
    } catch (err) {
      console.error('Failed to load high score:', err);
    }
  }

  // 保存历史最高分
  async saveHighScore(score: number) {
    try {
      if (this.prefs) { // Add null check
        await this.prefs.put('highScore', score);
        await this.prefs.flush();
      }
    } catch (err) {
      console.error('Failed to save high score:', err);
    }
  }

  endGame() {
    clearInterval(this.timer);
    this.isPlaying = false;
    // 更新历史最高分
    if (this.score > this.highScore) {
      this.highScore = this.score;
      this.saveHighScore(this.highScore);
    }
    promptAction.showToast({
      message: '游戏结束!',
      duration: 2000
    });
  }

  stopGame() {
    clearInterval(this.timer);
    this.isPlaying = false;
    if (this.score > this.highScore) {
      this.highScore = this.score;
      this.saveHighScore(this.highScore);
    }
  }

  moveSnake() {
    if (!this.isPlaying) return;

    let head: [number, number] = [this.snake[0][0], this.snake[0][1]];
    
    switch (this._moveDirection) {
      case 0: head[1] -= 1; break;
      case 1: head[1] += 1; break;
      case 2: head[0] -= 1; break;
      case 3: head[0] += 1; break;
    }

    // 修正边界检测逻辑
    const gridCells = 12; // 与显示区域保持一致
    if (head[0] < 0 || head[0] >= gridCells || 
        head[1] < 0 || head[1] >= gridCells) {
      if (!this.isInvincible) {
        this.endGame();
        return;
      }
      head[0] = (head[0] + gridCells) % gridCells;
      head[1] = (head[1] + gridCells) % gridCells;
    }

    if (head[0] === this.food[0] && head[1] === this.food[1]) {
      this.score += 10;
      this.generateFood();
      // 吃到食物时,只添加新头部,不删除尾部
      this.snake = [head, ...this.snake];
    } else {
      // 没吃到食物时,移动蛇身
      this.snake.pop();
      this.snake = [head, ...this.snake];
    }
  }

  // 添加暂停游戏方法
  @State isPaused: boolean = false; // 添加暂停状态
  
  // 修改暂停游戏方法
  pauseGame() {
    clearInterval(this.timer);
    this.isPlaying = false;
    this.isPaused = true;
  }
  
  // 修改恢复游戏方法
  resumeGame() {
    this.isPlaying = true;
    this.isPaused = false;
    this.timer = setInterval(() => {
      this.moveSnake();
    }, 200);
  }

  build() {
    Column() {
      Button('返回首页')
        .width(100)
        .height(40)
        .fontSize(16)
        .alignSelf(ItemAlign.Start)
        .margin(10)
        .onClick(() => {
          router.pushUrl({
            url: 'pages/Index'
          })
        })

      // 添加历史最高分显示
      Row() {
        Text(`当前得分: ${this.score}`)
          .fontSize(20)
        Text(`最高分: ${this.highScore}`)
          .fontSize(20)
          .margin({ left: 20 })
      }
      .margin({ bottom: 10 })

      // 修改按钮布局
      Row() {
        if (!this.isPlaying && !this.isPaused) {
          Button('开始游戏')
            .width(100)
            .height(35)
            .fontSize(14)
            .margin(5)
            .onClick(() => {
              this.startGame();
            })
        } else if (this.isPlaying) {
          Button('暂停')
            .width(100)
            .height(35)
            .fontSize(14)
            .margin(5)
            .onClick(() => {
              this.pauseGame();
            })
        } else if (this.isPaused) {
          Button('继续')
            .width(100)
            .height(35)
            .fontSize(14)
            .margin(5)
            .onClick(() => {
              this.resumeGame();
            })
        }
        Button('重新开始')
          .width(100)
          .height(35)
          .fontSize(14)
          .margin(5)
          .onClick(() => {
            this.startGame();
          })
        Button('结束游戏')
          .width(100)
          .height(35)
          .fontSize(14)
          .margin(5)
          .onClick(() => {
            this.stopGame();
          })
      }
      .margin({ top: 10 })

      Stack() {
        Circle({ width: this.gridSize, height: this.gridSize })
          .fill(this.foodColor)
          // 使用固定颜色描边
          .stroke(Color.Gray)
          .strokeWidth(2)
          // 添加阴影效果模拟渐变
          .shadow({
            radius: 3,
            color: Color.White,
            offsetX: 1,
            offsetY: 1
          })
          .position({
            x: this.food[0] * this.gridSize,
            y: this.food[1] * this.gridSize
          })
        ForEach(this.snake, (segment: [number, number], index: number) => {
          if (index === 0) {
            Rect({ width: this.gridSize, height: this.gridSize })
              .fill(this.snakeHeadColor)
              .radius(5)
              .position({
                x: segment[0] * this.gridSize,
                y: segment[1] * this.gridSize
              })
          } else {
            // 每节蛇身使用食物颜色
            Circle({ width: this.gridSize, height: this.gridSize })
              .fill(this.foodColor)
              .position({
                x: segment[0] * this.gridSize,
                y: segment[1] * this.gridSize
              })
          }
        })
      }
      .width(this.gridSize * 12)
      .height(this.gridSize * 12)
      .border({ width: 1, color: Color.Black })
      .clip(true) // 添加裁剪确保内容不会超出边框
      .margin({ bottom: 10 })

      Column() {
        Button('上')
          .width(80)
          .height(50)
          .fontSize(18)
          .margin(5)
          .onClick(() => { this._moveDirection = 0; })

        Row() {
          Button('左')
            .width(80)
            .height(50)
            .fontSize(18)
            .margin(5)
            .onClick(() => { this._moveDirection = 2; })
          Button('右')
            .width(80)
            .height(50)
            .fontSize(18)
            .margin(5)
            .onClick(() => { this._moveDirection = 3; })
        }
        
        Button('下')
          .width(80)
          .height(50)
          .fontSize(18)
          .margin(5)
          .onClick(() => { this._moveDirection = 1; })
      }
      .margin({ top: 10 })

      Row() {
        Text('无敌模式:')
          .fontSize(18)
          .fontColor(this.isInvincible ? Color.Red : Color.Black)
          .margin({ right: 10 })
        Toggle({ type: ToggleType.Switch, isOn: this.isInvincible })
          .width(40)
          .height(24)
          .onChange((isOn: boolean) => {
            this.isInvincible = isOn;
          })
        Text(this.isInvincible ? '开启' : '关闭')
          .fontSize(18)
          .fontColor(this.isInvincible ? Color.Red : Color.Black)
          .margin({ left: 10 })
      }
      .margin({ top: 20 })
      .padding(10)
      .borderRadius(10)
      .backgroundColor('#f0f0f0')
      .margin({ top: 10 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#E0F7FA')
    .onKeyEvent((event: KeyEvent) => {
      if (event.type === KeyType.Down) {
        switch (event.keyCode) {
          case 19: if (this._moveDirection !== 1) this._moveDirection = 0; break;
          case 20: if (this._moveDirection !== 0) this._moveDirection = 1; break;
          case 21: if (this._moveDirection !== 3) this._moveDirection = 2; break;
          case 22: if (this._moveDirection !== 2) this._moveDirection = 3; break;
        }
      }
    })
  }
}

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

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

相关文章

解决Win11耳机没有声音的问题

方法一&#xff1a;更新驱动程序&#xff08;有效&#xff09; 进入 “设置”&#xff08;快捷键&#xff1a;WinX&#xff09;&#xff0c;点击 “Windows 更新” → “高级选项” 点击 “可选更新” &#xff0c;然后点击 “驱动程序更新” 【注】&#xff1a;更新后可能会出…

【spring02】Spring 管理 Bean-IOC,基于 XML 配置 bean

文章目录 &#x1f30d;一. bean 创建顺序&#x1f30d;二. bean 对象的单例和多例❄️1. 机制❄️2. 使用细节 &#x1f30d;三. bean 的生命周期&#x1f30d;四. 配置 bean 的后置处理器 【这个比较难】&#x1f30d;五. 通过属性文件给 bean 注入值&#x1f30d;六. 基于 X…

内网渗透(杂项集合) --- 中的多协议与漏洞利用技术(杂项知识点 重点) 持续更新

目录 1. NetBIOS 名称的网络协议在局域网中内网渗透中起到什么作用 2. 使用 UDP 端口耗尽技术强制所有 DNS 查找失败&#xff0c;这个技术如何应用在局域网内网渗透测试中 3. 在本地创建一个 HTTP 服务来伪造 WPAD 服务器 什么是 WPAD 服务器&#xff1f;这个服务器是干嘛的…

el-tabs添加按钮增加点击禁止样式

前置文章 一、vue使用element-ui自定义样式思路分享【实操】 二、vue3&ts&el-tabs多个tab表单校验 现状确认 点击添加按钮&#xff0c;没有点击样式&#xff0c;用户感知不明显没有限制最大的tab添加数量&#xff0c;可以无限添加 调整目标&代码编写 调整目标…

LINUX 5 vim cat zip unzip

dd u撤销 ctrlr取消撤销 q!刚才的操作不做保存 刚才是编辑模式 现在是可视化模式 多行注释

PDFBox渲染生成pdf文档

使用PDFBox可以渲染生成pdf文档&#xff0c;并且自定义程度高&#xff0c;只是比较麻烦&#xff0c;pdf的内容位置都需要手动设置x&#xff08;横向&#xff09;和y&#xff08;纵向&#xff09;绝对位置&#xff0c;但是每个企业的单据都是不一样的&#xff0c;一般来说都会设…

Batch Normalization:深度学习训练的加速引擎

引言 在深度学习的发展历程中&#xff0c;训练深度神经网络一直是一项极具挑战性的任务。随着网络层数的增加&#xff0c;梯度消失、梯度爆炸以及训练过程中的内部协变量偏移&#xff08;Internal Covariate Shift&#xff09;问题愈发严重&#xff0c;极大地影响了模型的收敛…

低空经济基础设施建设方向与展望

随着科技的不断进步&#xff0c;低空经济正逐渐成为推动国家经济发展的新引擎。低空经济&#xff0c;指的是在低空范围内进行的各种经济活动&#xff0c;包括但不限于无人机物流、空中交通管理、低空旅游、农业监测等。本文将探讨低空经济基础设施建设的方向与未来展望。 1. 低…

如何保证RabbitMQ消息的可靠传输?

在这个图中&#xff0c;消息可能丢失的场景是1&#xff0c;2&#xff0c;3 1.在生产者将消息发送给RabbitMQ的时候&#xff0c;消息到底有没有正确的到达服务器呢&#xff0c;RabbitMQ提供了两种解决方案&#xff1a; a. 通过事务机制实现&#xff08;比较消耗性能&#xff0…

Sentinel核心源码分析(上)

文章目录 前言一、客户端与Spring Boot整合二、SphU.entry2.1、构建责任链2.2、调用责任链2.2.1、NodeSelectorSlot2.2.2、ClusterBuilderSlot2.2.3、LogSlot2.2.4、StatisticSlot2.2.5、AuthoritySlot2.2.6、SystemSlot2.2.7、FlowSlot2.2.7.1、selectNodeByRequesterAndStrat…

Systemd安全加密备份系统与智能通知

实训背景 你是一家金融科技公司的系统架构师&#xff0c;需为敏感数据设计一套安全备份系统&#xff0c;满足以下需求&#xff1a; 加密存储&#xff1a;自动解密插入的LUKS加密USB设备&#xff0c;挂载到安全目录。备份验证&#xff1a;备份完成后校验文件完整性&#xff0c…

6.0 使用Qt+ OpenCV+Python加载图片

本例作为python图像处理的入门课程1,使用Qt+ OpenCV+Python加载图片。 主要有如下几个地方需要注意: 1. OpenCV 默认使用 BGR 格式,而 Qt 使用 RGB。显示前需要转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB),一般使用某个QLabel控件进行显示。 pic = cv2.cvtColor(pic, cv2.C…

【Mac 从 0 到 1 保姆级配置教程 11】- Mac 基础配置 Finder、触控板、常用快捷键等

文章目录 前言配置 Finder1. 把我们的家目录请出来2. 显示文件扩展名3. 展示隐藏文件4. 显示路径栏和状态栏5. 固定文件夹到工具栏 基础快捷键1. Finder 导航快捷键2. 文件操作快捷键3. 视图和显示快捷键4. 搜索和选择快捷键5. 实用技巧6. 关于文件创建 配置触控板1. 右键设置2…

C++Primer - 动态内存管理

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

DeepSeek本地部署(Ollama)

1. Ollama 安装 Ollama 官网地址&#xff1a; https://ollama.com/安装包网盘地址: https://pan.baidu.com 2. Deepseek 部署 根据自己电脑配置和应用需求选择不同模型&#xff0c;配置不足会导致运行时候卡顿。 版本安装指令模型大小硬盘&#xff08;存储&#xff09;显卡…

第二期:深入理解 Spring Web MVC [特殊字符](核心注解 + 进阶开发)

前言&#xff1a; 欢迎来到 Spring Web MVC 深入学习 的第二期&#xff01;在第一期中&#xff0c;我们介绍了 Spring Web MVC 的基础知识&#xff0c;学习了如何 搭建开发环境、配置 Spring MVC、编写第一个应用&#xff0c;并初步了解了 控制器、视图解析、请求处理流程 等核…

论伺服电机在轨道式巡检机器人中的优势及应用实践​

一、引言​ 1.1 研究背景与意义​ 在现代工业生产、电力系统、轨道交通等诸多领域&#xff0c;保障设施设备的安全稳定运行至关重要。轨道式巡检机器人作为一种高效、智能的巡检工具&#xff0c;正逐渐在这些领域崭露头角。它能够沿着预设轨道&#xff0c;对目标区域进行全方位…

(51单片机)独立按键控制流水灯LED流向(独立按键教程)(LED使用教程)

源代码 如上图将7个文放在Keli5 中即可&#xff0c;然后烧录在单片机中就行了 烧录软件用的是STC-ISP&#xff0c;不知道怎么安装的可以去看江科大的视频&#xff1a; 【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】https://www.bilibili.com/video/BV1Mb411e7re?…

react-router children路由报错

项目场景&#xff1a; 写个路由页面&#xff0c;引发的问题 问题描述 报错&#xff1a; An absolute child route path must start with the combined path of all its parent routes. 代码&#xff1a; import { createBrowserRouter } from "react-router-dom";…

Socket编程TCP

Socket编程TCP 1、V1——EchoServer单进程版2、V2——EchoServer多进程版3、V3——EchoServer多线程版4、V4——EchoServer线程池版5、V5——多线程远程命令执行6、验证TCP——Windows作为client访问Linux7、connect的断线重连 1、V1——EchoServer单进程版 在TcpServer.hpp中实…