今天手把手教大家写canvas黑白块小游戏
其实canvas基本代码都是在js中写的,我写这个是如果带入到网页中 最好用手机版查看。
首先是css和html
css:
html,body{ width: 100%; height: 100%; margin: 0; padding: 0; text-align: center; overflow: hidden; }
html:
然后开始写js
//获取宽高 var h = document.documentElement.clientHeight; var w = document.documentElement.clientWidth; //canvas对象 var canvas = document.getElementById("mycan"); //获取绘制的环境 var ctx = canvas.getContext("2d"); //设置画布宽高 canvas.width = w; canvas.height = h;
这时候在浏览器中查看,也是一片空白,然后我们在画布中加点自己想要的东西,
比如先画三条线
/* mw mh 和mx my是一样的 为什么要写2次, 主要是w,h 是宽高 xy 是坐标 所以写2个 做个区分 其实也没啥区别,只写一个也没关系, 至于为什么加1,主要是为了让边框显示出来不至于0,0坐标的方块left和top 没有框 * */ var mw = parseInt(w/4)+1; var mh = parseInt(h/5)+1; var mx = parseInt(w/4)+1; var my = parseInt(h/5)+1; function drawline(x,y){ //beginPath主要是为了重新绘制的时候不至于被上一个所影响或者,不被下一个所消除 ctx.beginPath(); //设置颜色 ctx.strokeStyle = 'black'; //开始划线 ctx.moveTo(x,y); ctx.lineTo(x,h-1); ctx.stroke(); } function setline(){ for(var i = 1;i <= 3; i++){ drawline(mw*i,1); } } setline();
然后看看效果:
线画好了,然后开始画框
//new一个数组 var list = new Array(); for(var i = 0; i < 6; i++) { //内部添加数组长度为2 1个是用于存储 x 值 另一个用于存储 颜色的true和flase var arr = new Array(2); //应该随机一个值 0-3 var n = Math.floor(Math.random() * 4); console.log("n",n); arr[0] = n; arr[1] = true; //刚开始的时候 如果y值 大于屏幕的高度,就将y值放到最上面去至于为什么是6 //因为高度是分成5分的 所以必须加1 才能保证方块沾满屏幕 if(my*i > h){ list[i] = new kuang(my*i - my*6, arr); }else{ list[i] = new kuang(my*i, arr); } } function drawmian(){ /* 没什么用这个canvas.width = canvas.width; 其实每次画布都是清空重画,每次设置画布的宽高的时候画布自动清空,所以先清空画布,在从新绘制 * */ canvas.width = canvas.width; //当然如果全是白色也太单调了,我选择加上一张背景图片 //创建 img对象 var Img=document.createElement('img'); //设置img的路径 Img.src='/uploadfile/2018/0726/20180726040245324.jpg'; //将图片绘制到画布上去 ctx.drawImage(Img,0,0,w,h); //因为画布清空了一次,所以需要将划线写到内部 setline(); for(var i = 0; i < list.length ;i++){ ctx.beginPath(); //设置颜色 if(list[i].arr[1]){ //绿色 不要吐槽我的审美,我毫无审美观,随便写的颜色 ctx.fillStyle = "rgba(155, 187, 89, 1)"; }else{ //灰色 ctx.fillStyle = "rgba(192,192,192, 1)"; } //画方块然后填充自己设置的颜色 ctx.fillRect(mw*list[i].arr[0] , list[i].y, mw, mh); ctx.strokeStyle = "white"; //话边框,边框颜色自己设置 ctx.strokeRect(mw*list[i].arr[0] , list[i].y, mw, mh); ctx.stroke(); ctx.closePath(); } } drawmian();
然后再看看效果:
解析一下ctx.fillRect(mw*list[i].arr[0] , list[i].y, mw, mh);
这个函数就是相当于设置 一个方块参数分别的 坐标x,y 和宽高w,h
然后设置x的坐标是 mw*先前在数组里面存的n值
y坐标就是这个当前的高度
然后设置方块的大小宽高,现在也就好理解为什么我要设置两次 mw,mh,mx和my了吧
然后是在让这个canvas动起来
//这个就是设置每次移动的大小,数字越大移动的越快 var add = 2; function ksgame() { //先画出来 drawmian(); //然后开始循环判断 for(var i = 0; i < list.length; i++) { list[i].y+=add; //每当方块过了屏幕的高度 if(list[i].y > h) { var n = Math.floor(Math.random() * 4); list[i].arr[0] = n; list[i].arr[1] = true; //放到最上面去 list[i].y -= mh * 6; } } //这个函数相当于setInterval ,而且比setInterval平滑很多, //不至于看起来像卡了一样,需要了解可以去百度一下 time = requestAnimationFrame(goGame); } //drawmian(); ksgame();
这个只有自己看去看效果了,只要画布动起来了 我们只需要加上一点逻辑判断就可以,修改一部分代码,这个游戏就算完成了
首先在上层添加3个参数
var score = 0; //分数 var time = null; //用于停止动画 var start = false; //开始按钮
修改一下drawmian 主要是下面添加一个分数和 开始的文本
function drawmian() { /* 没什么用这个canvas.width = canvas.width; 其实每次画布都是清空重画,每次设置画布的宽高的时候画布自动清空,所以先清空画布,在从新绘制 * */ canvas.width = canvas.width; //当然如果全是白色也太单调了,我选择加上一张背景图片 //创建 img对象 var Img = document.createElement('img'); //设置img的路径 Img.src = '/uploadfile/2018/0726/20180726040245324.jpg'; //将图片绘制到画布上去 ctx.drawImage(Img, 0, 0, w, h); //因为画布清空了一次,所以需要将划线写到内部 setline(); var tadd = parseInt(w/2); for(var i = 0; i < list.length; i++) { ctx.beginPath(); //设置颜色 if(list[i].arr[1]) { //绿色 不要吐槽我的审美,我毫无审美观,随便写的颜色 ctx.fillStyle = "rgba(155, 187, 89, 1)"; } else { //灰色 ctx.fillStyle = "rgba(192,192,192, 1)"; } //画方块然后填充自己设置的颜色 ctx.fillRect(mw * list[i].arr[0], list[i].y, mw, mh); ctx.strokeStyle = "white"; //话边框,边框颜色自己设置 ctx.strokeRect(mw * list[i].arr[0], list[i].y, mw, mh); ctx.stroke(); ctx.closePath(); } //显示分数 kais(tadd,50,score,"50","red"); //如果没有开始,设置开始(只是设置文字) if(!start){ var x1 = (mw*list[4].arr[0] + mw/2); var y1 = (list[4].y + mh/2); kais(x1,y1,"开始"); } }
然后再修改一下 ksgeme,添加了一个 没有点击的判断
function ksgame() { //先画出来 drawmian(); //然后开始循环判断 for(var i = 0; i < list.length; i++) { list[i].y += add; //每当方块过了屏幕的高度 if(list[i].y > h) { //添加一个判断,如果没有点击超过了 高度,停止动画,并显示 if(list[i].arr[1] == true){ list[i].y -= 20; drawmian(); window.cancelAnimationFrame(time); return; } var n = Math.floor(Math.random() * 4); list[i].arr[0] = n; list[i].arr[1] = true; //放到最上面去 list[i].y -= mh * 6; } } //这个函数相当于setInterval ,而且比setInterval平滑很多, //不至于看起来像卡了一样,需要了解可以去百度一下 time = requestAnimationFrame(ksgame); }
//用于给添加一个文字, /* x x坐标 y y坐标 text 文本内容 px 大小 color 颜色 至于其他的位置,我注释掉的可以自己去试下 * */ function kais(x,y,text,px,color){ ctx.beginPath(); if(px){ ctx.font = px + "px Georgia"; }else{ ctx.font = "30px Georgia"; } ctx.fillStyle = color color : "black"; //ctx.textAlign="start"; //ctx.textAlign="end"; //ctx.textAlign="left"; ctx.textAlign="center"; //ctx.textAlign="right"; // ctx.textBaseline ="top";//顶部对齐 // ctx.textBaseline ="hanging";//悬挂 // ctx.textBaseline ="middle";//中间对齐 // ctx.textBaseline ="bottom";//底部对齐 ctx.textBaseline ="alphabetic";//默认 ctx.fillText(text,x,y); ctx.stroke(); ctx.closePath(); }
然后添加一个点击事件,是鼠标按下事件
//添加一个点击事件,至于移动端的 触屏事件我懒得写了 canvas.addEventListener("mousedown", function(event) { event = event || window.event; //这是当前点击的位置 var x = event.clientX; var y = event.clientY; if(!start){ if(list[4].y < y && list[4].arr[0]*mw < x ){ ksgame(); start = !start; } } //循环判断点击的是那个方块 for(var i = 0; i < list.length; i++) { //先判断点击的是那一排,也就是高度的坐标 if(list[i].y < y && list[i].y + mh > y) { //然后再查看点击的是那一列,也就是宽度的坐标 var j = parseInt(x/mw); //j 就是点击的是哪一列 //然后再讲这个排的 随机数n 于j对比,如果相同,那么点击的就是对的 //否则就是点的空白区 if(list[i].arr[0] == j) { //点击后将true变为false 设置颜色,而且不让多次点击得分 if(list[i].arr[1] == true) { list[i].arr[1] = false; //这里是分数每次超过20,就让速度变快一点 if(score % 20 == 0){ add++; } //分数 score++; } } else { console.log("进入取消"); window.cancelAnimationFrame(time); drawmian(); return; } } } })
这样一个 游戏基本没啥问题了,如果想要完善一点,自己写个重新开始之类的,如果读懂了我写的代码(应该是比较好理解了,已经解析的这么细致了),在继续开发应该是很容易的,好了,谢谢大家!,不懂可以留言!