前几天一个朋友问了我要作看你有多色这样的一个游戏须要怎么学,我也就本身写了一下。javascript
我有放在本身的我的网站上:查看游戏php
源代码也放在了github上:查看源码css
如今开始说明制过程:html
注:偷懒用了jquery,其实代码很少,彻底能够原生js,另外,因为此次我没有使用图片,因此img里面的内容是空的java
game -index.html -css -index.css -js -index.js -jqeuery.js -img
每一个页面使用一个div表示,进行到哪一步就将哪个页面div的display变为block,从而显示。jquery
index.html:css3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>找找看</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1">
<link href="./css/index.css" rel="stylesheet">
</head>
<body>
<!--加载页面-->
<div class="page loading" style="display: none">
<p>加载中...</p>
</div>
<!--开始游戏页面 -->
<div class="page index" style="display: none">
<h1>找找看</h1>
<p class="tip">
找出全部色块里颜色不一样的一个
</p>
<button class="start-game">
开始游戏
</button>
</div>
<!--游戏中-->
<div class="page room" style="display: block;">
<div class="top">
<span class="score">得分:0</span>
<span class="time">60</span>
<span class="btn btn-pause">暂停</span>
</div>
<div id="box"></div>
</div>
<!--暂停-->
<div class="page pause">
<h1>游戏暂停</h1>
<button class="continue">
继续游戏
</button>
</div>
<!--游戏结束-->
<div class="page over">
<h1>游戏结束</h1>
<p class="result">
总分:0
</p>
<button class="restart">
从新开始
</button>
</div>
<script src="./js/jquery-1.7.1.min.js"></script>
<script src="./js/index.js"></script>
</body>
</html>
index.cssgit
/* 重置样式 */
html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
table{border-collapse:collapse;border-spacing:0;}
caption,th{text-align:left;font-weight:normal;}
html,body,fieldset,img,iframe,abbr{border:0;}
i,cite,em,var,address,dfn{font-style:normal;}
[hidefocus],summary{outline:0;}
li{list-style:none;}
h1,h2,h3,h4,h5,h6,small{font-size:100%;}
sup,sub{font-size:83%;}
pre,code,kbd,samp{font-family:inherit;}
q:before,q:after{content:none;}
textarea{overflow:auto;resize:none;}
label,summary{cursor:default;}
a,button{cursor:pointer;}
h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:normal;}
del,ins,u,s,a,a:hover{text-decoration:none;}
body,textarea,input,button,select,keygen,legend{font:16px/1 "Microsoft Yahei", Arial, Helvetica, Sans-Serif,\5b8b\4f53;color:#333;outline:0;}
a,a:hover{color:#444;}
button{padding:0;margin:0;border:0;background-color:#fff;}
html, body { height: 100%; width: 100%; overflow: hidden;}
body { background-color: rgb(18, 149, 73);}
.page { display: none; position: relative; height: 100%; max-width: 600px; margin: 0 auto; color: #fff; text-align: center; }
.loading { display: block;}
.loading p { position: absolute; top: 50%; left: 50%; width: 200px; height: 30px; margin-left: -100px; margin-top: -15px; line-height: 30px; font-size: 26px; }
.index h1 { font-size: 30px; padding: 30px 0; }
.index p { height: 40px; line-height: 40px; font-size: 20px; color: #adffe0; text-align: center;}
.index button, .pause button, .over button{ display: block; position: absolute; bottom: 100px; left: 50%; height: 50px; width: 220px; margin-left: -110px; border-radius: 7px; line-height: 50px; box-shadow: 0 5px #da9622; color: inherit; cursor: pointer; font-weight: 700; font-size: 20px; background: #fcad26; }
#box { position: absolute; top: 50%; left: 50%; width: 500px; height: 500px; margin-left: -260px; margin-top: -260px; border-radius: 10px; padding: 10px; background-color: #ddd; }
@media only screen and (max-width: 500px) and (min-width: 414px) {
#box { width: 380px; height: 380px; margin-left: -200px; margin-top: -200px; }
}
@media only screen and (max-width: 414px) and (min-width: 375px) {
#box { width: 340px; height: 340px; border-radius: 8px; margin-left: -180px; margin-top: -180px; }
}
@media only screen and (max-width: 375px) {
#box { width: 300px; height: 300px; border-radius: 5px; margin-left: -160px; margin-top: -160px; }
}
#box span { display: block; float: left; border-radius: 10px; cursor: pointer; border: 5px solid #ddd; position: relative; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
#box.lv2 span { width: 50%; height: 50%; }
#box.lv3 span { width: 33.3333%; height: 33.3333%; }
#box.lv4 span { width: 25%; height: 25%; }
#box.lv5 span { width: 20%; height: 20%; }
#box.lv6 span { width: 16.666%; height: 16.666%; }
#box.lv7 span { width: 14.285%; height: 14.285%; }
.score { position: absolute; top: 10px; left: 5px; color: #adffe0; }
.time { position: absolute; top: 5px; left: 50%; display: block; color: #fff; width: 50px; margin-left: -25px; height: 24px; line-height: 24px; border-radius: 10px; text-align: center; font-size: 20px; font-weight: 700; background-color: rgb(117, 214, 171); }
.btn-pause{ display: block; position: absolute; top: 5px; right: 5px; height: 24px; width: 60px; border-radius: 7px; line-height: 24px; box-shadow: 0 4px #da9622; color: inherit; cursor: pointer; font-weight: 500; font-size: 16px; background: #fcad26; }
.pause h1, .over h1{ height: 150px; line-height: 150px; font-size: 30px; }
.over p { font-size: 26px; }
index.jsgithub
var game = {};
//缓存
game.pages = $('.page');
game.startBtn = $('.start-game').eq(0);
game.pauseBtn = $('.btn-pause').eq(0);
game.continueBtn = $('.continue').eq(0);
game.restartBtn = $('.restart').eq(0);
game.blockBox = $('#box');
game.scoreBox = $('.score').eq(0);
game.timeBox = $('.time').eq(0);
game.resultBox = $('.result').eq(0);
game.eventType = document.ontouchstart ? 'touchstart' : 'click';
game.imgUrls = [];
game.time = 60;
game.score = 0;
game.level = 0;
game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7];
game.colorDiff = [115, 100, 100, 85, 85, 85, 70, 70, 70, 70, 55, 55, 55, 55, 55, 40, 40, 40, 40, 40, 40, 25, 25, 25, 25, 25, 25, 25, 10, 10, 10, 10, 10, 10, 10, 10];
game.diffIndex = 0;
//加载游戏
game.loading = function () {
var imgCounts = this.imgUrls.length;
if ( imgCounts == 0) {
this.switchPage(1);
this.initEvent();
} else {
var num = 0,
self = this;
function count () {
num++;
if ( num == imgCounts ) {
self.switchPage(1);
self.initEvent();
}
}
for ( var i = 0; i < imgCounts; i++ ) {
var img = new Image();
img.onload = count;
img.src = this.imgUrls[i];
}
}
};
//初始化事件
game.initEvent = function () {
this.startBtn.on(this.eventType, this.start.bind(this));
this.restartBtn.on(this.eventType, this.start.bind(this));
this.blockBox.on(this.eventType, this.clickBlock.bind(this));
this.pauseBtn.on(this.eventType, this.pause.bind(this));
this.continueBtn.on(this.eventType, this.continue.bind(this));
};
//点击方块事件
game.clickBlock = function ( event ) {
if ( event.target.tagName.toLowerCase() === 'span' ) {
//选对了
if ( $(event.target).index() == this.diffIndex ) {
this.level++;
this.score++;
this.render();
} else {
this.over()
}
}
};
//开始游戏
game.start = function () {
this.switchPage(2);
this.render();
this.timeCount();
};
//游戏界面渲染
game.render = function () {
//获取有n*n
var num = this.levelMap[this.level] ? this.levelMap[this.level] : this.levelMap[this.levelMap.length - 1],
colorDiff = this.colorDiff[this.level] ? this.colorDiff[this.level] : this.colorDiff[this.colorDiff.length - 1],
color = [],
lvColor = [];
//分数
this.scoreBox.html('得分:' + this.score);
//时间
this.timeBox.html(this.time);
//给box添加类名
this.blockBox[0].className = 'lv' + num;
//获得不一样块的index
this.diffIndex = Math.floor(Math.random() * num * num);
//获取颜色
color = this.getColor(257 - colorDiff);
lvColor = this.getLvColor(color[0], colorDiff);
//添加block
var str = '';
num *= num;
for ( var i = 0; i < num; i++ ) {
if ( i == this.diffIndex ) {
str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
} else {
str += '<span style="background-color: ' + color[1] + ';"></span>';
}
};
this.blockBox.html(str);
};
//获得随机颜色
game.getColor = function (max) {
var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
return [t, "rgb(" + t.join(",") + ")"];
};
//获得不一样的颜色
game.getLvColor = function (color, diff) {
var r = [];
r[0] = color[0] + diff;
r[1] = color[1] + diff;
r[2] = color[2] + diff;
return [r, "rgb(" + r.join(",") + ")"];
};
//游戏结束处理
game.over = function () {
this.switchPage(4);
this.resultBox.html('总分:' + this.score);
clearInterval(this.timer);
this.time = 60;
this.score = 0;
this.level = 0;
};
//游戏暂停处理
game.pause = function () {
clearInterval(this.timer);
this.switchPage(3);
};
//继续游戏
game.continue = function () {
this.switchPage(2);
this.timeCount();
};
//计时器
game.timeCount = function () {
var self = this;
game.timer = setInterval(function(){
self.time--;
self.timeBox.html(self.time);
if ( self.time == 0 ) {
self.over.call(self);
}
}, 1000)
};
//换页
game.switchPage = function ( index ) {
this.pages.css('display', 'none');
this.pages.eq(index).css('display', 'block');
};
//游戏入口,触发加载
game.loading();
你们能够看到js代码,全部的变量和函数都添加到了game={}这个对象上,以防发生全局污染。web
有游戏加载这个步骤的主要目的是在游戏加载资源的时候让用户知道具体的加载过程,省得加载过慢时用户离开页面。
代码为:
...
game.imgUrls = [];
...
//加载游戏
game.loading = function () {
var imgCounts = this.imgUrls.length;
if ( imgCounts == 0) {
this.switchPage(1);
this.initEvent();
} else {
var num = 0,
self = this;
function count () {
num++;
if ( num == imgCounts ) {
self.switchPage(1);
self.initEvent();
}
}
for ( var i = 0; i < imgCounts; i++ ) {
var img = new Image();
img.onload = count;
img.src = this.imgUrls[i];
}
}
};
这段代码并不难理解,game.imgUrls为存放图片url的数组,游戏加载的时候经过获取到这个数组的长度,判断是否进行图片加载。
若是不须要加载就切换到开始游戏的界面,而且添加事件处理。
其中,this.switchPage函数的代码为:
...
game.pages = $('.page');
...
//换页
game.switchPage = function ( index ) {
this.pages.css('display', 'none');
this.pages.eq(index).css('display', 'block');
};
当加载图片存在时,即imgUrls不为空数组,那么开始加载图片
var num = 0,
self = this;
function count () {
num++;
if ( num == imgCounts ) {
self.switchPage(1);
self.initEvent();
}
}
for ( var i = 0; i < imgCounts; i++ ) {
var img = new Image();
img.onload = count;
img.src = this.imgUrls[i];
}
代码中,循环遍历了imgUrls,将src赋给一个img对象,而后onload(加载完成)就将计数+1,当计数和图片数量一致时说明所有加载完成,而后就换页和添加事件。
这个界面主要功能是显示提示信息,和点击开始游戏按钮时开始游戏。
添加事件都放在game.initEvent函数中
...
game.startBtn = $('.start-game').eq(0);
...
game.eventType = document.ontouchstart ? 'touchstart' : 'click';
...
//初始化事件
game.initEvent = function () {
...
this.startBtn.on(this.eventType, this.start.bind(this));
...
};
给图中的“开始游戏”按钮绑定了touchstart(click)事件,处理为game.start()——开始游戏
游戏元素不多,有4个:得分、时间、暂停按钮、装方块的盒子。
思路为:
当游戏开始时,等级默认为0,等级为0的方块为 2 x 2 放置,其余等级n x n 由 levelMap肯定,当level超过数组长度时,取7.
game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7];
而后生成对应数字的方块html,放进装方块的盒子,同时给每一个方块生成颜色,其中一个不一样,当点击方块时判断是否选到不一样,选对则晋级,选错则游戏结束。
开始讲解代码:
game.time = 60; //游戏时间
game.score = 0; //得分
game.level = 0; //等级
game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7]; // n x n 的方块
game.colorDiff = [115, 100, 100, 85, 85, 85, 70, 70, 70, 70, 55, 55, 55, 55, 55, 40, 40, 40, 40, 40, 40, 25, 25, 25, 25, 25, 25, 25, 10, 10, 10, 10, 10, 10, 10, 10]; // 色差,等级越高,色差越小
game.diffIndex = 0; //不一样颜色方块的index
...
//开始游戏(点击开始游戏就触发这个函数)
game.start = function () {
this.switchPage(2); //换页到游戏界面
this.render(); //render函数处理游戏界面渲染,主要包括生成方块,颜色等等
this.timeCount(); //开启计时器
};
//游戏界面渲染
game.render = function () {
/** * num 为n * n 的方块中的n,由等级决定,等级超过数组最大就取最后一个 * colorDiff 为色差,由等级决定,等级超过数组最大就取最后一个 */
var num = this.levelMap[this.level] ?
this.levelMap[this.level] :
this.levelMap[this.levelMap.length - 1],
colorDiff = this.colorDiff[this.level] ?
this.colorDiff[this.level] :
this.colorDiff[this.colorDiff.length - 1],
color = [],
lvColor = [];
//显示分数
this.scoreBox.html('得分:' + this.score);
//显示时间
this.timeBox.html(this.time);
//给box添加类名(主要是css须要,不一样数量的方块宽高应该不同,好比 2 * 2,每一个方块为50%)
this.blockBox[0].className = 'lv' + num;
//获得不一样颜色块的index
this.diffIndex = Math.floor(Math.random() * num * num);
//获取颜色
color = this.getColor(257 - colorDiff);
lvColor = this.getLvColor(color[0], colorDiff);
//添加block
var str = '';
num *= num;
for ( var i = 0; i < num; i++ ) {
if ( i == this.diffIndex ) {
str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
} else {
str += '<span style="background-color: ' + color[1] + ';"></span>';
}
};
this.blockBox.html(str);
};
//获得随机颜色
game.getColor = function (max) {
var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
return [t, "rgb(" + t.join(",") + ")"];
};
//获得不一样的颜色
game.getLvColor = function (color, diff) {
var r = [];
r[0] = color[0] + diff;
r[1] = color[1] + diff;
r[2] = color[2] + diff;
return [r, "rgb(" + r.join(",") + ")"];
};
思路不难,先知道方块是n×n的布局,而后在 n×n个方块中随机生成一个不一样的方块,记录在diffIndex这个变量里。
这里说一下Math.randon()是生成[0,1)的函数,可能等于0,不会等于1,若是是想生成n之内的一个整数(不包括n),写为:
Math.floor(Math.randon() * n)
Math.floor()表示向下取整,即舍去小数位。
而后生成随机颜色,全部方块共有两种颜色,一个方块不一样,其余相同。
//获得随机颜色
game.getColor = function (max) {
var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
return [t, "rgb(" + t.join(",") + ")"];
};
这个函数返回一个数组,array(0)也是一个数组,保存了rgb的值,array(1)为字符串,型如:”rgb(0,0,0)”。
render函数中是下面这样的,缘由为另外一个颜色是这个颜色加上色差获得,这样保证最大不超过256
color = this.getColor(257 - colorDiff);
另外一个颜色:
//获得不一样的颜色
game.getLvColor = function (color, diff) {
var r = [];
r[0] = color[0] + diff;
r[1] = color[1] + diff;
r[2] = color[2] + diff;
return [r, "rgb(" + r.join(",") + ")"];
};
获得了两种颜色,就能够给方块添加:
//获取颜色
color = this.getColor(257 - colorDiff);
lvColor = this.getLvColor(color[0], colorDiff);
//添加block
var str = '';
num *= num;
for ( var i = 0; i < num; i++ ) {
if ( i == this.diffIndex ) {
str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
} else {
str += '<span style="background-color: ' + color[1] + ';"></span>';
}
};
this.blockBox.html(str);
方块生成后,天然想到点击方块要判断是否正确,这里使用事件委托的方式,将点击事件绑定在方块盒子上:
this.blockBox.on(this.eventType, this.clickBlock.bind(this));
//点击方块事件
game.clickBlock = function ( event ) {
if ( event.target.tagName.toLowerCase() === 'span' ) {
//选对了
if ( $(event.target).index() == this.diffIndex ) {
this.level++;
this.score++;
this.render();
} else {
this.over()
}
}
};
代码结构一眼看去就了解什么意思了,先判断点的是否是方块,若是是,获得方块的index,而后和diffIndex进行对比,看是否选对。
选对了就加level,加分数,从新渲染游戏界面
选错了就执行over()函数,游戏结束。
讲一下游戏开始后执行的定时器函数:
//计时器
game.timeCount = function () {
var self = this;
game.timer = setInterval(function(){
self.time--;
self.timeBox.html(self.time);
if ( self.time == 0 ) {
self.over.call(self);
}
}, 1000)
};
判断是否时间到达0,是就执行over函数,否就继续执行,减时间并显示。
在游戏界面中还有一个暂停按钮:
this.pauseBtn.on(this.eventType, this.pause.bind(this));
//游戏暂停处理
game.pause = function () {
clearInterval(this.timer);
this.switchPage(3);
};
很简单,只是关闭定时器,而后换页就行了
继续游戏的按钮绑定continue函数
this.continueBtn.on(this.eventType, this.continue.bind(this));
//继续游戏
game.continue = function () {
this.switchPage(2);
this.timeCount();
};
换页,再开启定时器就好了
须要作的事情有:
一、显示得分
二、初始化游戏参数:score、level等等
三、点击从新开始,从新开始游戏
//游戏结束处理
game.over = function () {
this.switchPage(4);
this.resultBox.html('总分:' + this.score);
clearInterval(this.timer);
this.time = 60;
this.score = 0;
this.level = 0;
};
this.restartBtn.on(this.eventType, this.start.bind(this));
到此游戏讲解完毕,再补充点css中用得比较多的东西:
一、让width,height已知水平,垂直都居中显示:
div-parent { position: relative; }
div { position: absolute; top: 50%; left: 50%; width: 300px; height: 200px; margin-left: -150px; margin-top: -100px; }
width和height未知的话,垂直居中须要用到css3的知识。
二、再来一个n*n方块的css,这里用2*2做为例子:
.lv1 span { height: 50%; width: 50%; }
/* span做为一个方块 */
span { display: block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; /* box-sizing IE8+支持 */ float: left; position: relative; border: 5px solid #ddd; border-radius: 10px; cursor: pointer; }
box-sizing改变盒模型:
border-box:width = border + padding + 内容(IE6及之前浏览器默认)
content-box: width = 内容的宽度(现代浏览器默认)