canvas 制作2048

news2024/11/27 2:22:54

效果展示

对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步:

  1. 去0
  2. 合成
  3. 去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;
          }
        }
        // 去0
        const 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 和 求和 的过程完全可以封装成一个函数减少代码冗余。

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

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

相关文章

docker安装elashticsearch

福利&#xff1a;这是我的个人IT资源网站&#xff0c;所有资源都免费&#xff0c;注册登录后就可以看到密码&#xff0c;需要什么大家尽情选取&#xff01; 从docker下载elashticsearch镜像&#xff08;可以指定版本号&#xff09; docker pull elasticsearch:7.4.22. 从dock…

网络安全实验室3.脚本关

3.脚本关 1.key又又找不到了 url&#xff1a;http://lab1.xseclab.com/xss1_30ac8668cd453e7e387c76b132b140bb/index.php 点击链接&#xff0c;burp抓包&#xff0c;发送到重放模块&#xff0c;点击go 得到key is : yougotit_script_now 2.快速口算 url&#xff1a;http:…

树莓派开机自启动Python脚本或者应用程序

树莓派开机自启动Python脚本或者应用程序前言一、对于Python脚本的自启动方法1、打开etc/rc.local文件2、编辑输入需要启动的指令3、重启树莓派验证二、对于需要读写配置文件的应用程序的自启前言 在树莓派上写了一些Python脚本&#xff0c;还有一个java 的jar包想要在树莓派上…

2023年,什么样的CRM,才是您最需要的?

春节假期刚刚结束&#xff0c;当大家还沉浸在新春佳节的喜悦中时&#xff0c;很多地方已经争先恐后地奋力开跑了。近日&#xff0c;全国各地方政府相继出台并发布了2023年数字化转型规划&#xff0c;纷纷结合自身的区位特色和优势资源&#xff0c;明确2023年乃至此后数年的数字…

动态规划详解(完结篇)——如何抽象出动态规划算法?以及解题思路

今天直接开始讲解FIRST&#xff1a;如何抽象出动态规划算法&#xff1f;这个问题&#xff0c;困扰了无数代OIER&#xff0c;包括本蒟蒻在比赛的时候&#xff0c;看一道题&#xff0c;怎么想到他是什么算法的呢&#xff1f;这就需要抽象能力而不同的算法&#xff0c;往往有着不同…

The last packet sent successfully to the server was 0 milliseconds ago. 解决办法

mybatis-generator-maven-plugin插件The last packet sent successfully to the server was 0 milliseconds agoYou must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to…

Spark SQL 介绍

文章目录Spark SQL1、Hive on SparkSQL2、SparkSQL 优点3、SparkSQL 特点1) 容易整合2) 统一的数据访问3) 兼容 Hive4) 标准的数据连接4、DataFrame 是什么5、DataSet 是什么Spark SQL Spark SQL 是 Spark 用于结构化数据(structured data) 处理的Spark模块。 1、Hive on Spa…

维基百科数据抽取

1. 数据路径 https://dumps.wikimedia.org/enwiki/latest/ ----英文 https://dumps.wikimedia.org/zhwiki/latest/ ----中文 https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles.xml.bz2 --下载最新的 https://dumps.wikimedia.org/wikidatawiki/2023…

公司招了个腾讯P7:闲聊后被我套出拿下35Koffer的面试技巧

早上一进公司就见人事热热闹闹的带人办入职手续&#xff0c;早之前听说公司将来一个腾讯离职的同事&#xff0c;薪资已达中上水平&#xff0c;大家都很好奇到底是怎样的人才&#xff0c;果不其然&#xff0c;让我们见识到什么是测试天花板 在新人见面会上&#xff0c;自动化、测…

web开发

目录 使用Idea搭建Web项目 使用Idea开发Web项目基本知识 tomcat配置信息 HTML /CSS 开发主页 Servlet 学习和掌握的内容&#xff1a; HTML/CSSServlet MVC模式和Web开发数据库基本应用和JDBC应用软件项目开发流程 环境及工具版本&#xff1a; Windows10,JDK1.8 Idea2…

【C++】基于范围的for循环 (C++11)

基于范围的for循环 C11 一、范围for的基本语法二、范围for中使用引用 &#xff08;一些奇葩的问题&#xff09;讨论三、范围for的使用条件一、范围for的基本语法 在C98中如果要遍历一个数组&#xff0c;可以按照以下方式进行&#xff1a; #include<iostream> using nam…

分享111个JS焦点图代码,总有一款适合您

分享111个JS焦点图代码&#xff0c;总有一款适合您 111个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1GxjW5m9DNOPEQd-Qf_gGSA?pwd4aci 提取码&#xff1a;4aci Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj jQuery宽屏左右…

锦正茂EM3电磁铁的技术参数

产品特点&#xff1a; ※U形结构、视野开阔、磁场强度高、磁场强度大小调节方便 ※体积小、重量轻、占空比小、结构紧凑、磁场性能更佳 ※电磁铁的工作气隙调节轻便灵活&#xff0c;极头处设有螺纹&#xff0c;更换极头装卸方便 ※可选配工作间隙刻度指示 ※小气隙时用于铁…

代理模式(Proxy Pattern)

代理模式定义&#xff1a; 提供了对目标对象另外的访问方式&#xff1b;即通过代理对象访问目标对象。举个例子&#xff1a;猪八戒去找高翠兰结果是孙悟空变的&#xff0c;可以这样理解&#xff1a;把高翠兰的外貌抽象出来&#xff0c;高翠兰和孙悟空都实现了这个接口&#xff…

跨境电商选品重要吗?

选品很重要&#xff01;跨境电子商务选择的核心要求&#xff1a;优质商品&#xff0c;价格优势&#xff0c;符合跨境销售特点&#xff0c;满足目标海外市场需求&#xff0c;突出自身特色竞争优势。跨境电商是如何选择产品的&#xff1f;这个问题也很流行&#xff0c;应该考虑以…

面试-java Spring 一

一.Spring两大特性 控制反转(IoC)&#xff1a;就是创建对象的控制权&#xff0c;被反转到了Spring框架上。通常我们实例化一个对象时&#xff0c;都是使用类的构造方法来new一个对象&#xff0c;这个过程是由我们自己来控制的&#xff0c;而控制反转就把new对象的工交给了Spri…

加拿大访问学者家属如何办理探亲签证?

由于大多数访问学者的访学期限都为一年&#xff0c;家人来访不仅可以缓解访学的寂寞生活&#xff0c;而且也是家人到加拿大体验国外风情的好机会。家属在国内申请赴加签证时&#xff0c;如果材料齐全&#xff0c;一般上午递交了申请&#xff0c;下午就可以拿到签证。以下是家人…

mongo DB数据库bindIP的配置和我的理解(bindIP不是应用服务器的IP)

先批评这个文章&#xff01;典型的错误&#xff0c;bindIP根本不是绑定哪一个ip的 背景&#xff1a;最近在阿里云上搭建overleaf的web服务集群&#xff0c;数据库和应用服务器分离&#xff0c;一口气买了三台服务器准备开始干活。overleaf用的是mongodb&#xff0c;我本来准备…

【多道批处理系统】计算完成两个作业需要的最少时间,并图文叙述

一个多道批处理系统中仅有P1和P2两个作业,P2比P1晚5ms到达, 它们的计算和I/O操作顺序如下。 P1:计算60ms,I/O操作80ms,计算20ms。 P2:计算120ms,I/O操作40ms,计算40ms。 不考虑调度和切换时间,请计算完成两个作业需要的最少时间&#xff0c;并图文叙述两个作业的执行情况。

[开源]ChatGPT-OpenAI注册使用保姆级教程?[开箱可用][免费使用]

[开源]ChatGPT-OpenAI注册使用保姆级教程?[开箱可用][免费使用]ChatGPT是什么?1.ChatGPT官网2.一部分打不开的ChatGPT官网3.如何开始真实的ChatGPT官网之旅...3.1有美国IP的服务器3.2一个chrome浏览器插件ChatGPT for Google3.3打开了...4.获取用户输入正确的手机号(美国)4.1…