1 Star 0 Fork 0

haruhi/导航WebApp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
snake.html 12.78 KB
一键复制 编辑 原始数据 按行查看 历史
haruhi 提交于 2021-04-14 22:47 . add snake.html
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
<style>
@font-face {
font-family: "game";
src: url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;800&display=swap");
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
button:focus {
outline: 0;
}
html,
body {
height: 100%;
font-family: "Poppins", sans-serif;
color: #6e7888;
}
body {
background-color: #222738;
display: flex;
justify-content: center;
align-items: center;
color: #6e7888;
}
canvas {
background-color: #181825;
}
.container {
display: flex;
width: 100%;
height: 100%;
flex-flow: column wrap;
justify-content: center;
align-items: center;
}
#ui {
display: flex;
align-items: center;
font-size: 10px;
flex-flow: column;
margin-left: 10px;
}
h2 {
font-weight: 200;
transform: rotate(270deg);
}
#score {
margin-top: 20px;
font-size: 30px;
font-weight: 800;
}
.noselect {
user-select: none;
}
#replay {
font-size: 10px;
padding: 10px 20px;
background: #6e7888;
border: none;
color: #222738;
border-radius: 20px;
font-weight: 800;
transform: rotate(270deg);
cursor: pointer;
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#replay:hover {
background: #a6aab5;
background: #4cffd7;
transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);
}
#replay svg {
margin-right: 8px;
}
@media (max-width: 480px) {
#replay {
margin-bottom: 20px;
}
#replay,
h2 {
transform: rotate(0deg);
}
#ui {
flex-flow: row wrap;
margin-bottom: 20px;
}
#score {
margin-top: 0;
margin-left: 20px;
}
.container {
flex-flow: column wrap;
}
}
#credit {
width: 100%;
bottom: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 600;
color: inherit;
text-transform: uppercase;
padding-left: 35px;
}
#credit span {
font-size: 10px;
margin-left: 20px;
color: inherit;
letter-spacing: 4px;
}
#credit h1 {
font-size: 25px;
}
.wrapper {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
margin-bottom: 20px;
}
</style>
<div class="container noselect">
<div class="wrapper">
<button id="replay">
<i class="fas fa-play"></i>
RESTART
</button>
<div id="canvas">
</div>
<div id="ui">
<h2>SCORE
</h2>
<span id="score">00</span>
</div>
</div>
<div id="credit">
<h1>SNAKE</h1> <span>by Fariat</span>
</div>
</div>
<script>
let replay = document.querySelector("#replay");
let score = document.querySelector("#score");
let canvas = document.createElement("canvas");
document.querySelector("#canvas").appendChild(canvas);
let ctx = canvas ? canvas.getContext("2d") : null;
function cnvRes(width = 400, height = 400) {
ctx.canvas.width = width;
ctx.canvas.height = height;
}
let pubVars = {
snake: undefined,
snakeLength: undefined,
food: undefined,
currentHue: undefined,
segments: undefined,
historyPath: [],
gameOver: false,
tails: [],
update: undefined,
maxScore: window.localStorage.getItem("maxScore") || undefined,
effects: []
};
let helpers = {
collision(isSelfCol, snakeHead) {
if (isSelfCol) {
if (snakeHead.x == pubVars.food.x && snakeHead.y == pubVars.food.y) {
pubVars.food.respawnFood();
pubVars.tails.push(new Snake(pubVars.snakeLength - 1, "tail"));
pubVars.snakeLength++;
pubVars.snake.delay - 0.5;
}
} else {
for (let i = 1; i < pubVars.historyPath.length; i++) {
if (
snakeHead.x == pubVars.historyPath[i].x &&
snakeHead.y == pubVars.historyPath[i].y
) {
pubVars.gameOver = true;
}
}
}
},
randHue() {
return Math.floor(Math.random() * 360);
},
randCor(newCors) {
let randX =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.width) /
pubVars.segments;
let randY =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.height) /
pubVars.segments;
if (newCors) {
randX =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.width) /
pubVars.segments;
randY =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.height) /
pubVars.segments;
return {
randX,
randY
};
} else {
return {
randX,
randY
};
}
},
positionLogger(limit, loc) {
pubVars.historyPath.push(loc);
if (pubVars.historyPath.length > limit) {
pubVars.historyPath.shift();
}
},
hsl2rgb(hue, saturation, lightness) {
if (hue == undefined) {
return [0, 0, 0];
}
var chroma = (1 - Math.abs(2 * lightness - 1)) * saturation;
var huePrime = hue / 60;
var secondComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));
huePrime = Math.floor(huePrime);
var red;
var green;
var blue;
if (huePrime === 0) {
red = chroma;
green = secondComponent;
blue = 0;
} else if (huePrime === 1) {
red = secondComponent;
green = chroma;
blue = 0;
} else if (huePrime === 2) {
red = 0;
green = chroma;
blue = secondComponent;
} else if (huePrime === 3) {
red = 0;
green = secondComponent;
blue = chroma;
} else if (huePrime === 4) {
red = secondComponent;
green = 0;
blue = chroma;
} else if (huePrime === 5) {
red = chroma;
green = 0;
blue = secondComponent;
}
var lightnessAdjustment = lightness - chroma / 2;
red += lightnessAdjustment;
green += lightnessAdjustment;
blue += lightnessAdjustment;
return [
Math.round(red * 255),
Math.round(green * 255),
Math.round(blue * 255)
];
}
};
let input = {
left: false,
down: false,
right: true,
up: false,
listen() {
addEventListener(
"keydown",
(e) => {
switch (e.key) {
case "ArrowLeft":
if (!this.right) {
this.left = true;
this.down = false;
this.right = false;
this.up = false;
}
break;
case "ArrowRight":
if (!this.left) {
this.left = false;
this.down = false;
this.right = true;
this.up = false;
}
break;
case "ArrowUp":
if (!this.down) {
this.left = false;
this.down = false;
this.right = false;
this.up = true;
}
break;
case "ArrowDown":
if (!this.up) {
this.left = false;
this.down = true;
this.right = false;
this.up = false;
}
break;
default:
break;
}
},
false
);
}
};
class Snake {
constructor(i, type) {
this.x = type == "tail" ? pubVars.historyPath[i].x : 0;
this.y = type == "tail" ? pubVars.historyPath[i].y : 0;
this.type = type;
this.index = i;
this.delay = 10;
this.localDelay = 10;
this.size = ctx.canvas.width / pubVars.segments;
this.color = "white";
}
draw() {
ctx.lineWidth = 1;
ctx.fillStyle = this.color;
ctx.strokeStyle = "#181825";
ctx.strokeRect(this.x, this.y, this.size, this.size);
ctx.fillRect(this.x, this.y, this.size, this.size);
}
update() {
this.draw();
if (this.localDelay < 0) {
if (this.type == "tail") {
this.x = pubVars.historyPath[this.index].x;
this.y = pubVars.historyPath[this.index].y;
} else {
this.localDelay = this.delay;
if (input.left) {
this.x -= ctx.canvas.width / pubVars.segments;
}
if (input.right) {
this.x += ctx.canvas.width / pubVars.segments;
}
if (input.up) {
this.y -= ctx.canvas.width / pubVars.segments;
}
if (input.down) {
this.y += ctx.canvas.width / pubVars.segments;
}
if (this.x + ctx.canvas.width / pubVars.segments > ctx.canvas.width) {
this.x = 0;
}
if (this.y + ctx.canvas.height / pubVars.segments > ctx.canvas.width) {
this.y = 0;
}
if (this.y < 0) {
this.y = ctx.canvas.height - ctx.canvas.height / pubVars.segments;
}
if (this.x < 0) {
this.x = ctx.canvas.width - ctx.canvas.width / pubVars.segments;
}
helpers.collision(true, { ...this
});
helpers.collision(false, { ...this
});
helpers.positionLogger(pubVars.snakeLength, {
x: this.x,
y: this.y
});
}
} else {
this.localDelay--;
}
}
}
class Food extends Snake {
constructor() {
super();
this.x =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.width) /
pubVars.segments;
this.y =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.height) /
pubVars.segments;
this.color = pubVars.currentHue = `hsl(${helpers.randHue()}, 100%, 55%)`;
}
draw() {
ctx.save();
ctx.shadowColor = this.color;
ctx.shadowBlur = 50;
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.size, this.size);
ctx.restore();
}
respawnFood() {
pubVars.effects.push(
new Effect(
pubVars.food.x,
pubVars.food.y,
pubVars.currentHue,
pubVars.food.size,
pubVars.effects.length - 1
)
);
this.color = pubVars.currentHue = `hsl(${helpers.randHue()}, 100%, 50%)`;
this.x =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.width) /
pubVars.segments;
this.y =
(Math.floor(Math.random() * pubVars.segments) * ctx.canvas.height) /
pubVars.segments;
for (let i = 0; i < pubVars.historyPath.length; i++) {
if (
this.x == pubVars.historyPath[i].x &&
this.y == pubVars.historyPath[i].y
) {
this.respawnFood();
}
}
}
}
class Effect {
constructor(x, y, color, size, i) {
this.x = x;
this.y = y;
this.color = color;
this.size = size;
this.ttl = 0;
this.angle = 1;
this.index = i;
}
draw() {
let hsl = this.color
.split("")
.filter((l) => l.match(/[^hsl()$% ]/g))
.join("")
.split(",")
.map((n) => +n);
let [r, g, b] = helpers.hsl2rgb(hsl[0], hsl[1] / 100, hsl[2] / 100);
ctx.save();
ctx.translate(this.size / 2 + this.x, this.size / 2 + this.y);
ctx.rotate((this.angle * Math.PI) / 180.0);
ctx.lineWidth = 2;
ctx.strokeStyle = `rgb(${r},${g},${b},${1 / this.ttl})`;
ctx.strokeRect(-this.size / 2, -this.size / 2, this.size, this.size);
ctx.restore();
}
update() {
this.draw();
if (this.size > 0) {
this.y -= 1;
this.ttl >= 40 ?
pubVars.effects.splice(this.i + 1, 1) :
(this.ttl += 0.5);
this.angle += 7;
}
}
}
function scoreManager() {
let currentScore = pubVars.snakeLength - 1;
score.innerText = currentScore.toString();
}
function setup() {
// Intialization of the game.
cnvRes();
input.listen();
pubVars.segments = 32;
pubVars.snakeLength = 1;
pubVars.snake = new Snake("head");
pubVars.food = new Food();
loop();
}
function loop() {
pubVars.update = setInterval(() => {
if (!pubVars.gameOver) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
pubVars.snake.update();
if (pubVars.tails.length) {
for (let i = 0; i < pubVars.tails.length; i++) {
pubVars.tails[i].update();
}
}
pubVars.food.draw();
scoreManager();
for (let i = 0; i < pubVars.effects.length; i++) {
pubVars.effects[i].update();
}
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
gameOver();
}
}, 1000 / 60);
}
setup();
replay.addEventListener("click", () => {
reset();
});
function gameOver() {
pubVars.maxScore ? null : (pubVars.maxScore = pubVars.snakeLength - 1);
pubVars.snakeLength - 1 > pubVars.maxScore ?
(pubVars.maxScore = pubVars.snakeLength - 1) :
null;
window.localStorage.setItem("maxScore", pubVars.maxScore);
ctx.fillStyle = "#4cffd7";
ctx.textAlign = "center";
ctx.font = "bold 30px Poppins, sans-serif";
ctx.fillText("GAME OVER", ctx.canvas.width / 2, ctx.canvas.height / 2);
ctx.font = "15px Poppins, sans-serif";
ctx.fillText(
`SCORE ${pubVars.snakeLength - 1}`,
ctx.canvas.width / 2,
ctx.canvas.height / 2 + 60
);
ctx.fillText(
`MAXSCORE ${pubVars.maxScore}`,
ctx.canvas.width / 2,
ctx.canvas.height / 2 + 80
);
}
function reset() {
clearInterval(pubVars.update);
pubVars.snake = undefined;
pubVars.snakeLength = undefined;
pubVars.food = undefined;
pubVars.currentHue = undefined;
pubVars.segments = undefined;
pubVars.historyPath = [];
pubVars.gameOver = false;
pubVars.tails = [];
pubVars.update = undefined;
input.left = false;
input.down = false;
input.right = true;
input.up = false;
setup();
}
</script>
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/Lelouch-cc/haruhinav.git
git@gitee.com:Lelouch-cc/haruhinav.git
Lelouch-cc
haruhinav
导航WebApp
master

搜索帮助