文档章节

HTML5——canvas制作游戏2048

axingqi
 axingqi
发布于 2017/06/30 20:56
字数 1784
阅读 6
收藏 0
点赞 0
评论 0

         笔者刚学HTML5不久,这是笔者第一次用HTML5制作游戏,希望大家多多提点意见。

        废话不多说,先来一张效果图:

        笔者只做了游戏主体,至于那些得分啊,历史最高分之类的,都没有去实现。那些都是比较简单的内容,这里就不多说了。下面讲述的过程中,将主要是讲讲笔者本人制作过程中的一些思路。

        首先,是页面部分,这部分也没啥好讲的,直接上代码:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>2048</title>
<style type="text/css">
     div{
         text-align:center;
         margin-top:150px;
     }
     #view{
         border:1px solid #ccc;
     }
</style>
</head>
<body>
<div>
     <canvas id="view" height="500px" width="500px"></canvas>
     <script type="text/javascript" src="Test_2048.js"></script>
</div>
</body>
</html>
        值得注意的是,要为canvas设置一个id,方便js调用。接下来就是js部分了,这部分是本游戏的重点,首先,笔者声明了需要用到的一些变量和对象,如下:

var dom=document.getElementById("view");
var ctx=dom.getContext("2d");

var width=ctx.canvas.width;
var height=ctx.canvas.height;

var box_width=width*0.8*0.25;
var margin_width=width*0.2*0.20;

var digital=new Array();
for ( var i = 0; i < 4; i++) {
	digital[i]=new Array();              //声明二维数组
	for ( var j = 0; j < 4; j++) {
		digital[i][j]=0;                 //给数组赋初值
	}
}

        开头两行是必不可少的,首先通过document.getElementById()获得canvas对象,再通过canvas对象获得上下文绘图环境,(以下的方法属性几乎都是上下文绘图环境对象的方法,但是因为习惯,仍称之为canvas的方法属性,希望读者注意)还有一点要注意的是,js是没有二维数组的,所以我们通过for循环来声明二维数组并给它赋初值。做完这一步之后,下面就开始绘制游戏背景了,这是笔者的一个特点,无论做什么游戏,笔者总是先把界面给做出来,即使这可以说是开发游戏中最简单的一个环节,但笔者总有一种感觉,做出界面就是做了半个游戏,(呵呵)。而且,对笔者而言,有一个界面看着,对之后的思路可能更加清晰。扯远了,下面谈谈界面的开发。其实2048的界面很简单,就是由一个大的矩形包着十六个小矩形,在笔者制作的界面中,大矩形并无特别,只是小矩形的四个角都是圆角的,而canvas绘图并没有提供给我们绘制圆角矩形的方法,因此,笔者自定义了一个方法。笔者看过很多人自定义的画圆角矩形的方法,都比较麻烦,是用moveTo和lineTo绘制四条边,然后用圆弧公式arc绘制圆角,搞的一大堆代码。笔者这里用的arcTo这个函数,具体代码如下:

function drawRect(x,y,c){
	ctx.beginPath();
	ctx.fillStyle=c;
	ctx.moveTo(x,y);
	ctx.arcTo(x+box_width,y,x+box_width,y+1,margin_width*0.7);
	ctx.arcTo(x+box_width,y+box_width,x+box_width-1,y+box_width,margin_width*0.7);
	ctx.arcTo(x,y+box_width,x,y+box_width-1,margin_width*0.7);
	ctx.arcTo(x,y,x+1,y,margin_width*0.7);
	ctx.fill();	
}
        这里传的x和y是小矩形的左上角的坐标,c是填充的颜色,对arcTo这个函数不明白的可以查看w3cschool里的讲解,也可以查看笔者的另一篇文章: canvas学习心得之arcTo。之后是整个界面的代码,没什么好说的了:

function drawBack(){
	ctx.beginPath();
	ctx.fillStyle="#f0d799";
	ctx.fillRect(0,0,width,height);
	for ( var i= 0; i <4; i++) {
		for ( var j = 0; j < 4; j++) {
			var c="";
			if(digital[i][j]==0){c="#D7C184 ";}
			if(digital[i][j]==2){c="#f5bb82 ";}
			if(digital[i][j]==4){c="#DBB280 ";}
			if(digital[i][j]==8){c="#E1C57A ";}
			if(digital[i][j]==16){c="#E8B173 ";}
			if(digital[i][j]==32){c="#F2A769 ";}
			if(digital[i][j]==64){c="#e08931 ";}
			if(digital[i][j]==128){c="#f27f0c ";}
			if(digital[i][j]==256){c="#f76063 ";}
			if(digital[i][j]==512){c="#e84648 ";}
			if(digital[i][j]==1024){c="#b03133 ";}
			if(digital[i][j]==2048){c="#fc080c ";}
			x=margin_width+i*(box_width+margin_width);
			y=margin_width+j*(box_width+margin_width);
			drawRect(x,y,c);
		}
	}
}
        接下来就是绘制小矩形里的数字,玩过2048的都知道,它是随机在某个矩形里生成一个“2”;所以我们先要判断随机得到的那个位置是否已有数字,如果已有就重新随机,否则将他保存在数组里,以下是代码:

function createRandom(){
	var x=Math.round(Math.random()*3);
	var y=Math.round(Math.random()*3);
	if (digital[x][y]==0) {
		digital[x][y]=2;
	}else{
		createRandom();
	}
}
        这里数组里面有了数据,就可以绘制数字了,代码如下:

function drawDigital(){
	for ( var i = 0; i < 4; i++) {
		for ( var j = 0; j < 4; j++) {
			if (digital[i][j]>0) {
				ctx.beginPath();
				ctx.textAlign="center";
				ctx.textBaseline="middle";
				ctx.fillStyle="red";
				ctx.font="40px Arial";
				x=margin_width+i*(box_width+margin_width)+box_width/2;
				y=margin_width+j*(box_width+margin_width)+box_width/2;
				ctx.fillText(digital[i][j],x,y);
			}
		}
	}
}
        因为canvas有textAlign和textBaseline这两个属性,这里的x和y直接取小矩形的中心点坐标就行。

        接下来就是本游戏的重点了,玩过2048的都知道,我们下达一个向左向右或其他方向的指令,数字就会向那个方向汇拢,并且相同的数字会合并起来变成更大的数字,对此,笔者的思路是:将二维数组拆分为四个一维数组,具体拆分看指令,比如我们下达一个向右的指令,则将二维数组横向拆分,若向下则纵向拆分。然后对一维数组进行判断,是否符合指令的标准,如果不符合,则对数组进行移动和合并两个操作,然后再判断是否符合,如此循环,直到得到符合的数组,然后将数组的数据重新赋值给二维数组。之后就是清除原有的图像,重新绘制图像。如下是代码:

        判断一维数组是否符合标准:

function checkDigital(arr){                           //判断数组是否已按排列好
	var flag=false;
	if (arr[0]==0&&arr[1]==0&&arr[2]==0&&arr[3]==0||
			arr[0]>0&&arr[1]==0&&arr[2]==0&&arr[3]==0||
			arr[0]>0&&arr[1]>0&&arr[2]==0&&arr[3]==0||
			arr[0]>0&&arr[1]>0&&arr[2]>0&&arr[3]==0||
			arr[0]>0&&arr[1]>0&&arr[2]>0&&arr[3]>0) {
		flag=true;
	}
	if (arr[0]==arr[1]&&arr[0]!=0||
		arr[1]==arr[2]&&arr[1]!=0||
		arr[2]==arr[3]&&arr[2]!=0||
		arr[3]==arr[4]&&arr[3]!=0
	) {
		flag=false;
	}
	return flag;
}
         对数组进行移动和合并操作:

function changeDigital(arr){
		for ( var i = 0; i <3; i++) {
			if (arr[i]==0) {
				var temp=arr[i];
				arr[i]=arr[i+1];
				arr[i+1]=temp;
			}
			if (arr[i]==arr[i+1]&&arr[i]!=0) {
				arr[i]=arr[i]+arr[i+1];
				arr[i+1]=0;
			}		
		}
		if (checkDigital(arr)){
			return arr;
		}else{
			return changeDigital(arr);
		}
}
         最后是下指令代码,四个方向大同小异,这里只贴部分:

document.onkeydown=function(event){
     var e = event || window.event || arguments.callee.caller.arguments[0];
     if(e && e.keyCode==37){                    //向左移动
    	 for ( var i = 0; i <4; i++) {
    			var arr=new Array();
    			arr[0]=digital[0][i];
    			arr[1]=digital[1][i];
    			arr[2]=digital[2][i];
    			arr[3]=digital[3][i];
    			if (!checkDigital(arr)){
    				arr=changeDigital(arr);
    			}
    			digital[0][i]=arr[0];
    			digital[1][i]=arr[1];
    			digital[2][i]=arr[2];
    			digital[3][i]=arr[3];
    		}
    	 if (checkOver()) {
			alert("GAME OVER");
		}else{
			ctx.clearRect(0,0,width,height);
	    	createRandom();
	    	drawBack();
	    	drawDigital();
		}   	
     }

        到此就算大功告成了,笔者第一次写这么长的文章,写得不好,大家多多提点意见。

        另外,完整版代码也已上传,有兴趣的可以下载看看:点击打开链接




© 著作权归作者所有

共有 人打赏支持
axingqi
粉丝 0
博文 21
码字总数 9949
作品 0
茂名
扣丁学堂HTML5培训课程怎么样

  在如今,随着移动互联网技术的发展和进步,比如HTML5在移动互联端的应用,让更多人了解到它的丰富性趣味性便利性,但HTML5就包括这些么?扣丁学堂HTML5培训课程怎么样?零基础能学会么?...

扣丁学堂 ⋅ 06/01 ⋅ 0

WEB前端开发学习HTML5到底有多厉害?

Web前端开发工程师是一个很新的职业,是从事Web前端开发工作的工程师。主要进行网站开发,优化,完善的工作。网页制作是Web 1.0时代的产物,那时网站的主要内容都是静态的,用户使用网站的行...

web前端小辰 ⋅ 05/23 ⋅ 0

超级绚丽,20款前端动画特效,轰炸你的眼睛

前言 HTML5一个相当出色的web技术,它不仅可以让你更加方便地操纵页面元素,而且可以通过canvas实现更多的动画特效,引进HTML5标准后,CSS3也就可以发挥更大的作用。本文主要介绍了一些基于H...

浪漫程序员 ⋅ 04/25 ⋅ 0

《WebGL编程指南》学习笔记——2.使用元素

《WebGL编程指南》学习笔记——2.使用< canvas >元素 上一节初步认识了WebGL,这一小节我们来开始学习使用< canvas >元素绘制二维图形 WebGL编程指南学习笔记2使用 canvas 元素 下小节我们正...

hushhw ⋅ 2017/12/16 ⋅ 0

【重磅】IT界大牛 —— 廖雪峰加盟开课吧,Web全栈视频限时领取

2018年,互联网行业风起云涌,IT工程师如果仅凭传统开发思维,无法突破固有知识体系,终将会被社会所淘汰。会跨平台混合应用开发、微信小程序、Web应用、pc以及手机炫酷网页的HTML5全栈开发工...

vm199zkg3y7150u5 ⋅ 05/23 ⋅ 0

html5-web本地存储

在html5中为我们提供了一种本地缓存机制,它将取代我们的cookie,并且它是不会随浏览器发会我们的服务器端的。我们可以采用js在客户端自由的操作本地缓存。html5中缓存主要有localStorage,和...

zting科技 ⋅ 2017/01/10 ⋅ 0

26、《每周一点canvas动画》——3D旋转与碰撞

各位同学实在不好意思,最近忙着面试找工作,耽搁了一个星期。由于前一篇文章的关注的量比较多,让我决定以后的文章尽量多加一些高质量的DEMO和配图。可能这比较耗费时间,但质量才是王道,希...

qq_39759115 ⋅ 04/17 ⋅ 0

php canvas 前端JS压缩,获取图片二进制流数据并上传

效果图(canvas压缩图片会失真): 参考: php canvas 前端JS压缩,获取图片二进制流数据并上传 https://www.cnblogs.com/-mrl/p/8708114.html js+php如何实现上传图片 https://www.jianshu....

豆花饭烧土豆 ⋅ 05/30 ⋅ 0

Web前端最全面试宝典- Html篇

HTML 1.对WEB标准以及W3C的理解与认识 标签闭合、标签小写、不乱嵌套、提高搜索机器人搜索几率、使用外 链css和js脚本、结构行为表现的分离、文件下载与页面速度更快、内容能被更多的用户所访...

颜卿今天Coding了吗 ⋅ 2017/03/04 ⋅ 0

HTML5在客户端存储数据的新方法——localStorage

HTML5在客户端存储数据的新方法——localStorage localStorage作为HTML5本地存储web storage特性的API之一,主要作用是将数据保存在客户端中,而客户端一般是指上海网站设计用户的计算机。 ...

祈澈姑娘 ⋅ 2017/12/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

容器之重命名镜像

使用docker tag命令来重命名镜像名称,先执行help,查看如何使用如下 mjduan@mjduandeMacBook-Pro:~/Docker % docker tag --helpUsage:docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TA...

汉斯-冯-拉特 ⋅ 10分钟前 ⋅ 0

with 的高级用法

那么 上下文管理器 又是什么呢? 上下文管理器协议包含 __enter__ 和 __exit__ 两个方法。with 语句开始运行时,会在上下文管理器对象上调用 __enter__ 方法。with 语句运行结束后,会在上下...

阿豪boy ⋅ 30分钟前 ⋅ 0

使用 jsoup 模拟登录 urp 教务系统

需要的 jsoup 相关 jar包:https://www.lanzous.com/i1abckj 1、首先打开教务系统的登录页面,F12 开启浏览器调试,注意一下 Request Headers 一栏的 Cookie 选项,我们一会需要拿这个 Cook...

大灰狼时间 ⋅ 30分钟前 ⋅ 0

关于线程的创建

转自自己的笔记: http://note.youdao.com/noteshare?id=87584d4874acdeaf4aa027bdc9cb7324&sub=B49E8956E145476191C3FD1E4AB40DFA 1.创建线程的方法 Java使用Thread类代表线程,所有的线程对......

MarinJ_Shao ⋅ 41分钟前 ⋅ 0

工厂模式学习

1. 参考资料 工厂模式-伯乐在线 三种工厂-思否 深入理解工厂模式 2. 知识点理解 2.1 java三种工厂 简单工厂 工厂模式 抽象工厂 2.2 异同点 逐级复杂 简单工厂通过构造时传入的标识来生产产品...

liuyan_lc ⋅ 53分钟前 ⋅ 0

Java NIO

1.目录 Java IO的历史 Java NIO之Channel Java NIO之Buffer Java NIO之Selector Java NIO之文件处理 Java NIO之Charset Java 可扩展IO 2.简介 “IO的历史”讲述了Java IO API从开始到现在的发...

士别三日 ⋅ 57分钟前 ⋅ 0

[Err] ORA-24344: success with compilation error

从txt文本复制出创建function的脚本,直接执行,然后报错:[Err] ORA-24344: success with compilation error。 突然发现脚本的关键字,居然不是高亮显示。 然后我把脚本前面的空格去掉,执行...

wenzhizhon ⋅ 今天 ⋅ 0

Spring Security授权过程

前言 本文是接上一章Spring Security认证过程进一步分析Spring Security用户名密码登录授权是如何实现得; 类图 调试过程 使用debug方式启动https://github.com/longfeizheng/logback该项目,...

hutaishi ⋅ 今天 ⋅ 0

HAProxy基于KeepAlived实现Web高可用及动静分离

前言 软件负载均衡一般通过两种方式来实现: 基于操作系统的软负载实现 基于第三方应用的软负载实现 LVS是基于Linux操作系统实现的一种软负载,而HAProxy则是基于第三方应用实现的软负载。 ...

寰宇01 ⋅ 今天 ⋅ 0

微软自研处理器的小动作:已经开始移植其他平台的工具链

微软将 Windows 10 、Linux 以及工具链如 C/C++ 和 .NET Core 运行时库、Visual C++ 2017 命令行工具、RyuJIT 编辑器等移植到其自主研发的处理器架构 E2。微软还移植了广泛使用的 LLVM C/C++...

linux-tao ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部