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. MySQL Schema与数据类型优化

    Schema与数据类型优化 选择优化的数据类型 1.更小的通常更好 更小的数据类型通常更快,因为它们占用更少的磁盘,内存和CPU缓存 2.简单就好 简单数据类型的操作通常需要更少的CPU周期.例如:整 ...

  2. JavaFX 选择文件 导入Excel文件并解析

    FXML 控制器 : @FXML public void selectExcel(MouseEvent event) { FileChooser fileChooser = new FileChoos ...

  3. Activiti6系列(1)- 核心数据库表及字段注释说明

    前言 本文是根据<疯狂工作流讲义-Activiti6.0>一书中提取过来的,有兴趣的可以去当当网买这本书,讲的很不错,最后还有实战案例. 虽然是提取过来的,但完全靠手打梳理,觉得有用的小伙 ...

  4. 转载 | embed用法(网站中视频、音频的添加)

    网站中添加视频: <embed src="http://player.video.qiyi.com/390cf6c74450e4c70b7bd2d883169914/0/0/w_19r ...

  5. IDEA+maven搭建scala开发环境(spark)(半转载)

    以下内容部分来自于https://zhuanlan.zhihu.com/p/23141509,我尝试了一遍,然后添加了一些图片.. 其实我觉得在IDEA中使用scala插件然后创建project的时候 ...

  6. intellIJ IDEA学习笔记

    如果你初次用idea,毫无目的的度娘如何使用IDEA     浪费的将会是大量的时间.为以表诚意, 上一套IDEA教学视频,以表我诚意.(下载地址:https://pan.baidu.com/s/1g ...

  7. CSV Data Set Config 拓展开发

    1.目的 在日常的性能测试项目中,经常会遇到参数化的问题,我们所熟知的LR工具对参数化支持非常友好,然而JMeter相对逊色一些.大家都知道在使用JMeter工具参数化时常用CSV Data Set ...

  8. Redis 学习笔记(篇九):主从复制

    Redis 中,可以通过执行 savleof 命令或者设置 slaveof 选项,让一个服务器去复制另一个服务器,我们称被复制的服务器为主服务器,而对主服务器进行复制的服务器则被称为从服务器. Red ...

  9. Homebrew 安装 Docker Desktop for Mac

    无意中发现Homebrew现在已经支持Docker Desktop for Mac了,因此特意把原来通过 https://docs.docker.com/docker-for-mac/install/ ...

  10. C++函数中,两个自动释放内存的动态内存申请类

    最近做一个事情,实现一个流程交互,其中主交互流程函数中,涉及较多的内存申请, 而健康的函数,都是在函数退出前将手动申请不再需要的内存释放掉, 使用很多方法,都避免不了较多的出错分支时,一堆的if fr ...