ES6 手写一个“辨色”小游戏
栏目: JavaScript · 发布时间: 7年前
内容简介:依稀记得几年前朋友圈流行的辨色小游戏,找出颜色不同的矩形。前些天突发奇想,打算自己手写一个类似的游戏,话不多说,先上Demo . --本实例基于 ES6 实现,并兼容 ie9及以上。
依稀记得几年前朋友圈流行的辨色小游戏,找出颜色不同的矩形。前些天突发奇想,打算自己手写一个类似的游戏,话不多说,先上Demo . -- 项目源码
本实例基于 ES6 实现,并兼容 ie9及以上。
2. 项目结构
index.html index.css index.js
本文主要讲述如何使用 js 实现功能,html css 不在此范围。直接上代码。
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="index.css">
<title>suporka color game</title>
</head>
<body>
<div class="container">
<div class="wgt-home" id="page-one">
<h1>辨色力测试</h1>
<p>找出所有色块里颜色不同的一个</p>
<a id="start" class="btn btn-primary btn-lg">开始挑战</a>
</div>
<header class="header">
<h1>辨色力测试</h1>
</header>
<aside class="wgt-score">
</aside>
<section id="screen" class="screen">
</section>
<footer>
<div> <a href="http://zxpsuper.github.io" style="color: #FAF8EF"> my blog</a></div>
©<a href="https://zxpsuper.github.io">Suporka</a>
©<a href="https://zxpsuper.github.io/Demo/advanced_front_end/">My book</a>
©<a href="https://github.com/zxpsuper">My Github</a>
</footer>
</div>
</body>
<!-- <script src="index.js"></script> -->
<script src="colorGame.js"></script>
<script>
// 事件兼容方法,兼容ie
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
window.onload = function () {
addEvent(document.querySelector('#start'), 'click', function() {
document.querySelector('#page-one').style.display = 'none'
new ColorGame({
time: 30
})
})
}
</script>
</html>
复制代码
/*index.css*/
body {
background-color: #FAF8EF;
}
footer {
display: block;
margin-top: 10px;
text-align: center;
}
h1 {
font-size: 2em;
margin: .67em 0;
}
a {
text-decoration: none;
}
footer a {
margin-right: 14px;
}
.container {
margin: auto;
padding: 0 10px;
max-width: 600px;
}
.wgt-home {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-top: 50px;
font-size: 20px;
background: #fc0;
text-align: center;
color: #fff;
}
.wgt-home p {
margin-top: 4em;
}
.btn {
display: inline-block;
margin-bottom: 0;
font-weight: 400;
text-align: center;
vertical-align: middle;
cursor: auto;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
-webkit-user-select: none;
user-select: none;
}
.btn-lg {
padding: 10px 16px;
font-size: 18px;
line-height: 1.33;
border-radius: 6px;
}
.btn-primary {
color: #fff;
background-color: #428bca;
border-color: #357ebd;
}
.wgt-home .btn {
margin-top: 4em;
width: 50%;
max-width: 300px;
}
.screen {
display: block;
margin-top: 10px;
padding: 1px;
}
.screen .block {
float: left;
box-sizing: border-box;
padding: 1px;
}
.screen .block .block-inner {
content: ' ';
display: block;
width: 100%;
padding-top: 100%;
border-radius: 2px;
-webkit-user-select: none;
user-select: none;
}
.result {
color: red;
text-align: center;
font-size: 20px;
cursor: pointer;
}
复制代码
// index.js
// es6 class
class ColorGame {
constructor() {
}
}
复制代码
3. 功能实现
一个游戏对象有其默认的配置,也可以由使用者单独设置,因此——
// index.js
class ColorGame {
constructor(userOption) {
this.option = {
time: 30, // 总时长
end: score => {
document.getElementById(
"screen"
).innerHTML = `<div class="result" style="width: 100%;">
<div class="block-inner" id="restart"> You score is ${score} <br/> click to start again</div>
</div>`;
addEvent(document.getElementById("restart"), "click", () => {
this.init();
});
} // 结束函数
}
this.init(userOption); // 初始化,合并用户配置
}
}
复制代码
此游戏中可以配置的为游戏总时长 time 以及结束方法 end()。
上述代码中游戏结束时显示用户得分,并且使其点击可以重新开始游戏,addEvent() 为兼容 ie 的事件监听方法,代码如下:
// 事件兼容方法
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
复制代码
init() 带参数时为初始化游戏,不带参数为游戏重新开始的功能。因此——
// index.js
class ColorGame {
constructor(userOption) {
// ...
}
init(userOption) {
this.step = 0; // 关卡
this.score = 0; // 得分
if (userOption) {
if (Object.assign) {
// 合并用户配置, es6写法
Object.assign(this.option, userOption);
} else {
// 兼容es6写法
extend(this.option, userOption, true);
}
}
// 倒计时赋值
this.time = this.option.time;
// 设置初始时间和分数
document.getElementsByClassName(
"wgt-score"
)[0].innerHTML = `得分:<span id="score">${this.score}</span>
时间:<span id="timer">${this.time}</span>`;
// 开始计时, es6 箭头函数
window.timer = setInterval(() => {
if (this.time === 0) {
// 如果时间为0,clearInterval并调用结束方法
clearInterval(window.timer);
this.option.end(this.score);
} else {
this.time--;
document.getElementById("timer").innerHTML = this.time;
}
}, 1000);
this.nextStep(); // 下一关
}
}
复制代码
其中extend() 为兼容性合并配置的写法,具体代码如下:
// 合并参数方法
function extend(o, n, override) {
for (var p in n) {
if (n.hasOwnProperty(p) && (!o.hasOwnProperty(p) || override))
o[p] = n[p];
}
}
复制代码
nextStep() 为此游戏的核心方法,下面将详细介绍。
// index.js
class ColorGame {
constructor(userOption) {
// ...
}
init(userOption) {
// ...
}
nextStep() {
}
}
复制代码
游戏主体为 n*n 的矩阵图形,并且每个小盒子的大小一致,只是其中有一块颜色与众不同,每个关卡的 一般颜色 也不相同,因此我们需要随机获取一个颜色,并且根据关卡级别的增加返回一个逐渐接近一般颜色的 特殊颜色 。
颜色由 RGB 三色构成,三色值越接近,则颜色显示越接近。随着等级的增加,两种颜色的三色值差无限接近与 0. 此时我想起了中学时代的反比例函数(无限接近于x轴), 本文用的是 100/step (随着step增大而减小).
/**
* 根据关卡等级返回相应的一般颜色和特殊颜色
* @param {number} step 关卡级别
*/
function getColor(step) {
// rgb 随机加减 random
let random = Math.floor(100/step);
// 获取随机一般颜色,拆分三色值
let color = randomColor(17, 255),
m = color.match(/[\da-z]{2}/g);
// 转化为 10 进制
for (let i = 0; i < m.length; i++) m[i] = parseInt(m[i], 16); //rgb
let specialColor =
getRandomColorNumber(m[0], random) +
getRandomColorNumber(m[1], random) +
getRandomColorNumber(m[2], random);
return [color, specialColor];
}
/**
* 获取随机颜色相近的 rgb 三色值
* @param {number} num 单色值
* @param {number} random 随机加减的数值
*/
function getRandomColorNumber(num, random) {
let temp = Math.floor(num + (Math.random() < 0.5 ? -1 : 1) * random);
if (temp > 255) {
return "ff";
} else if (temp > 16) {
return temp.toString(16);
} else if (temp > 0) {
return "0" + temp.toString(16);
} else {
return "00";
}
}
/**
* 随机颜色
* @param {number} min 最小值
* @param {number} max 最大值
*/
function randomColor(min, max) {
var r = randomNum(min, max).toString(16);
var g = randomNum(min, max).toString(16);
var b = randomNum(min, max).toString(16);
return r + g + b;
}
/**
* 随机数
* @param {number} min 最小值
* @param {number} max 最大值
*/
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
复制代码
讲完了基本的方法,接下讲述nextStep() 方法。
首先,矩阵必须要有最多的列数限制,太小不好操作,显示也不好看。
其次,确定每个关卡的列数 col,即可得知小盒子的总个数 col * col, 将每个盒子的 HTML 片段字符串存入长度为 col * col 的数组 arr 中,再随机修改其中一个的颜色赋值为特殊颜色,并给这个 div 一个特殊 id,且监听此 dom 元素的点击事件,若点击了,则进入下一个关卡。
// index.js
class ColorGame {
constructor(userOption) {
// ...
}
init(userOption) {
// ...
}
nextStep() {
// 记级
this.step++;
let col; // 列数
// 设置列数,最高不超过16
if (this.step < 6) {
col = this.step + 1;
} else if (this.step < 12) {
col = Math.floor(this.step / 2) * 2;
} else if (this.step < 18) {
col = Math.floor(this.step / 3) * 3;
} else {
col = 16;
}
// 小盒子宽度
let blockWidth = ((100 / col).toFixed(2) * 100 - 1) / 100;
// 随机盒子index
let randomBlock = Math.floor(col * col * Math.random());
// 解构赋值获取一般颜色和特殊颜色, es6 解构
let [normalColor, specialColor] = getColor(this.step);
// es6 模板字符串
let item = `<div class="block" style="width: ${blockWidth}%;">
<div class="block-inner" style="background-color: #${normalColor}"></div>
</div>`;
// 包含所有盒子的数组
let arr = [];
// 初始化数组
for (let i = 0; i < col * col; i++) arr.push(item);
// 修改随机盒子
arr[randomBlock] = `<div class="block" style="width: ${blockWidth}%;">
<div class="block-inner" style="background-color: #${specialColor}" id="special-block"></div>
</div>`;
// 修改页面 dom 元素
document.getElementById("screen").innerHTML = arr.join("");
// 监听特殊盒子点击事件
addEvent(document.getElementById("special-block"), "click", () => {
this.nextStep();
this.score++;
// 修改得分
document.getElementById("score").innerHTML = this.score;
});
}
}
复制代码
写到这里,请打开 index.html ,是不是实现了该有的功能?故事是不是就这么结束了?嗯,细心的你可能会发现,此游戏在 ie 中行不通,ie 不兼容 es6 语法。怎么办?
4. 兼容与拓展
为了兼容 ie , 我们需要把 es6 语法转化为 es5, 使用 babel 编译即可。
我们发现此 js 文件只可通过 script 标签引入,我想让它兼容 common.js 或者 require.js 的模块引入,该怎么做?
--UMD, 这里有篇文章讲述到 js 的模块化,里面有涉及 UMD, 有需要的同学可以看看——Javascript 模块化
下面具体讲述如何使用 webpack 实现上述需求:
// webpack.js
const path = require('path');
module.exports = {
entry: {
index: './index.js', //入口
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" },
]
},
plugins: [
new VueLoaderPlugin(),
],
output: {
path: path.resolve(__dirname, './'),
library: 'ColorGame',
libraryExport: "default",
libraryTarget: 'umd',
filename: 'colorGame.js',
},
};
复制代码
index.js 文件最后一行添加 export default ColorGame
执行命令 webpack --config ./webpack.js
index.html 引入生成的 colorGame.js
即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
How to Solve It
Zbigniew Michalewicz、David B. Fogel / Springer / 2004-03-01 / USD 59.95
This book is the only source that provides comprehensive, current, and detailed information on problem solving using modern heuristics. It covers classic methods of optimization, including dynamic pro......一起来看看 《How to Solve It》 这本书的介绍吧!