canvas 制作2048
效果展示
对UI不满意可以自行调整,这里只是说一下游戏的逻辑,具体的API调用不做过多展示。

玩法分析
2048 的玩法非常简单,通过键盘的按下,所有的数字都向着同一个方向移动,如果出现两个相同的数字,就将这两个数字合成,如果所有的各自都被占满,并且无法合成的时候,视为游戏失败。
功能实现
场景
需要一个背景和16个格子,使用绘制矩形的API和一个双重循环就可以实现。
function drawMap() {ctx.beginPath();ctx.fillStyle = '#bbada0'ctx.fillRect(200,0,600,600);for(let i = 0; i < 4; i++){for(let k = 0; k < 4; k++){ctx.beginPath();ctx.fillStyle = 'rgba(238, 228, 218, 0.35)';ctx.fillRect(i * 150 + 210, k*150+10,130,130);}}
}
数字生成
我们随机生成一个数字2 或者 4 ,并且需要随机一个没有数字的位置。
在这之前我们需要准备几个变量
- number: 用来存储新生成的数字
- map: 一个二维数组,用来储存格子中的数字,如果是0则视为空
使用Math.random()生成随机数,并且利用循环反复生成位置,知道生成的位置为空,将数字填入map数组的对应位置。
function createNumber(closebtn) {let number = Math.random() > 0.5 ? 2 : 4;let x, y; let gameover = true;for(let i = 0; i < 4; i++){for(let j = 0; j < 4; j++){if(numberlist[i][j] == 0){gameover = false;break;}}}// 这里是对游戏结束的判断if(gameover) {alert('gameover!');init();return;}while(1) {x = Math.floor(Math.random() * 4);y = Math.floor(Math.random() * 4);if(numberlist[x][y] == 0) break;}numberlist[x][y] = number;
}
更新视图
之前我们定义的一个数组map,用来储存格子中的数据,之后我们只需要根据这个map中的数据去更新我们的画布,就可以实现数字的渲染,之后的合成,也只需要对map这个数组进行更新,然后再根据数组中的数据去渲染视图。
代码中也包含了2048的配色方案,对颜色不敏感的直接用这套方案就好
function drawNumber() {for(let i = 0; i < 4; i++){for(let j = 0; j < 4; j++){let color = '';switch(numberlist[i][j]) {case 0: continue; break;case 2: color = '#EEE4DA'; break;case 4: color = '#ECE0C8'; break;case 8: color = '#f2b179'; break;case 16: color = '#f59563'; break;case 32: color = '#f67c5f'; break;case 64: color = '#f65e3b'; break;case 128: color = '#edcf72'; break;case 256: color = '#edcc61'; break;case 512: color = '#edc850'; break;case 1024: color = '#edc53f'; break;case 2048: color = '#edc22e'; break;}ctx.beginPath();ctx.fillStyle = color;ctx.fillRect(j * 150 + 210, i*150+10, 130, 130);ctx.fillStyle = 'black';ctx.fillText(numberlist[i][j], j * 150 + 75 + 200, i * 150+75, 130);}}
}
事件监听
为对应的按键绑定事件:
document.addEventListener('keydown', (e) => {switch(e.key) {case 'w': case 'ArrowUp':// 这个函数用来更新数据,下一步会见到uploadNumberList('top');break;case 'a': case 'ArrowLeft': uploadNumberList('left');break;case 's': case 'ArrowDown': uploadNumberList('bottom');break;case 'd': case 'ArrowRight': uploadNumberList('right');break;default: break;}
数据更新
数据的更新,我们用向左来做例子,一共分为3步:
- 去0
- 合成
- 去0
下面是实现的代码:
整体的思路下面的代码中写有注释
// 4行, 向左for(let i = 0; i < 4; i++){// 每一行执行去0,加和,去0三项// 建一个新数组拷贝非0元素const arr = numberlist[i];const newArr = [0,0,0,0];let cnt = 0;for(let j = 0; j < 4; j++){if(arr[j] != 0) {newArr[cnt] = arr[j];cnt++;}}// 求和for(let j = 0; j < 3; j++){if(newArr[j] == newArr[j+1] && newArr[j] != 0){newArr[j] = newArr[j] * 2;newArr[j+1] = 0;}}// 去0const newArr2 = [0,0,0,0];cnt = 0;for(let j = 0; j < 4; j++){if(newArr[j] != 0) {newArr2[cnt] = newArr[j];cnt++;}}// 经过上面的三步这一行已经处理完成,将新的处理完成的数组替换原有的numberlist[i] = newArr2;}
数据更新之后,不要忘记重新渲染下视图。
结束
到这里游戏就制作好了,像这种小游戏我觉得采用面向过程的方式更加合适

自己先玩上一把
另外像是 去0 和 求和 的过程完全可以封装成一个函数减少代码冗余。
相关文章:
canvas 制作2048
效果展示 对UI不满意可以自行调整,这里只是说一下游戏的逻辑,具体的API调用不做过多展示。 玩法分析 2048 的玩法非常简单,通过键盘的按下,所有的数字都向着同一个方向移动,如果出现两个相同的数字,就将…...
playwright: 全局修改页面等待超时时间
等待超时时间默认是30s, 可以通过以下几个方法设置: browser_context.set_default_navigation_timeout()browser_context.set_default_timeout()page.set_default_navigation_timeout()page.set_default_timeout() set_default_navigation_timeout set_default_n…...
C++类和对象(中)
✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 I do not believe in taking the right decision. I take a decision and make it right. 我不相信什么正确的决定。我都是先做决定,然后把…...
Docker安装EalasticSearch、Kibana,安装Elasticvue插件
使用Docker快速安装部署ES和Kibana的前提:首先需要确保已经安装了Docker环境。 如果没有安装Docker的话,先在Linux上安装Docker。 有了Docker环境后,就可以使用Docker安装部署ES和Kibana了 一、安装ES 1、拉取EalasticSearch镜像 docker p…...
算法训练营 day39 贪心算法 无重叠区间 划分字母区间 合并区间
算法训练营 day39 贪心算法 无重叠区间 划分字母区间 合并区间 无重叠区间 435. 无重叠区间 - 力扣(LeetCode) 给定一个区间的集合 intervals ,其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互…...
c/c++开发,无可避免的文件访问开发案例
一、缓存文件系统 ANSI C标准中的C语言库提供了fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等标准函数,这些函数在不同的操作系统中应该调用不同的内核API,从而支持开发者跨平台实现对文件的访问。 在Lin…...
MySQL学习笔记
MySQL学习笔记一、基础配置二、数据库操作三、表的操作1.创建表2.表选项3.查看表4.修改表5.删除表6.复制表7.检查优化修复表四、数据操作基础增删改查五、字符集编码六、数据类型(列类型)1.数值类型2.字符串类型3.日期时间类型4.枚举和集合七、列属性&am…...
ccs导入工程失败的处理方法
文章目录当导入CCS新工程时出现下述错误怎么办?方法一 从TI官网下载安装包进行安装,下载链接:软件下载完成 安装路径为上面的文件夹点击安装完成后,导入安装路径,并点击Refresh按钮,依据路径进行更新&#…...
探针台常见的故障及解决方法
症状、 可能原因、 解决方法 移动样品后画面变模糊 —显微镜不垂直,调垂直显微镜 样品台不水平 —调水平样品台 显微镜视场亮度不足,边缘切割或看不到像—转换器不在定位位置上 把转换器转到定位位置上 管镜转盘不在定位位置上 —把管镜转盘转到定…...
域内资源探测
✅作者简介:CSDN内容合伙人、信息安全专业在校大学生🏆 🔥系列专栏 :内网安全 📃新人博主 :欢迎点赞收藏关注,会回访! 💬舞台再大,你不上台,永远是…...
c# 将数据导出到EXCEL文件
第一步:项目中加入引用。 在鼠标右击项目,点击【添加】弹出菜单列表,选择【项目引用】弹出【引用管理器】对话框,选择【COM】-【Microsoft Excel 16.0 Object Library】,如图所示: 第二步,编辑…...
微服务 分片 运维管理
微服务 分片 运维管理分片分片的概念分片案例环境搭建案例改造成任务分片Dataflow类型调度代码示例运维管理事件追踪运维平台搭建步骤使用步骤分片 分片的概念 当只有一台机器的情况下,给定时任务分片四个,在机器A启动四个线程,分别处理四个…...
批量占满TEMP表空间问题处理与排查
批量占满TEMP表空间问题处理与排查应急处置问题排查查看占用TEMP表空间高的SQL获取目标SQL执行计划方法一:EXPLAIN PLAN FOR方法二:DBMS_XPLAN.DISPLAY_CURSOR方法三:DBMS_XPLAN.DISPLAY_AWR方法四:AUTOTRACE数据库跑批任务占满TE…...
Pytorch中的tensor和variable
Tensor与Variable pytorch两个基本对象:Tensor(张量)和Variable(变量) 其中,tensor不能反向传播,variable可以反向传播(forword)。 反向传播是为了让神经网络更新前面…...
暗月内网渗透实战——项目七
首先环境配置 VMware的网络配置图 环境拓扑图 开始渗透 信息收集 使用kali扫描一下靶机的IP地址 靶机IP:192.168.0.114 攻击机IP:192.168.0.109 获取到了ip地址之后,我们扫描一下靶机开放的端口 靶机开放了21,80,999,3389,5985,6588端口…...
【Java 面试合集】描述下Objec类中常用的方法(未完待续中...)
描述下Objec类中常用的方法 1. 概述 首先我们要知道Object 类是所有的对象的基类,也就是所有的方法都是可以被重写的。 那么到底哪些方法是我们常用的方法呢??? cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringw…...
SQLSERVER 的 truncate 和 delete 有区别吗?
一:背景 1. 讲故事 在面试中我相信有很多朋友会被问到 truncate 和 delete 有什么区别 ,这是一个很有意思的话题,本篇我就试着来回答一下,如果下次大家遇到这类问题,我的答案应该可以帮你成功度过吧。 二࿱…...
【C++】CC++内存管理
就是你被爱情困住了?Wake up bro! 文章目录一、C/C内存分布二、C语言中动态内存管理方式三、C中内存管理方式1.new和delete操作内置类型2.new和delete操作自定义类型(仅限vs的底层实现机制,new和delete一定要匹配使用,…...
数据预处理之图像去空白
数据预处理之图像去空白图像去空白介绍方法边缘检测阈值处理形态学图像剪切图像去空白 介绍 图像去空白是指在图像处理中去除图像中的空白区域的过程。空白区域通常是指图像中的白色或其他颜色,其不包含有用的信息。去空白的目的是为了节省存储空间、提高图像处理…...
真的麻了,别再为难软件测试员了......
前言 有不少技术友在测试群里讨论,近期的面试越来越难了,要背的八股文越来越多了,考察得越来越细,越来越底层,明摆着就是想让我们徒手造航母嘛!实在是太为难我们这些测试工程师了。 这不,为了帮大家节约时…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
