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新增一列为主键

    mysql新增一列为主键 由于一次疏忽在建表的时候忘记加上主键了, 但是目前来说表里面又有数据了,所以不能删表重建,所以需要新加一列主键 然后我就新加一列,并且为auto_increment,然后设置 ...

  2. zookeeper基本知识入门(一)

    之前我们在搭建hadoop分布式环境的时候用到过Zookeeper注册hadoop服务.那么到底Zookeeper在分布式环境中发挥了什么作用呢,这次我们就来讨论这个问题. 在分布式系统中通常都会有多 ...

  3. java学习-NIO(四)Selector

    这一节我们将探索选择器(selectors).选择器提供选择执行已经就绪的任务的能力,这使得多元 I/O 成为可能.就像在第一章中描述的那样,就绪选择和多元执行使得单线程能够有效率地同时管理多个 I/ ...

  4. 【0805 | Day 8】Python进阶(二)

    列表类型内置方法 一.列表类型内置方法(list) 用途:多个爱好.多个武器.多种化妆品 定义:[ ]内可以有多个任意类型的值,逗号分隔元素 # my_boy_friend = list(['jaso ...

  5. Oracle - SPM固定执行计划(一)

    一.前言 生产中偶尔会碰到一些sql,有多种执行计划,其中部分情况是统计信息过旧造成的,重新收集下统计信息就行了.但是有些时候重新收集统计信息也解决不了问题,而开发又在嗷嗷叫,没时间让你去慢慢分析原因 ...

  6. 前端中的设计模式 JavaScript

    最近再准备秋招,然后顺便把过去空白的设计模式相关概念补一补,这些内容都是从<JavaScript设计模式与开发实践>一书中整理出来的 (1)单例模式 定义:保证一个类仅有一个实例,并提供一 ...

  7. 聊聊我在这家公司设计的SSO

    最近小明遇到一个需求:需要将几个独立的系统(子系统)汇总到一个集中的系统(父系统)当中,当用户在父系统登录过后,再点击这几个子系统,就可以免登录跳转到任意一个系统.当时一听,duang~duang~就 ...

  8. app发布当天,用户无法登录

    原因:当用户登录时候有商城用户的触发器存在,它会让商城用户也更新成登录状态. 由于用户量大,导致数据库锁死. 最后解决案:删掉触发器,在app的接口登录程序里,追加商城用户更新成登录的操作. 他案1: ...

  9. SecureCRT软件的个性化设置

    工欲善其事,必先利其器.如果我们能花点时间把每天工作都要用到的SecureCRT软件设置的舒服一些,日后工作起来也是会心情愉悦.事半功倍的. 1.日志文件设置 2.窗口配色和关键字高亮 3.效果展示 ...

  10. Spring学习之旅(十四)--缓存

    数据库的读写并发一直都是应用性能的瓶颈所在之一,针对改动频率很小的数据我们应该将他存放到缓存中,减少与数据库的交互. 启用对缓存的支持 Spring 对缓存的支持有两种方式: 注解驱动的缓存 XML ...