基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day 1
基于 HTML5 Canvas 制作一个精美的 2048 小游戏
在这个快节奏的生活中,简单而富有挑战性的游戏总能给我们带来乐趣。2048 是一款受欢迎的益智游戏,不仅考验智力,还能让人回味无穷。今天,我带领大家将一起学习如何使用 HTML5 Canvas 来制作一个精美的 2048 小游戏。
一、了解游戏规则
在深入代码之前,我们需要了解游戏的基本规则:
- 目标:通过合并相同的数字块,最终达到2048。
- 操作:玩家可以通过上下左右的箭头键控制数字块的移动。
- 生成新块:每次成功移动后,会随机生成一个“2”或“4”的数字块。
- 游戏结束:当所有方块被填满且无法进行任何合并时,游戏结束。
二、建立 HTML 结构
首先,我们需要搭建游戏的基础 HTML 结构。在 HTML 文件中,引入 Canvas 元素以绘制游戏界面。
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>2048 游戏</title><link rel="stylesheet" href="style.css">
</head>
<body><div class="container"><canvas id="gameCanvas"></canvas></div><script src="script.js"></script>
</body>
</html>
三、样式设计
接下来,我们需要为游戏添加一些样式,使其更具吸引力。我们将在 CSS 文件中设置按钮和画布的样式。
body {display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #faf8ef;font-family: 'Arial', sans-serif;
}.container {position: relative;
}canvas {border: 2px solid #bbada0;background-color: #eee4da;
}
四、游戏逻辑实现
在脚本文件中,我们将编写游戏的核心逻辑,包括初始化游戏、绘制方块、移动操作和合并方块等。
4.1 初始化
首先,我们需要创建一个类似于二维数组的数字格子,并用随机数填充初始状态。
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');const gridSize = 4;
const tileSize = 100;
canvas.width = gridSize * tileSize;
canvas.height = gridSize * tileSize;let board = Array.from({ length: gridSize }, () => Array(gridSize).fill(0));function initBoard() {addRandomTile();addRandomTile();drawBoard();
}function drawBoard() {ctx.clearRect(0, 0, canvas.width, canvas.height);for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {drawTile(r, c);}}
}function drawTile(r, c) {const value = board[r][c];ctx.fillStyle = value !== 0 ? getTileColor(value) : '#ccc0b3';ctx.fillRect(c * tileSize, r * tileSize, tileSize - 10, tileSize - 10);if (value !== 0) {ctx.fillStyle = '#776e65';ctx.font = 'bold 45px Arial';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText(value, c * tileSize + tileSize / 2 - 5, r * tileSize + tileSize / 2);}
}function getTileColor(value) {switch (value) {case 2: return '#eee4da';case 4: return '#ede0c8';case 8: return '#f2b179';case 16: return '#f59563';case 32: return '#f67c5f';case 64: return '#f67c5f';case 128: return '#edcf72';case 256: return '#edcc61';case 512: return '#edc850';case 1024: return '#edc53f';case 2048: return '#edc22e';default: return '#ccc0b3';}
}function addRandomTile() {let emptyCells = [];for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {if (board[r][c] === 0) {emptyCells.push({ r, c });}}}if (emptyCells.length) {const { r, c } = emptyCells[Math.floor(Math.random() * emptyCells.length)];board[r][c] = Math.random() < 0.9 ? 2 : 4;}
}
4.2 移动与合并方块
通过键盘事件监听来实现方块的移动和合并,我们定义方向常量,结合用户输入的方向实现移动和合并的逻辑。
document.addEventListener('keydown', (event) => {switch (event.key) {case 'ArrowUp':moveUp();break;case 'ArrowDown':moveDown();break;case 'ArrowLeft':moveLeft();break;case 'ArrowRight':moveRight();break;}drawBoard();
});function canMergeTiles(r1, c1, r2, c2) {return board[r1][c1] !== 0 && board[r1][c1] === board[r2][c2];
}function moveUp() {for (let c = 0; c < gridSize; c++) {for (let r = 1; r < gridSize; r++) {if (board[r][c] !== 0) {let targetRow = r;while (targetRow > 0 && board[targetRow - 1][c] === 0) {// 向上移动board[targetRow - 1][c] = board[targetRow][c];board[targetRow][c] = 0;targetRow--;}if (targetRow > 0 && canMergeTiles(targetRow - 1, c, targetRow, c)) {// 合并方块board[targetRow - 1][c] *= 2;board[targetRow][c] = 0;}}}}
}function moveDown() {for (let c = 0; c < gridSize; c++) {for (let r = gridSize - 2; r >= 0; r--) {if (board[r][c] !== 0) {let targetRow = r;while (targetRow < gridSize - 1 && board[targetRow + 1][c] === 0) {// 向下移动board[targetRow + 1][c] = board[targetRow][c];board[targetRow][c] = 0;targetRow++;}if (targetRow < gridSize - 1 && canMergeTiles(targetRow + 1, c, targetRow, c)) {// 合并方块board[targetRow + 1][c] *= 2;board[targetRow][c] = 0;}}}}
}function moveLeft() {for (let r = 0; r < gridSize; r++) {for (let c = 1; c < gridSize; c++) {if (board[r][c] !== 0) {let targetCol = c;while (targetCol > 0 && board[r][targetCol - 1] === 0) {// 向左移动board[r][targetCol - 1] = board[r][targetCol];board[r][targetCol] = 0;targetCol--;}if (targetCol > 0 && canMergeTiles(r, targetCol - 1, r, targetCol)) {// 合并方块board[r][targetCol - 1] *= 2;board[r][targetCol] = 0;}}}}
}function moveRight() {for (let r = 0; r < gridSize; r++) {for (let c = gridSize - 2; c >= 0; c--) {if (board[r][c] !== 0) {let targetCol = c;while (targetCol < gridSize - 1 && board[r][targetCol + 1] === 0) {// 向右移动board[r][targetCol + 1] = board[r][targetCol];board[r][targetCol] = 0;targetCol++;}if (targetCol < gridSize - 1 && canMergeTiles(r, targetCol + 1, r, targetCol)) {// 合并方块board[r][targetCol + 1] *= 2;board[r][targetCol] = 0;}}}}
}
五、完善游戏体验
在游戏逻辑实现后,我们需要添加分数计算、胜利和失败的提示,以及重新开始游戏的功能。这些都将进一步提升游戏体验。
5.1 分数系统
我们为游戏添加分数系统,每次合并方块时更新分数。
let score = 0;function mergeTiles(r1, c1, r2, c2) {if (board[r1][c1] === board[r2][c2]) {board[r1][c1] *= 2;score += board[r1][c1];board[r2][c2] = 0;}
}
5.2 结束提示
当玩家没有可移动的方块时,可以弹出提示框告知游戏结束。
function checkGameOver() {for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {if (board[r][c] === 0) {return false; // 还有空格}if (c < gridSize - 1 && canMergeTiles(r, c, r, c + 1)) {return false; // 可以合并}if (r < gridSize - 1 && canMergeTiles(r, c, r + 1, c)) {return false; // 可以合并}}}return true; // 游戏结束
}function showGameOver() {alert('游戏结束!您的得分是:' + score);
}
结论
现在,您应该对如何使用 HTML5 Canvas 制作一个 2048 小游戏有了更详细的了解。从简单的 UI 设计到移动和合并方块的逻辑实现,每一步都至关重要。虽然本文未能详细说明所有代码,但希望您能根据提供的思路和示例进行深入探索和实现。创建游戏是一项有趣且富有成就感的工作,快去尝试制作您自己的 2048 小游戏吧!
完整代码
HTML (index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>2048 游戏</title><link rel="stylesheet" href="style.css">
</head>
<body><div class="container"><canvas id="gameCanvas"></canvas></div><script src="script.js"></script>
</body>
</html>
CSS (style.css)
body {display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #faf8ef;font-family: 'Arial', sans-serif;
}.container {position: relative;
}canvas {border: 2px solid #bbada0;background-color: #eee4da;
}
JavaScript (script.js)
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');const gridSize = 4;
const tileSize = 100;
canvas.width = gridSize * tileSize;
canvas.height = gridSize * tileSize;let board = Array.from({ length: gridSize }, () => Array(gridSize).fill(0));
let score = 0;initBoard();function initBoard() {addRandomTile();addRandomTile();drawBoard();
}function drawBoard() {ctx.clearRect(0, 0, canvas.width, canvas.height);for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {drawTile(r, c);}}// 显示分数ctx.fillStyle = '#776e65';ctx.font = 'bold 20px Arial';ctx.textAlign = 'center';ctx.fillText('Score: ' + score, canvas.width / 2, canvas.height - 20);
}function drawTile(r, c) {const value = board[r][c];ctx.fillStyle = value !== 0 ? getTileColor(value) : '#ccc0b3';ctx.fillRect(c * tileSize, r * tileSize, tileSize - 10, tileSize - 10);if (value !== 0) {ctx.fillStyle = '#776e65';ctx.font = 'bold 45px Arial';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText(value, c * tileSize + tileSize / 2 - 5, r * tileSize + tileSize / 2);}
}function getTileColor(value) {switch (value) {case 2: return '#eee4da';case 4: return '#ede0c8';case 8: return '#f2b179';case 16: return '#f59563';case 32: return '#f67c5f';case 64: return '#f67c5f';case 128: return '#edcf72';case 256: return '#edcc61';case 512: return '#edc850';case 1024: return '#edc53f';case 2048: return '#edc22e';default: return '#ccc0b3';}
}function addRandomTile() {let emptyCells = [];for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {if (board[r][c] === 0) {emptyCells.push({ r, c });}}}if (emptyCells.length) {const { r, c } = emptyCells[Math.floor(Math.random() * emptyCells.length)];board[r][c] = Math.random() < 0.9 ? 2 : 4;}
}document.addEventListener('keydown', (event) => {let moved = false;switch (event.key) {case 'ArrowUp':moved = moveUp();break;case 'ArrowDown':moved = moveDown();break;case 'ArrowLeft':moved = moveLeft();break;case 'ArrowRight':moved = moveRight();break;}if (moved) {addRandomTile();drawBoard();if (checkGameOver()) {showGameOver();}}
});function canMergeTiles(r1, c1, r2, c2) {return board[r1][c1] !== 0 && board[r1][c1] === board[r2][c2];
}function moveUp() {let moved = false;for (let c = 0; c < gridSize; c++) {for (let r = 1; r < gridSize; r++) {if (board[r][c] !== 0) {let targetRow = r;while (targetRow > 0 && board[targetRow - 1][c] === 0) {board[targetRow - 1][c] = board[targetRow][c];board[targetRow][c] = 0;targetRow--;moved = true;}if (targetRow > 0 && canMergeTiles(targetRow - 1, c, targetRow, c)) {board[targetRow - 1][c] *= 2;score += board[targetRow - 1][c];board[targetRow][c] = 0;moved = true;}}}}return moved;
}function moveDown() {let moved = false;for (let c = 0; c < gridSize; c++) {for (let r = gridSize - 2; r >= 0; r--) {if (board[r][c] !== 0) {let targetRow = r;while (targetRow < gridSize - 1 && board[targetRow + 1][c] === 0) {board[targetRow + 1][c] = board[targetRow][c];board[targetRow][c] = 0;targetRow++;moved = true}if (targetRow < gridSize - 1 && canMergeTiles(targetRow + 1, c, targetRow, c)) {board[targetRow + 1][c] *= 2;score += board[targetRow + 1][c];board[targetRow][c] = 0;moved = true;}}}}return moved;
}function moveLeft() {let moved = false;for (let r = 0; r < gridSize; r++) {for (let c = 1; c < gridSize; c++) {if (board[r][c] !== 0) {let targetCol = c;while (targetCol > 0 && board[r][targetCol - 1] === 0) {board[r][targetCol - 1] = board[r][targetCol];board[r][targetCol] = 0;targetCol--;moved = true;}if (targetCol > 0 && canMergeTiles(r, targetCol - 1, r, targetCol)) {board[r][targetCol - 1] *= 2;score += board[r][targetCol - 1];board[r][targetCol] = 0;moved = true;}}}}return moved;
}function moveRight() {let moved = false;for (let r = 0; r < gridSize; r++) {for (let c = gridSize - 2; c >= 0; c--) {if (board[r][c] !== 0) {let targetCol = c;while (targetCol < gridSize - 1 && board[r][targetCol + 1] === 0) {board[r][targetCol + 1] = board[r][targetCol];board[r][targetCol] = 0;targetCol++;moved = true;}if (targetCol < gridSize - 1 && canMergeTiles(r, targetCol + 1, r, targetCol)) {board[r][targetCol + 1] *= 2;score += board[r][targetCol + 1];board[r][targetCol] = 0;moved = true;}}}}return moved;
}function checkGameOver() {for (let r = 0; r < gridSize; r++) {for (let c = 0; c < gridSize; c++) {if (board[r][c] === 0) {return false; // 还有空格}if (c < gridSize - 1 && canMergeTiles(r, c, r, c + 1)) {return false; // 可以合并}if (r < gridSize - 1 && canMergeTiles(r, c, r + 1, c)) {return false; // 可以合并}}}return true; // 游戏结束
}function showGameOver() {alert('游戏结束!您的得分是:' + score);
}
相关文章:
基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day 1
基于 HTML5 Canvas 制作一个精美的 2048 小游戏 在这个快节奏的生活中,简单而富有挑战性的游戏总能给我们带来乐趣。2048 是一款受欢迎的益智游戏,不仅考验智力,还能让人回味无穷。今天,我带领大家将一起学习如何使用 HTML5 Canv…...
macos arm 本地/docker/本地k8s 安装jupyterhub 并登陆
概述 很多文章写的启动官方docker镜像后,新建linux用户即可直接登录,不知道是否版本原因,总之目前最新版我亲测不可以,踩坑两天,这里记录下解决过程,以及各种细节在文档中的位置.以及为什么官方镜像不能直接使用的原因. part1 本地安装jupyterhub https://jupyterhub.readth…...
go采集注册表
package mainimport ("fmt""golang.org/x/sys/windows/registry""log""os""strconv""strings" )func USBSTOR_Enum() {// 打开注册表键keyPath : SYSTEM\CurrentControlSet\Services\USBSTOR\Enumk, err : regist…...
Java连接TDengine和MySQL双数据源
git文件地址:项目首页 - SpringBoot连接TDengine和MySQL双数据源:SpringBoot连接TDengine和MySQL双数据源 - GitCode 1、yml配置 spring:datasource:druid:mysql:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/testusername: roo…...
配置AOSP下载环境
1#curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo 2#repo init -u https://android.googlesource.com/platform/manifest 3#清华镜像站帮助页 https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/ 4#同步安卓AOSP 这里是安卓13 repo init -u htt…...
SpringBoot源码解析(七):应用上下文结构体系
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...
5 分钟复刻你的声音,一键实现 GPT-Sovits 模型部署
想象一下,只需简单几步操作,就能生成逼真的语音效果,无论是为客户服务还是为游戏角色配音,都能轻松实现。GPT-Sovits 模型,其高效的语音生成能力为实现自然、流畅的语音交互提供了强有力的技术支持。本文将详细介绍如何…...
数字化时代,传统代理模式的变革之路
在数字化飞速发展的今天,线上线下融合(O2O)成了商业领域的大趋势。这股潮流,正猛烈冲击着传统代理模式,给它带来了新的改变。 咱们先看看线上线下融合现在啥情况。线上渠道那是越来越多,企业纷纷在电商平台…...
python爬虫爬取淘宝商品比价||淘宝商品详情API接口
最近在学习北京理工大学的爬虫课程,其中一个实例是讲如何爬取淘宝商品信息,现整理如下: 功能描述:获取淘宝搜索页面的信息,提取其中的商品名称和价格 探讨:淘宝的搜索接口 翻页的处理 技术路线:requests…...
HunyuanVideo 文生视频模型实践
HunyuanVideo 文生视频模型实践 flyfish 运行 HunyuanVideo 模型使用文本生成视频的推荐配置(batch size 1): 模型分辨率(height/width/frame)峰值显存HunyuanVideo720px1280px129f60GHunyuanVideo544px960px129f45G 本项目适用于使用 N…...
CSRF攻击XSS攻击
概述 在 HTML 中,<a>, <form>, <img>, <script>, <iframe>, <link> 等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指…...
vue3学习日记8 - 一级分类
最近发现职场前端用的框架大多为vue,所以最近也跟着黑马程序员vue3的课程进行学习,以下是我的学习记录 视频网址: Day2-17.Layout-Pinia优化重复请求_哔哩哔哩_bilibili 学习日记: vue3学习日记1 - 环境搭建-CSDN博客 vue3学…...
Notepad++移除所有空格
1.打开Notepad。 2.打开你想要编辑的文件。 3.按下 Ctrl H 打开查找和替换对话框,并选择 “正则表达式”。 4.在 “查找目标” 框中输入 \s。 5.在 “替换为” 框中留空,不填写任何内容。 6.点击 “全部替换” 按钮。...
JavaSE第八天
一、继承之super关键字 super关键字: 一个引用变量,用于引用父类对象 父类和子类都具有相同的命名方法,要调用父类方法时使用 父类和子类都具有相同的命名属性,要调用父类中的属性时使用 super也是父类的构造函数,…...
ideal jdk报错如何解决
例如: 可能一:环境变量中未配置 请在Path中加入并将要使用的最好置顶,如 可能二:项目结构中语言级别错误: 可能三:Maven工程中,对于模块要单独设置jdk: 如: 未设置则为默认,在博主本次展示中为:...
嵌入式Linux ntpclient的使用
ntpclient是一个用于与NTP(Network Time Protocol,网络时间协议)服务器通信并测量系统时间的工具。我这里用的是"ntpclient_2024_132"。下载源码编译后会得到一个ntpclient程序。 下面是对ntpclient每个选项的解释: -…...
25/1/15 嵌入式笔记 初学STM32F108
GPIO初始化函数 GPIO_Ini:初始化GPIO引脚的模式,速度和引脚号 GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA的引脚0 GPIO输出控制函数 GPIO_SetBits:将指定的GPIO引脚设置为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0); // 将GPIO…...
【练习】力扣热题100 字符串解码
题目 给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k保证为正整数。 你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,…...
1.快慢指针-力扣-283-移动零
题目描述 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 用例 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nu…...
5. 使用springboot做一个音乐播放器软件项目【业务逻辑开发】
#万物oop 上一章文章 我们做了音乐播放器 数据表的创建。参加地址: https://blog.csdn.net/Drug_/article/details/145093705 今天分享的这篇文章就是根据数据表 来写 业务逻辑 。 今天我们主要是实现管理后台的功能。 对于这篇文章 的理解 需要小伙伴有 springbo…...
配置正确spring-boot工程启动的时候报错dynamic-datasource Please check the setting of primary
一个两年没有碰的spring-boot工程,启动时报错。因为用了baomidou的多源数据库配置,因此启动时报错primary没有正确配置。经过检查,确定配置文件配置正确。 报错原因是没有读到正确的配置文件。pom文件里的resources标签重定义,把…...
Freeswitch使用media_bug能力实现回铃音检测
利用freeswitch的media bug能力来在智能外呼时通过websocket对接智能中心的声音检测接口,来实现回铃音检测,来判断用户当前是否已响应,拒接,关机等。 1.回铃音处理流程 2.模块源码目录结构 首先新建一个freeswitch的源码的src/a…...
Kubernetes(k8s)和Docker Compose本质区别
Kubernetes(简称 k8s)和 Docker Compose 是容器编排领域的两大重要工具,虽然它们都用于管理和编排容器化应用,但在设计目标、功能特性、使用场景和复杂度上存在显著差异。以下将从多个方面详细探讨 Kubernetes 和 Docker Compose …...
OSI七层协议——分层网络协议
OSI七层协议,顾名思义,分为七层,实际上七层是不存在的,是人为的进行划分,让人更好的理解 七层协议包括,物理层(我),数据链路层(据),网络层(网),传输层(传输),会话层(会),表示层(表),应用层(用)(记忆口诀->我会用表…...
RabbitMQ 客户端 连接、发送、接收处理消息
RabbitMQ 客户端 连接、发送、接收处理消息 一. RabbitMQ 的机制跟 Tcp、Udp、Http 这种还不太一样 RabbitMQ 服务,不是像其他服务器一样,负责逻辑处理,然后转发给客户端 而是所有客户端想要向 RabbitMQ服务发送消息, 第一步&a…...
SQL ON与WHERE区别
在 MySQL 中,ON 和 WHERE 都用于过滤数据,但它们的使用场景和作用有所不同,尤其是在涉及 JOIN 操作时。下面通过具体的例子来说明它们的区别。 1. ON 的作用 ON 用于指定表之间的连接条件,决定哪些行应该被连接在一起。它在 JOI…...
[创业之路-254]:《华为数字化转型之道》-1-华为是一个由客户需求牵引、高度数字化、高度智能化、由无数个闭环流程组成的价值创造、评估、分配系统。
前言: 华为是一个由客户需求牵引、高度数字化、高度智能化、由无数个闭环流程组成的价值创造、评估、分配系统。华为的流程大到战略,小到日常工作,是由无数个自我调节自我优化的数字化闭环控制流程组成,大闭环套小闭环࿰…...
免费为企业IT规划WSUS:Windows Server 更新服务 (WSUS) 之快速入门教程(一)
哈喽大家好,欢迎来到虚拟化时代君(XNHCYL),收不到通知请将我点击星标!“ 大家好,我是虚拟化时代君,一位潜心于互联网的技术宅男。这里每天为你分享各种你感兴趣的技术、教程、软件、资源、福利…...
异步任务与定时任务
一、异步任务 基于TaskExecutionAutoConfiguration配置类中,注册的ThreadPoolTaskExecutor线程池对象进行异步任务执行。 (一)手动执行异步任务 在yml中配置线程池参数 spring: task:execution:pool:core-size: 5 # 核心线程数max-size: 20 # 最大线…...
大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(5)
大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(5) 前言本篇摘要11. Chatbot:融合大模型的多模态聊天机器人11.5 Chatbot的特殊Events11.5.1 各事件总演示11.5.2 详解.undo、.retry、.like和.edit…...
32单片机综合应用案例——基于GPS的车辆追踪器(三)(内附详细代码讲解!!!)
困难不会永远存在,只要你勇于面对,坚持努力,就一定能够战胜一切困难。每一次挑战都是一次成长的机会,不要害怕失败,失败是成功之母。只有经历过失败,你才能更加明白自己的不足,并不断改进自己&a…...
扣除价格因素与剔除季节性因素:统计数据中的“真实”增长(中英双语)
扣除价格因素与剔除季节性因素:统计数据中的“真实”增长 在经济统计分析中,我们经常会听到“扣除价格因素”和“剔除季节性因素”这两个概念。这两者都是为了排除外部干扰因素,真实反映经济活动的增长情况。它们分别针对价格波动和季节性波…...
网卡接收报文的过程
网卡接收报文的过程通常包括以下几个关键步骤: 1. 硬件接收: • 网卡硬件首先接收到从网络传输过来的数据包。网络接口卡(NIC)负责将接收到的电信号转换为数字信号,并存储到一个硬件缓冲区中。 2. DMA传输ÿ…...
Windows图形界面(GUI)-QT-C/C++ - QT 对话窗口
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 模态对话框 非模态对话框 文件对话框 基本概念 静态函数 常见属性 颜色对话框 基本概念 静态函数 常见属性 字体对话框 基本概念 静态函数 常见属性 输入对话框 基本概念 …...
bypass--2025春秋杯冬季赛
漏洞点 题目不难,这个循环赋值的结束条件是s[i]0,并且s和key再栈上的位置是挨着的 那么很容易想到,第二次循环赋值的时候,有一个溢出,溢出部分的值是第一次写入的key的值。 那么基本思路就是,利用这段溢出…...
学习微信小程序的下拉列表控件-picker
1、创建一个空白工程 2、index.wxml中写上picker布局: <!--index.wxml--> <view class"container"><picker mode"selector" range"{{array}}" bindchange"bindPickerChange"><view class"pick…...
【17】Word:林楚楠-供应链❗
目录 题目 NO1.2 NO3 NO4 NO5 NO6 NO7 NO89 题目 NO1.2 另存为:文件→另存为→文档→文件名/考生文件夹F12/FnF12→文件名/考生文件夹 插入→分节符→文本框→输入文件→排版_居中对齐→间距/回车去掉文本框的边框→选中文本框→格式:形状轮廓…...
父子盒子滑动事件穿透问题
问题描述 当父子盒子都有滚动条时,在子盒子内滚动时,父盒子滚动子盒子无法滚动,直到父盒子滚动到底部,子盒子才滚动 解决 如果是vue的项目,直接在子盒子上添加 wheel.stop""...
vue-amap、leaflet、融汇 离线地图瓦片使用情况分析
vue-amap: vue3写的,使用文档 -> 文档地址 <-的离线jsApi里的demo,发现 tile-url不能读取本地项目文件夹里的瓦片,文档里写的其实还是要互联网读取的高德瓦片......... 作者在git库回复tile-url要么放项目里使用绝对路…...
leetcode - 1055. Shortest Way to Form String
Description A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., “ace” is a subsequence of “abcd…...
【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发三
目录 1 -> 绘制图形 1.1 -> 绘制基本几何图形 1.2 -> 绘制自定义几何图形 2 -> 添加动画效果 2.1 -> animateTo实现闪屏动画 2.2 -> 页面转场动画 3 -> 常见组件说明 1 -> 绘制图形 绘制能力主要是通过框架提供的绘制组件来支撑,支…...
RabbitMQ 进阶
文章目录 一、发送者的可靠性 1.1 生产者重试机制:1.2 生产者确认机制: 1.2.1 开启生产者确认:1.2.2 定义 ReturnCallback:1.2.3 定义 ConfirmCallback: 二、MQ 的可靠性 2.1 数据持久化: 2.1.1 交换机持…...
RabbitMQ---TTL与死信
(一)TTL 1.TTL概念 TTL又叫过期时间 RabbitMQ可以对队列和消息设置TTL,当消息到达过期时间还没有被消费时就会自动删除 注:这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列本身,不是说队列过期时间…...
uniapp(小程序、app、微信公众号、H5)预览下载文件(pdf)
1. 小程序、app 在uniapp开发小程序环境或者app环境中,都可以使用以下方式预览文件 之前其实写过一篇,就是使用uniapp官网提供文件下载、文件保存、文件打开的API, uniapp文件下载 感兴趣也可以去看下 uni.downloadFile({// baseURL 是...
Spring Boot经典面试题及答案
一、Spring Boot基础知识 什么是Spring Boot? 答案: Spring Boot是Spring开源组织下的子项目,是Spring组件一站式解决方案。它简化了Spring应用程序的初始化和开发过程,通过“约定大于配置”的原则,减少了手动配置的繁…...
usb通过hdc连接鸿蒙next的常用指令
参考官方 注册报名https://www.hiascend.com/developer/activities/details/44de441ef599450596131c8cb52f7f8c/signup?channelCodeS1&recommended496144 hdc-调试命令-调测调优-系统 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guid…...
FPGA:Quartus软件与操作系统版本对照表
文章目录 1.软件概述2.软件版本3.设计流程4.支持的设备5.新特性6.版本对照 1.软件概述 Quartus软件是由英特尔(Intel)公司开发的一款功能强大的FPGA(现场可编程逻辑门阵列)设计工具,广泛应用于数字电路设计、仿真、综…...
RustDesk ID更新脚本
RustDesk ID更新脚本 此PowerShell脚本自动更新RustDesk ID和密码,并将信息安全地存储在Bitwarden中。 特点 使用以下选项更新RustDesk ID: 使用系统主机名生成一个随机的9位数输入自定义值 为RustDesk生成新的随机密码将RustDesk ID和密码安全地存储…...
[C语言]字符串分离
题目 从标准输入流(控制台)中获取一行字符串 str,字符串中可能会存在空格,现在需要将字符串进行分离,规则如下: (1)将 str 中位于 偶数下标 的元素放置在字符串 str1 之中 (2)将 str 中位于 奇数下标 的…...
-bash: /java: cannot execute binary file
在linux安装jdk报错 -bash: /java: cannot execute binary file 原因是jdk安装包和linux的不一致 程序员的面试宝典,一个免费的刷题平台...