d3.js是一个不错的可视化框架,同时对于操作dom也是十分方便的。今天我们使用d3.js配合es6的类来制作一个童年小游戏–贪吃蛇。话不多说先上图片。

1. js snaker类

class Snaker {
constructor() {
this._size = 30;
this._len = 3;
this._width = 900;
this._height = 690;
this._rows = 23;
this._cols = 30;
this._colors = d3.scaleLinear().range(['#E75229','#FFBF35']);
this._svg = null;
this._currentArray = [[0,2],[0,1],[0,0]];
this._interval = null;
this._duration = 1000;
this._direction = 1;//上右下左0123
this._randomPosition = [0,6];
this.initSvg();
this.addKeyListener();
}
initSvg() {
this._svg = d3.select('.svg-container')
.append('svg')
.attr('width', this._width)
.attr('height', this._height)
this._svg.selectAll('line.rows')
.data(d3.range(this._rows))
.enter()
.append('line')
.attr('class', 'line rows')
.attr('x1', 0)
.attr('y1', d => d * this._size)
.attr('x2', this._width)
.attr('y2', d => d * this._size)
this._svg.selectAll('line.cols')
.data(d3.range(this._cols))
.enter()
.append('line')
.attr('class', 'line cols')
.attr('x1', d => d * this._size)
.attr('y1', 0)
.attr('x2', d => d * this._size)
.attr('y2', this._height)
}
addKeyListener() {
d3.select('body').on('keydown', () => {
switch (d3.event.keyCode) {
case 37:
this.rotate(3);
break;
case 38:
this.rotate(0);
break;
case 39:
this.rotate(1);
break;
case 40:
this.rotate(2);
break;
case 32:
console.log('空格');
break;
case 80:
console.log('暂停');
break;
default:
break;
}
})
}
rotate(num) {
if(num == this._direction) {
this.rotateMove();
} else if(num % 2 != this._direction % 2) {
this._direction = num;
this.rotateMove();
}
}
renderSnaker() {
this._svg.selectAll('rect.active').remove();
this._svg.selectAll('rect.active')
.data(this._currentArray)
.enter()
.append('rect')
.attr('class', 'active')
.attr('x', d => d[1] * this._size)
.attr('y', d => d[0] * this._size)
.attr('width', this._size)
.attr('height', this._size)
.attr('fill', (d,i) => this._colors(i / this._len))
.attr('stroke', (d,i) => this._colors(i / this._len))
}
canMove() {
//下一步没有触碰边缘
let noTouchBorder = true;
//下一步没有触碰自身
let noTouchSelf = true;
//新数组
let newArray = [];
//判断方向
switch(this._direction) {
case 0:
if(this._currentArray[0][0] == 0) {
noTouchBorder = false;
} else {
newArray = this._currentArray.map((c,i,arr) => {
if(i == 0) {
return [c[0] - 1, c[1]]
} else {
return arr[i - 1]
}
})
}
break;
case 1:
if(this._currentArray[0][1] == this._cols - 1) {
noTouchBorder = false;
} else {
newArray = this._currentArray.map((c,i,arr) => {
if(i == 0) {
return [c[0], c[1] + 1]
} else {
return arr[i - 1]
}
})
}
break;
case 2:
if(this._currentArray[0][0] == this._rows - 1) {
noTouchBorder = false;
} else {
newArray = this._currentArray.map((c,i,arr) => {
if(i == 0) {
return [c[0] + 1, c[1]]
} else {
return arr[i - 1]
}
})
}
break;
case 3:
if(this._currentArray[0][1] == 0) {
noTouchBorder = false;
} else {
newArray = this._currentArray.map((c,i,arr) => {
if(i == 0) {
return [c[0], c[1] - 1]
} else {
return arr[i - 1]
}
})
}
break;
}
//判断新数组第一个元素是否出现在后面其他元素中
for(var i=1; i<newArray.length; i++) {
if(newArray[0][0] == newArray[i][0] && newArray[0][1] == newArray[i][1]) {
noTouchSelf = false;
}
}
return noTouchBorder && noTouchSelf;
}
setScoreAndSpeed() {
d3.select('#score').html(this._len);
d3.select('#speed').html((this._duration * (1 - this._len / 1000) / 1000).toString().substr(0,8) + 's')
}
moveArray() {
if(this.canMove()) {
if(this._direction == 0) {
if(this._currentArray[0][0] - 1 == this._randomPosition[0] && this._currentArray[0][1] == this._randomPosition[1]) {
this._currentArray.unshift(this._randomPosition);
this._len ++;
this.setScoreAndSpeed();
this.removeRandomPosition();
this.randomPosition();
} else {
this._currentArray.unshift([this._currentArray[0][0] - 1,this._currentArray[0][1]])
this._currentArray.pop();
}
} else if(this._direction == 1) {
if(this._currentArray[0][0] == this._randomPosition[0] && this._currentArray[0][1] + 1 == this._randomPosition[1]) {
this._currentArray.unshift(this._randomPosition);
this._len ++;
this.setScoreAndSpeed();
this.removeRandomPosition();
this.randomPosition();
} else {
this._currentArray.unshift([this._currentArray[0][0],this._currentArray[0][1] + 1])
this._currentArray.pop();
}
} else if(this._direction == 2) {
if(this._currentArray[0][0] + 1 == this._randomPosition[0] && this._currentArray[0][1] == this._randomPosition[1]) {
this._currentArray.unshift(this._randomPosition);
this._len ++;
this.setScoreAndSpeed();
this.removeRandomPosition();
this.randomPosition();
} else {
this._currentArray.unshift([this._currentArray[0][0] + 1,this._currentArray[0][1]])
this._currentArray.pop();
}
} else if(this._direction == 3) {
if(this._currentArray[0][0] == this._randomPosition[0] && this._currentArray[0][1] - 1 == this._randomPosition[1]) {
this._currentArray.unshift(this._randomPosition);
this._len ++;
this.setScoreAndSpeed();
this.removeRandomPosition();
this.randomPosition();
} else {
this._currentArray.unshift([this._currentArray[0][0],this._currentArray[0][1] - 1])
this._currentArray.pop();
}
}
} else {
console.log('game over');
alert('game over')
}
}
removeRandomPosition() {
d3.selectAll('rect.random').remove();
}
randomPosition() {
let random = Math.floor(Math.random() * (this._cols * this._rows - this._len));
let temp = [];
for(var i=0; i<this._rows; i++) {
for(var j=0; j<this._cols; j++) {
temp.push([i,j])
}
}
let emptyArray = temp.filter(a => !this._currentArray.some(b => b[0] == a[0] && b[1] == a[1]));
this._randomPosition = emptyArray[random];
this._svg.append('rect')
.attr('class', 'random')
.attr('x', this._randomPosition[1] * this._size)
.attr('y', this._randomPosition[0] * this._size)
.attr('width', this._size)
.attr('height', this._size)
}
interval() {
this._interval = setInterval(() => {
this.moveArray();
this.renderSnaker();
}, this._duration * (1 - this._len / 1000))
}
//转弯附带移动一次
rotateMove() {
this.moveArray();
this.renderSnaker();
}
initData() {
this._currentArray = [[0,2],[0,1],[0,0]];
}
start() {
this.initData();
this.renderSnaker();
this.interval();
this.randomPosition();
this.setScoreAndSpeed();
}
}

2. css 代码

* {
padding:;
margin:;
}
.container {
width: 100vw;
height: 100vh;
}
.svg-container {
margin: 50px;
width: 900px;
height: 690px;
border: 3px double #666;
display: inline-block;
overflow: hidden;
}
aside {
width: 200px;
height: 300px;
display: inline-block;
vertical-align: top;
margin-top: 50px;
}
.line {
shape-rendering: crispEdges;
stroke: #bbbbbb;
}
.active {
stroke-width:;
fill-opacity: 0.5;
}
.random {
fill: #ff00ff;
fill-opacity: 0.5;
stroke: #ff00ff;
stroke-width:;
}

3. html代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$</title>
<link rel="stylesheet" type="text/css" href="css/base.css"/>
<script type="text/javascript" src="js/d3.v4.js"></script>
<script type="text/javascript" src="js/base.js"></script>
</head>
<body>
<div class="container">
<div class="svg-container"></div>
<aside>
<table>
<tr>
<td>当前分数:</td>
<td id="score"></td>
</tr>
<tr>
<td>当前速度:</td>
<td id="speed"></td>
</tr>
</table>
<button onclick="start()">开始游戏</button>
</aside>
</div>
<script>
var snaker = new Snaker();
function start() {
snaker.start();
} </script>
</body>
</html>

有想预览或者下载demo的朋友请移步至个人博客

原文地址 http://www.bettersmile.cn

d3.js 制作简单的贪吃蛇的更多相关文章

  1. d3.js 制作简单的俄罗斯方块

    d3.js是一个不错的可视化框架,同时对于操作dom也是十分方便的.今天我们使用d3.js配合es6的类来制作一个童年小游戏--俄罗斯方块.话不多说先上图片. 1. js tetris类 由于方法拆分 ...

  2. js编写简单的贪吃蛇游戏

    css代码 *{ margin:; padding:; } td{ width: 4px; height: 4px; background: #ccc; border: 2px solid #ccc; ...

  3. 使用JS制作小游戏贪吃蛇

    先看效果图: 过程如下: 1.首先创建一张画布地图<div class="map"> </div>: 2.创建食物的自调用函数 (function (){ ...

  4. C#简单实现贪吃蛇程序(LinQ + Entity)

    做梦想起来的C#简单实现贪吃蛇程序(LinQ + Entity) 最近一直在忙着单位核心开发组件的版本更新,前天加了一个通宵,昨天晚上却睡不着,脑子里面突然不知怎的一直在想贪吃蛇的实现方法.以往也有类 ...

  5. TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇

    TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...

  6. D3.js 制作中国地图 .net 公共基础类

    D3.js 制作中国地图 from:  http://d3.decembercafe.org/pages/map/index.html GeoJSON is a format for encoding ...

  7. Java一个简单的贪吃蛇

    Java一个简单的贪吃蛇 虽然GUI已经要淘汰了,但是手动写写界面还是有助于理解语法的,像构造函数 ,函数调用,内部类,继承,接口.有助于半初学者强化理解. 直接上代码 游戏主体类: package ...

  8. GUI简单实战——贪吃蛇

    将前面学到的GUI基础知识完成实战,完成一个简单的贪吃蛇项目 项目功能 用键盘上下左右实现贪吃蛇的自动移动 贪吃蛇吃到食物后,长度加一,分数加一 贪吃蛇吃到自己的身体,则游戏结束 按空格键实现游戏的暂 ...

  9. d3.js制作连线动画图和编辑器

    此文章为原创文章,原文地址:https://www.cnblogs.com/eagle1098/p/11431679.html 连线动画图 编辑器 效果如上图所示.本项目使用主要d3.jsv4制作,分 ...

随机推荐

  1. LR有的JMeter也有之三“集合点”

    继续上两篇的文章内容和思路进行.(文思如尿崩,谁与我争锋----韩寒)哈哈! 集合点:简单来理解一下,虽然我们的“性能测试”理解为“多用户并发测试”,但真正的并发是不存在的,为了更真实的实现并发这感念 ...

  2. MATLAB使用过程中遇到的问题(持续更新)

    note:如果对你有帮助,请点赞评论哟!!! 问题1:每次双击.m文件都会自动打开一个matlab程序 step1:下载这个文件 http://pan.baidu.com/s/1pL2ULOf ste ...

  3. 论文阅读 | Falcon: Balancing Interactive Latency and Resolution Sensitivity for Scalable Linked Visualizations

    作者: Dominik Moritz, Bill Howe, Jeffrey Heer 发表于CHI 2019, 三位作者都来自于University of Washington Interactiv ...

  4. opencv图像直方图均衡化及其原理

    直方图均衡化是什么有什么用 先说什么是直方图均衡化,通俗的说,以灰度图为例,原图的某一个像素为x,经过某个函数变为y.形成新的图.新的图的灰度值的分布是均匀的,这个过程就叫直方图均衡化. 图像直方图均 ...

  5. asp.net core 一个中小型项目实战的起手式——项目搭建与仓储模式下的持久层创建(1)

    常规的中小型项目搭建方式一般是三层架构加上mvc与webapi作为一个主要框架,再加上一些第三方库,例如orm框架(EF.SqlSugar.Dapper等),API文档工具(Swagger)这些的应用 ...

  6. 为什么unsigned (-1)表示无符号整数的最大值

    整数在计算机中的表示 在计算机中,整数采用补码表示.当前主流编译器中整型在内存中占用四个字节,共32位. 机器数:一个数在计算机中的二进制表示形式, 叫做这个数的机器数.机器数是带符号的,在计算机用一 ...

  7. gunicorn 基础配置使用

    flask 自带的 web 服务器稳定性较差,只能用于测试.最近做的 web 项目,每次启动,需要敲一堆参数文件,今天学习了官方文档里关于配置的说明,记录一下. 创建一个 gunicorn.conf ...

  8. PHP危险函数总结学习

    1.PHP中代码执行的危险函数 call_user_func() 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数. 传入call_user_func()的参数不能为引用传递 ...

  9. Visual Studio 2015&2017 key

    Visual Studio 2015 key Key : HMGNV-WCYXV-X7G9W-YCX63-B98R2 Visual Studio Enterprise 2015 Key :HM6NR- ...

  10. Python --深入浅出Apriori关联分析算法(二) Apriori关联规则实战

    上一篇我们讲了关联分析的几个概念,支持度,置信度,提升度.以及如何利用Apriori算法高效地根据物品的支持度找出所有物品的频繁项集. Python --深入浅出Apriori关联分析算法(一) 这次 ...