在线体验地址(电脑键盘控制):贪吃蛇游戏体验
更多html游戏源码可以看我的专栏:html游戏源码
文章末尾是该游戏的完整代码(基于html+css+js),没学过前端或者没有编辑器的朋友不要着急,只要有电脑就可以完整运行此项目。
步骤:首先在桌面新建一个文本文档,然后把完整代码复制进去,保存并关闭。接着把文件的后缀改为html,双击即可看到游戏界面。
不会修改文件后缀或者文件显示不了后缀的朋友可以看看教程:https://www.windowszj.com/news/4884.html
界面出现中文乱码的可以看看如何解决:https://zhuanlan.zhihu.com/p/149128500
基础设定:吃一个分数增加52,达到520分会弹出一个表白框。
分数达到520之后弹出表白框。(里面的文字可以更改)
如何修改文字:
代码复制过去后,键盘按住ctrl+f 搜索:爱你 应该就可以定位到文字了。
当然这个效果是最基础的,你们可以自己改进,比如分数达到520分就出现爱心,烟花等等。可以结合我之前的表白代码:html表白代码大全
完整源码:
DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>贪吃蛇TITLE>
<meta charset="utf-8" />
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<style type="text/css">
/*================================================
General
================================================*/
* {
box-sizing: border-box;
}
html,
body {
background-color: #000;
height: 100%;
}
body {
background: #222;
background: radial-gradient(#333, #111);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
color: #fff;
font: 100%/1.5 sans-serif;
overflow: hidden;
}
/*================================================
Score
================================================*/
.score {
color: rgba(255, 255, 255, 0.5);
font-size: 16px;
font-weight: bold;
padding-top: 5px;
text-align: center;
}
/*================================================
Stage
================================================*/
.stage {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
z-index: 2;
}
/*================================================
Tiles
================================================*/
.tile {
background: rgba(0, 0, 0, 0.15);
position: absolute;
transition-property: background, box-shadow, opacity, transform;
transform: translateZ(0);
transition-duration: 3000ms;
}
.tile:before {
bottom: 0;
content: "";
height: 0;
left: 0;
margin: auto;
opacity: 0;
position: absolute;
right: 0;
top: 0;
width: 0;
transition: opacity 300ms;
}
.tile.path:before {
opacity: 1;
}
.tile.up:before {
border-bottom: 4px inset rgba(255, 255, 255, 0.15);
border-left: 4px solid transparent;
border-right: 4px solid transparent;
}
.tile.down:before {
border-top: 4px inset rgba(255, 255, 255, 0.15);
border-left: 4px solid transparent;
border-right: 4px solid transparent;
}
.tile.left:before {
border-right: 4px inset rgba(255, 255, 255, 0.15);
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
}
.tile.right:before {
border-left: 4px inset rgba(255, 255, 255, 0.15);
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
}
@media (max-width: 900px), (max-height: 900px) {
.tile.up:before,
.tile.down:before,
.tile.left:before,
.tile.right:before {
border-width: 3px;
}
}
@media (max-width: 500px), (max-height: 500px) {
.tile.up:before,
.tile.down:before,
.tile.left:before,
.tile.right:before {
border-width: 2px;
}
}
.tile.pressed {
background: rgba(0, 0, 0, 0.3);
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6);
transition-duration: 0ms;
}
style>
head>
<body>
<div class="score">分数:0div>
<div class="stage">div>
<script type="text/javascript">
var score=0;
/*================================================
Polyfill
================================================*/
(function() {
"use strict";
/*================================================
Request Animation Frame
================================================*/
var lastTime = 0;
var vendors = ["webkit", "moz"];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + "RequestAnimationFrame"];
window.cancelAnimationFrame =
window[vendors[x] + "CancelAnimationFrame"] ||
window[vendors[x] + "CancelRequestAnimationFrame"];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
})();
/*================================================
DOM Manipulation
================================================*/
(function() {
"use strict";
function hasClass(elem, className) {
return new RegExp(" " + className + " ").test(" " + elem.className + " ");
}
function addClass(elem, className) {
if (!hasClass(elem, className)) {
elem.className += " " + className;
}
}
function removeClass(elem, className) {
var newClass = " " + elem.className.replace(/[\t\r\n]/g, " ") + " ";
if (hasClass(elem, className)) {
while (newClass.indexOf(" " + className + " ") >= 0) {
newClass = newClass.replace(" " + className + " ", " ");
}
elem.className = newClass.replace(/^\s+|\s+$/g, "");
}
}
function toggleClass(elem, className) {
var newClass = " " + elem.className.replace(/[\t\r\n]/g, " ") + " ";
if (hasClass(elem, className)) {
while (newClass.indexOf(" " + className + " ") >= 0) {
newClass = newClass.replace(" " + className + " ", " ");
}
elem.className = newClass.replace(/^\s+|\s+$/g, "");
} else {
elem.className += " " + className;
}
}
})();
/*================================================
Core
================================================*/
g = {};
(function() {
"use strict";
/*================================================
Math
================================================*/
g.m = Math;
g.mathProps = "E LN10 LN2 LOG2E LOG10E PI SQRT1_2 SQRT2 abs acos asin atan ceil cos exp floor log round sin sqrt tan atan2 pow max min".split(
" "
);
for (var i = 0; i < g.mathProps.length; i++) {
g[g.mathProps[i]] = g.m[g.mathProps[i]];
}
g.m.TWO_PI = g.m.PI * 2;
/*================================================
Miscellaneous
================================================*/
g.isset = function(prop) {
return typeof prop != "undefined";
};
g.log = function() {
if (g.isset(g.config) && g.config.debug && window.console) {
console.log(Array.prototype.slice.call(arguments));
}
};
})();
/*================================================
Group
================================================*/
(function() {
"use strict";
g.Group = function() {
this.collection = [];
this.length = 0;
};
g.Group.prototype.add = function(item) {
this.collection.push(item);
this.length++;
};
g.Group.prototype.remove = function(index) {
if (index < this.length) {
this.collection.splice(index, 1);
this.length--;
}
};
g.Group.prototype.empty = function() {
this.collection.length = 0;
this.length = 0;
};
g.Group.prototype.each = function(action, asc) {
var asc = asc || 0,
i;
if (asc) {
for (i = 0; i < this.length; i++) {
this.collection[i][action](i);
}
} else {
i = this.length;
while (i--) {
this.collection[i][action](i);
}
}
};
})();
/*================================================
Utilities
================================================*/
(function() {
"use strict";
g.util = {};
/*================================================
Random
================================================*/
g.util.rand = function(min, max) {
return g.m.random() * (max - min) + min;
};
g.util.randInt = function(min, max) {
return g.m.floor(g.m.random() * (max - min + 1)) + min;
};
})();
/*================================================
State
================================================*/
(function() {
"use strict";
g.states = {};
g.addState = function(state) {
g.states[state.name] = state;
};
g.setState = function(name) {
if (g.state) {
g.states[g.state].exit();
}
g.state = name;
g.states[g.state].init();
};
g.currentState = function() {
return g.states[g.state];
};
})();
/*================================================
Time
================================================*/
(function() {
"use strict";
g.Time = function() {
this.reset();
};
g.Time.prototype.reset = function() {
this.now = Date.now();
this.last = Date.now();
this.delta = 60;
this.ndelta = 1;
this.elapsed = 0;
this.nelapsed = 0;
this.tick = 0;
};
g.Time.prototype.update = function() {
this.now = Date.now();
this.delta = this.now - this.last;
this.ndelta = Math.min(Math.max(this.delta / (1000 / 60), 0.0001), 10);
this.elapsed += this.delta;
this.nelapsed += this.ndelta;
this.last = this.now;
this.tick++;
};
})();
/*================================================
Grid Entity
================================================*/
(function() {
"use strict";
g.Grid = function(cols, rows) {
this.cols = cols;
this.rows = rows;
this.tiles = [];
for (var x = 0; x < cols; x++) {
this.tiles[x] = [];
for (var y = 0; y < rows; y++) {
this.tiles[x].push("empty");
}
}
};
g.Grid.prototype.get = function(x, y) {
return this.tiles[x][y];
};
g.Grid.prototype.set = function(x, y, val) {
this.tiles[x][y] = val;
};
})();
/*================================================
Board Tile Entity
================================================*/
(function() {
"use strict";
g.BoardTile = function(opt) {
this.parentState = opt.parentState;
this.parentGroup = opt.parentGroup;
this.col = opt.col;
this.row = opt.row;
this.x = opt.x;
this.y = opt.y;
this.z = 0;
this.w = opt.w;
this.h = opt.h;
this.elem = document.createElement("div");
this.elem.style.position = "absolute";
this.elem.className = "tile";
this.parentState.stageElem.appendChild(this.elem);
this.classes = {
pressed: 0,
path: 0,
up: 0,
down: 0,
left: 0,
right: 0
};
this.updateDimensions();
};
g.BoardTile.prototype.update = function() {
for (var k in this.classes) {
if (this.classes[k]) {
this.classes[k]--;
}
}
if (
this.parentState.food.tile.col == this.col ||
this.parentState.food.tile.row == this.row
) {
this.classes.path = 1;
if (this.col < this.parentState.food.tile.col) {
this.classes.right = 1;
} else {
this.classes.right = 0;
}
if (this.col > this.parentState.food.tile.col) {
this.classes.left = 1;
} else {
this.classes.left = 0;
}
if (this.row > this.parentState.food.tile.row) {
this.classes.up = 1;
} else {
this.classes.up = 0;
}
if (this.row < this.parentState.food.tile.row) {
this.classes.down = 1;
} else {
this.classes.down = 0;
}
} else {
this.classes.path = 0;
}
if (this.parentState.food.eaten) {
this.classes.path = 0;
}
};
g.BoardTile.prototype.updateDimensions = function() {
this.x = this.col * this.parentState.tileWidth;
this.y = this.row * this.parentState.tileHeight;
this.w = this.parentState.tileWidth - this.parentState.spacing;
this.h = this.parentState.tileHeight - this.parentState.spacing;
this.elem.style.left = this.x + "px";
this.elem.style.top = this.y + "px";
this.elem.style.width = this.w + "px";
this.elem.style.height = this.h + "px";
};
g.BoardTile.prototype.render = function() {
var classString = "";
for (var k in this.classes) {
if (this.classes[k]) {
classString += k + " ";
}
}
this.elem.className = "tile " + classString;
};
})();
/*================================================
Snake Tile Entity
================================================*/
(function() {
"use strict";
g.SnakeTile = function(opt) {
this.parentState = opt.parentState;
this.parentGroup = opt.parentGroup;
this.col = opt.col;
this.row = opt.row;
this.x = opt.x;
this.y = opt.y;
this.w = opt.w;
this.h = opt.h;
this.color = null;
this.scale = 1;
this.rotation = 0;
this.blur = 0;
this.alpha = 1;
this.borderRadius = 0;
this.borderRadiusAmount = 0;
this.elem = document.createElement("div");
this.elem.style.position = "absolute";
this.parentState.stageElem.appendChild(this.elem);
};
g.SnakeTile.prototype.update = function(i) {
this.x = this.col * this.parentState.tileWidth;
this.y = this.row * this.parentState.tileHeight;
if (i == 0) {
this.color = "#fff";
this.blur =
this.parentState.dimAvg * 0.03 +
Math.sin(this.parentState.time.elapsed / 200) *
this.parentState.dimAvg *
0.015;
if (this.parentState.snake.dir == "n") {
this.borderRadius =
this.borderRadiusAmount + "% " + this.borderRadiusAmount + "% 0 0";
} else if (this.parentState.snake.dir == "s") {
this.borderRadius =
"0 0 " +
this.borderRadiusAmount +
"% " +
this.borderRadiusAmount +
"%";
} else if (this.parentState.snake.dir == "e") {
this.borderRadius =
"0 " +
this.borderRadiusAmount +
"% " +
this.borderRadiusAmount +
"% 0";
} else if (this.parentState.snake.dir == "w") {
this.borderRadius =
this.borderRadiusAmount + "% 0 0 " + this.borderRadiusAmount + "%";
}
} else {
this.color = "#fff";
this.blur = 0;
this.borderRadius = "0";
}
this.alpha = 1 - i / this.parentState.snake.tiles.length * 0.6;
this.rotation =
this.parentState.snake.justAteTick /
this.parentState.snake.justAteTickMax *
90;
this.scale =
1 +
this.parentState.snake.justAteTick /
this.parentState.snake.justAteTickMax *
1;
};
g.SnakeTile.prototype.updateDimensions = function() {
this.w = this.parentState.tileWidth - this.parentState.spacing;
this.h = this.parentState.tileHeight - this.parentState.spacing;
};
g.SnakeTile.prototype.render = function(i) {
this.elem.style.left = this.x + "px";
this.elem.style.top = this.y + "px";
this.elem.style.width = this.w + "px";
this.elem.style.height = this.h + "px";
this.elem.style.backgroundColor = "rgba(255, 255, 255, " + this.alpha + ")";
this.elem.style.boxShadow = "0 0 " + this.blur + "px #fff";
this.elem.style.borderRadius = this.borderRadius;
};
})();
/*================================================
Food Tile Entity
================================================*/
(function() {
"use strict";
g.FoodTile = function(opt) {
this.parentState = opt.parentState;
this.parentGroup = opt.parentGroup;
this.col = opt.col;
this.row = opt.row;
this.x = opt.x;
this.y = opt.y;
this.w = opt.w;
this.h = opt.h;
this.blur = 0;
this.scale = 1;
this.hue = 100;
this.opacity = 0;
this.elem = document.createElement("div");
this.elem.style.position = "absolute";
this.parentState.stageElem.appendChild(this.elem);
};
g.FoodTile.prototype.update = function() {
this.x = this.col * this.parentState.tileWidth;
this.y = this.row * this.parentState.tileHeight;
this.blur =
this.parentState.dimAvg * 0.03 +
Math.sin(this.parentState.time.elapsed / 200) *
this.parentState.dimAvg *
0.015;
this.scale = 0.8 + Math.sin(this.parentState.time.elapsed / 200) * 0.2;
if (this.parentState.food.birthTick || this.parentState.food.deathTick) {
if (this.parentState.food.birthTick) {
this.opacity = 1 - this.parentState.food.birthTick / 1 * 1;
} else {
this.opacity = this.parentState.food.deathTick / 1 * 1;
}
} else {
this.opacity = 1;
}
};
g.FoodTile.prototype.updateDimensions = function() {
this.w = this.parentState.tileWidth - this.parentState.spacing;
this.h = this.parentState.tileHeight - this.parentState.spacing;
};
g.FoodTile.prototype.render = function() {
this.elem.style.left = this.x + "px";
this.elem.style.top = this.y + "px";
this.elem.style.width = this.w + "px";
this.elem.style.height = this.h + "px";
this.elem.style["transform"] = "translateZ(0) scale(" + this.scale + ")";
this.elem.style.backgroundColor = "hsla(" + this.hue + ", 100%, 60%, 1)";
this.elem.style.boxShadow =
"0 0 " + this.blur + "px hsla(" + this.hue + ", 100%, 60%, 1)";
this.elem.style.opacity = this.opacity;
};
})();
/*================================================
Snake Entity
================================================*/
(function() {
"use strict";
g.Snake = function(opt) {
this.parentState = opt.parentState;
(this.dir = "e"), (this.currDir = this.dir);
this.tiles = [];
for (var i = 0; i < 5; i++) {
this.tiles.push(
new g.SnakeTile({
parentState: this.parentState,
parentGroup: this.tiles,
col: 8 - i,
row: 3,
x: (8 - i) * opt.parentState.tileWidth,
y: 3 * opt.parentState.tileHeight,
w: opt.parentState.tileWidth - opt.parentState.spacing,
h: opt.parentState.tileHeight - opt.parentState.spacing
})
);
}
this.last = 0;
this.updateTick = 10;
this.updateTickMax = this.updateTick;
this.updateTickLimit = 3;
this.updateTickChange = 0.2;
this.deathFlag = 0;
this.justAteTick = 0;
this.justAteTickMax = 1;
this.justAteTickChange = 0.05;
// sync data grid of the play state
var i = this.tiles.length;
while (i--) {
this.parentState.grid.set(this.tiles[i].col, this.tiles[i].row, "snake");
}
};
g.Snake.prototype.updateDimensions = function() {
var i = this.tiles.length;
while (i--) {
this.tiles[i].updateDimensions();
}
};
g.Snake.prototype.update = function() {
if (this.parentState.keys.up) {
if (
this.dir != "s" &&
this.dir != "n" &&
this.currDir != "s" &&
this.currDir != "n"
) {
this.dir = "n";
}
} else if (this.parentState.keys.down) {
if (
this.dir != "n" &&
this.dir != "s" &&
this.currDir != "n" &&
this.currDir != "s"
) {
this.dir = "s";
}
} else if (this.parentState.keys.right) {
if (
this.dir != "w" &&
this.dir != "e" &&
this.currDir != "w" &&
this.currDir != "e"
) {
this.dir = "e";
}
} else if (this.parentState.keys.left) {
if (
this.dir != "e" &&
this.dir != "w" &&
this.currDir != "e" &&
this.currDir != "w"
) {
this.dir = "w";
}
}
this.parentState.keys.up = 0;
this.parentState.keys.down = 0;
this.parentState.keys.right = 0;
this.parentState.keys.left = 0;
this.updateTick += this.parentState.time.ndelta;
if (this.updateTick >= this.updateTickMax) {
// reset the update timer to 0, or whatever leftover there is
this.updateTick = this.updateTick - this.updateTickMax;
// rotate snake block array
this.tiles.unshift(
new g.SnakeTile({
parentState: this.parentState,
parentGroup: this.tiles,
col: this.tiles[0].col,
row: this.tiles[0].row,
x: this.tiles[0].col * this.parentState.tileWidth,
y: this.tiles[0].row * this.parentState.tileHeight,
w: this.parentState.tileWidth - this.parentState.spacing,
h: this.parentState.tileHeight - this.parentState.spacing
})
);
this.last = this.tiles.pop();
this.parentState.stageElem.removeChild(this.last.elem);
this.parentState.boardTiles.collection[
this.last.col + this.last.row * this.parentState.cols
].classes.pressed = 2;
// sync data grid of the play state
var i = this.tiles.length;
while (i--) {
this.parentState.grid.set(
this.tiles[i].col,
this.tiles[i].row,
"snake"
);
}
this.parentState.grid.set(this.last.col, this.last.row, "empty");
// move the snake's head
if (this.dir == "n") {
this.currDir = "n";
this.tiles[0].row -= 1;
} else if (this.dir == "s") {
this.currDir = "s";
this.tiles[0].row += 1;
} else if (this.dir == "w") {
this.currDir = "w";
this.tiles[0].col -= 1;
} else if (this.dir == "e") {
this.currDir = "e";
this.tiles[0].col += 1;
}
// wrap walls
this.wallFlag = false;
if (this.tiles[0].col >= this.parentState.cols) {
this.tiles[0].col = 0;
this.wallFlag = true;
}
if (this.tiles[0].col < 0) {
this.tiles[0].col = this.parentState.cols - 1;
this.wallFlag = true;
}
if (this.tiles[0].row >= this.parentState.rows) {
this.tiles[0].row = 0;
this.wallFlag = true;
}
if (this.tiles[0].row < 0) {
this.tiles[0].row = this.parentState.rows - 1;
this.wallFlag = true;
}
// check death by eating self
if (
this.parentState.grid.get(this.tiles[0].col, this.tiles[0].row) ==
"snake"
) {
this.deathFlag = 1;
clearTimeout(this.foodCreateTimeout);
}
// check eating of food
if (
this.parentState.grid.get(this.tiles[0].col, this.tiles[0].row) ==
"food"
) {
this.tiles.push(
new g.SnakeTile({
parentState: this.parentState,
parentGroup: this.tiles,
col: this.last.col,
row: this.last.row,
x: this.last.col * this.parentState.tileWidth,
y: this.last.row * this.parentState.tileHeight,
w: this.parentState.tileWidth - this.parentState.spacing,
h: this.parentState.tileHeight - this.parentState.spacing
})
);
if (this.updateTickMax - this.updateTickChange > this.updateTickLimit) {
this.updateTickMax -= this.updateTickChange;
}
this.parentState.score=this.parentState.score+52;
this.parentState.scoreElem.innerHTML = "分数:"+this.parentState.score;
this.justAteTick = this.justAteTickMax;
score=this.parentState.score;
this.parentState.food.eaten = 1;
this.parentState.stageElem.removeChild(this.parentState.food.tile.elem);
if(score==520){
alert('永远爱你!');
}
var _this = this;
this.foodCreateTimeout = setTimeout(function() {
_this.parentState.food = new g.Food({
parentState: _this.parentState
});
}, 300);
}
// check death by eating self
if (this.deathFlag) {
g.setState("play");
}
}
// update individual snake tiles
var i = this.tiles.length;
while (i--) {
this.tiles[i].update(i);
}
if (this.justAteTick > 0) {
this.justAteTick -= this.justAteTickChange;
} else if (this.justAteTick < 0) {
this.justAteTick = 0;
}
};
g.Snake.prototype.render = function() {
// render individual snake tiles
var i = this.tiles.length;
while (i--) {
this.tiles[i].render(i);
}
};
})();
/*================================================
Food Entity
================================================*/
(function() {
"use strict";
g.Food = function(opt) {
this.parentState = opt.parentState;
this.tile = new g.FoodTile({
parentState: this.parentState,
col: 0,
row: 0,
x: 0,
y: 0,
w: opt.parentState.tileWidth - opt.parentState.spacing,
h: opt.parentState.tileHeight - opt.parentState.spacing
});
this.reset();
this.eaten = 0;
this.birthTick = 1;
this.deathTick = 0;
this.birthTickChange = 0.025;
this.deathTickChange = 0.05;
};
g.Food.prototype.reset = function() {
var empty = [];
for (var x = 0; x < this.parentState.cols; x++) {
for (var y = 0; y < this.parentState.rows; y++) {
var tile = this.parentState.grid.get(x, y);
if (tile == "empty") {
empty.push({ x: x, y: y });
}
}
}
var newTile = empty[g.util.randInt(0, empty.length - 1)];
this.tile.col = newTile.x;
this.tile.row = newTile.y;
};
g.Food.prototype.updateDimensions = function() {
this.tile.updateDimensions();
};
g.Food.prototype.update = function() {
// update food tile
this.tile.update();
if (this.birthTick > 0) {
this.birthTick -= this.birthTickChange;
} else if (this.birthTick < 0) {
this.birthTick = 0;
}
// sync data grid of the play state
this.parentState.grid.set(this.tile.col, this.tile.row, "food");
};
g.Food.prototype.render = function() {
this.tile.render();
};
})();
/*================================================
Play State
================================================*/
(function() {
"use strict";
function StatePlay() {
this.name = "play";
}
StatePlay.prototype.init = function() {
this.scoreElem = document.querySelector(".score");
this.stageElem = document.querySelector(".stage");
this.dimLong = 28;
this.dimShort = 16;
this.padding = 0.25;
this.boardTiles = new g.Group();
this.keys = {};
this.foodCreateTimeout = null;
this.score = 0;
this.scoreElem.innerHTML = '分数:'+this.score;
this.time = new g.Time();
this.getDimensions();
if (this.winWidth < this.winHeight) {
this.rows = this.dimLong;
this.cols = this.dimShort;
} else {
this.rows = this.dimShort;
this.cols = this.dimLong;
}
this.spacing = 1;
this.grid = new g.Grid(this.cols, this.rows);
this.resize();
this.createBoardTiles();
this.bindEvents();
this.snake = new g.Snake({
parentState: this
});
this.food = new g.Food({
parentState: this
});
};
StatePlay.prototype.getDimensions = function() {
this.winWidth = window.innerWidth;
this.winHeight = window.innerHeight;
this.activeWidth = this.winWidth - this.winWidth * this.padding;
this.activeHeight = this.winHeight - this.winHeight * this.padding;
};
StatePlay.prototype.resize = function() {
var _this = g.currentState();
_this.getDimensions();
_this.stageRatio = _this.rows / _this.cols;
if (_this.activeWidth > _this.activeHeight / _this.stageRatio) {
_this.stageHeight = _this.activeHeight;
_this.stageElem.style.height = _this.stageHeight + "px";
_this.stageWidth = Math.floor(_this.stageHeight / _this.stageRatio);
_this.stageElem.style.width = _this.stageWidth + "px";
} else {
_this.stageWidth = _this.activeWidth;
_this.stageElem.style.width = _this.stageWidth + "px";
_this.stageHeight = Math.floor(_this.stageWidth * _this.stageRatio);
_this.stageElem.style.height = _this.stageHeight + "px";
}
_this.tileWidth = ~~(_this.stageWidth / _this.cols);
_this.tileHeight = ~~(_this.stageHeight / _this.rows);
_this.dimAvg = (_this.activeWidth + _this.activeHeight) / 2;
_this.spacing = Math.max(1, ~~(_this.dimAvg * 0.0025));
_this.stageElem.style.marginTop =
-_this.stageElem.offsetHeight / 2 + _this.headerHeight / 2 + "px";
_this.boardTiles.each("updateDimensions");
_this.snake !== undefined && _this.snake.updateDimensions();
_this.food !== undefined && _this.food.updateDimensions();
};
StatePlay.prototype.createBoardTiles = function() {
for (var y = 0; y < this.rows; y++) {
for (var x = 0; x < this.cols; x++) {
this.boardTiles.add(
new g.BoardTile({
parentState: this,
parentGroup: this.boardTiles,
col: x,
row: y,
x: x * this.tileWidth,
y: y * this.tileHeight,
w: this.tileWidth - this.spacing,
h: this.tileHeight - this.spacing
})
);
}
}
};
StatePlay.prototype.upOn = function() {
g.currentState().keys.up = 1;
};
StatePlay.prototype.downOn = function() {
g.currentState().keys.down = 1;
};
StatePlay.prototype.rightOn = function() {
g.currentState().keys.right = 1;
};
StatePlay.prototype.leftOn = function() {
g.currentState().keys.left = 1;
};
StatePlay.prototype.upOff = function() {
g.currentState().keys.up = 0;
};
StatePlay.prototype.downOff = function() {
g.currentState().keys.down = 0;
};
StatePlay.prototype.rightOff = function() {
g.currentState().keys.right = 0;
};
StatePlay.prototype.leftOff = function() {
g.currentState().keys.left = 0;
};
StatePlay.prototype.keydown = function(e) {
e.preventDefault();
var e = e.keyCode ? e.keyCode : e.which,
_this = g.currentState();
if (e === 38 || e === 87) {
_this.upOn();
}
if (e === 39 || e === 68) {
_this.rightOn();
}
if (e === 40 || e === 83) {
_this.downOn();
}
if (e === 37 || e === 65) {
_this.leftOn();
}
};
StatePlay.prototype.bindEvents = function() {
var _this = g.currentState();
window.addEventListener("keydown", _this.keydown, false);
window.addEventListener("resize", _this.resize, false);
};
StatePlay.prototype.step = function() {
this.boardTiles.each("update");
this.boardTiles.each("render");
this.snake.update();
this.snake.render();
this.food.update();
this.food.render();
this.time.update();
};
StatePlay.prototype.exit = function() {
window.removeEventListener("keydown", this.keydown, false);
window.removeEventListener("resize", this.resize, false);
this.stageElem.innerHTML = "";
this.grid.tiles = null;
this.time = null;
};
g.addState(new StatePlay());
})();
/*================================================
Game
================================================*/
(function() {
"use strict";
g.config = {
title: "Snakely",
debug: window.location.hash == "#debug" ? 1 : 0,
state: "play"
};
g.setState(g.config.state);
g.time = new g.Time();
g.step = function() {
requestAnimationFrame(g.step);
g.states[g.state].step();
g.time.update();
};
window.addEventListener("load", g.step, false);
})();
script>
上下左右控制(键盘操作)<br>
可以撞墙,但不可以撞到自己<br>
body>
html>