d3.js 制作簡單的貪吃蛇

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;//上右下左0123this._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: 0;margin: 0;
}
.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: 2;fill-opacity: 0.5;
}
.random {fill: #ff00ff;fill-opacity: 0.5;stroke: #ff00ff;stroke-width: 2;
}

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

轉載于:https://www.cnblogs.com/vadim-web/p/11496275.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248138.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248138.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248138.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

js高級第六天

Q課程回顧&#xff1a; ? 閉包&#xff1a;有權訪問另外一個函數的局部變量的函數&#xff0c;作用&#xff1a;延伸變量使用范圍 ? mdn&#xff0c;w3c function fn1 () {var n 3;return function () {console.log(n);} }? 遞歸&#xff1a;函數調用其本身 function f…

Chrome 75 lazy-loading

Chrome 75 & lazy-loading https://addyosmani.com/blog/lazy-loading/ https://chromestatus.com/feature/5645767347798016 Chrome 75 將默認啟用延遲加載功能 自 Chrome 75 起&#xff0c;將原生支持圖片的延遲加載&#xff0c;在代碼中編寫 <img loading"lazy&…

d3.js 實現煙花鮮果

今天在d3.js官網上看到了一個煙花的DEMO&#xff0c;是canvas制作的&#xff0c;于是我想用d3.js來實現它&#xff0c;js代碼只有幾行。好了廢話不多說&#xff0c;先上圖。 1 js 類 因為煙花要有下落的效果&#xff0c;所以里面用到了一些簡單的數學和物理知識來模擬重力&…

阿里Sentinel控制臺源碼修改-對接Apollo規則持久化

改造背景 前面我們講解了如何對接Apollo來持久化限流的規則&#xff0c;對接后可以直接通過Apollo的后臺進行規則的修改&#xff0c;推送到各個客戶端實時生效。 但還有一個問題就是Sentinel控制臺沒有對接Apollo&#xff0c;Sentinel控制臺本來就可以修改限流的規則&#xff0…

第八節:EF Core連接MySql和Sqlite數據庫

。。。 轉載于:https://www.cnblogs.com/yaopengfei/p/11507557.html

Flask--WebSocket

flask websocket websocket原理 Socket&#xff1a; FTP - 文件服務 Django Flask Http - TCP: 1.一次請求 一次響應 斷開 2.客戶端永遠處于主動狀態 3.服務器永遠處于被動狀態 4.Http無狀態 - 在服務器不保存客戶端的信息 5.服務器無法主動找到客戶端 1.輪詢 客戶端向服務器…

jQuery第一天

課程回顧&#xff1a; ? 正則&#xff1a;匹配字符組合模式; ? 創建&#xff1a;var reg1 new RegExp(/abc/); var reg2 /abc/; ? 測試&#xff1a;reg1.test(‘abc’); ? 特殊字符&#xff1a;元字符 ? 邊界符&#xff1a;^&#xff0c;$ ? 字符類&#xff1a;[…

Python學習(一)

一、版本&#xff1a; Python2.X /Python3.x 官方宣布2020 年 1 月 1 日&#xff0c; 停止 Python 2 的更新。 Python3.x不兼容Python2.x  二、安裝&#xff08;以mac 為例&#xff09; MAC 系統一般都自帶有 Python2.x版本 的環境&#xff0c;你也可以在鏈接 https://www.py…

jQuery—淘寶精品服飾案例

<body><div class"wrapper"><ul id"left"><li><a href"#">女靴</a></li><li><a href"#">雪地靴</a></li><li><a href"#">冬裙</a>&l…

Python機器學習實踐:決策樹判別汽車金融違約用戶

文章發布于公號【數智物語】 &#xff08;ID&#xff1a;decision_engine&#xff09;&#xff0c;關注公號不錯過每一篇干貨。 轉自 | 法納斯特&#xff08;公眾號ID:walker398&#xff09; 作者 | 小F 決策樹呈樹形結構&#xff0c;是一種基本的回歸和分類方法。 決策樹模型的…

Python學習(二)語言基礎

一、變量與類型 在程序設計中&#xff0c;變量是一種存儲數據的載體 整型&#xff1a;Python中可以處理任意大小的整數浮點型&#xff1a;浮點數也就是小數字符串型&#xff1a;字符串是以單引號或雙引號括起來的任意文本布爾型&#xff1a;布爾值只有True、False兩種值&#x…

jQuery—tab欄切換

<div class"tab"><div class"tab_list"><ul><li class"current">商品介紹</li><li>規格與包裝</li><li>售后保障</li><li>商品評價&#xff08;50000&#xff09;</li><l…

MongoDB分組查詢,聚合查詢,以及復雜查詢

準備數據 from pymongo import MongoClient import datetimeclientMongoClient(mongodb://localhost:27017) tableclient[db1][emp]l[ (張飛,male,18,20170301,,7300.33,401,1), #以下是教學部 (張云,male,78,20150302,teacher,1000000.31,401,1), (劉備,male,81,20130305,teac…

Python學習(三)基礎

一、函數與模塊 定義函數&#xff1a; 函數代碼塊以 def 關鍵詞開頭&#xff0c;后接函數標識符名稱和圓括號 ()。任何傳入參數和自變量必須放在圓括號中間&#xff0c;圓括號之間可以用于定義參數。函數的第一行語句可以選擇性地使用文檔字符串—用于存放函數說明。函數內容以…

操作系統原理之I/O設備管理(第六章上半部分)

一、I/O系統的組成 I/O系統不僅包括各種I/O設備&#xff0c;還包括與設備相連的設備控制器&#xff0c;有些系統還配備了專?? 于輸?/輸出控制的專?計算機&#xff0c;即通道。此外&#xff0c;I/O系統要通過總線與CPU、內存相連。 I/O系統的結構&#xff1a; I/O設備的分類…

js控制a標簽點擊事件 觸發下載

問題背景&#xff0c;動態獲取data把url賦值到a標簽的url中&#xff0c;讓a標簽自動下載 首先想到的應該是$(xxx).click(), 查資料明白&#xff1a;js中的$(...).click()事件只能觸發綁定的onClick方法&#xff0c;不能跳轉到href。 第二種方法&#xff1a;獲取到url之后locat…

操作系統原理之I/O設備管理(第六章下半部分)

五、I/O軟件原理 輸入輸出軟件的總體目標是將軟件組織成一種層次結構 低層軟件用來屏蔽硬件的具體細節高層軟件則主要是為用戶提供一個簡潔、規范的界面設備管理的4個層次&#xff1a; 用戶層軟件 -》向系統發出I/O請求&#xff0c;顯示I/O操作的結果&#xff0c;提供?戶與設備…

jQuery第二天

課程回顧&#xff1a; ? jQuery&#xff1a;JavaScript庫 ? 入口函數&#xff1a;$(function () {}); ? jQuery&#xff1a;jQuery對象&#xff0c;DOM對象 ? jQuery轉成DOM&#xff1a;$(‘元素’)[索引值] ? DOM轉成jQuery&#xff1a;$(DOM對象); ? 篩選方法&am…

切換Debug/Release編譯模式和Archive的作用

&#xfeff;在學這個之前&#xff0c;以為很難&#xff0c;也起不到什么作用&#xff0c;但是等真正運用到工程里面&#xff0c;才發現&#xff0c;這個能幫你省下很多工作量。 1&#xff0c;Debug和Release版本區別&#xff1f; 進行iOS開發&#xff0c;在Xcode調試程序時&am…

Linux 防火墻:Netfilter iptables

一、Netfilter 簡介 (1) Netfilter 是 Linux 內置的一種防火墻機制&#xff0c;我們一般也稱之為數據包過濾機制&#xff0c;而 iptables 只是操作 netfilter 的一個命令行工具(2) Netfilter 是 Linux CentOS 6 內置的防火墻機制&#xff0c;Firewall 是 Linux CentOS 7 內置的…