这玩意光修bug都花了三小时 最终还是做出来了
效果(WASD操控)
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇</title>
<link rel="stylesheet" href="./css/style.css">
<style>
body {
padding: 0;
margin: 0;
overflow: hidden;
}
.map {
position: relative;
background-color: #313131;
width: 100vw;
height: 100vh;
}
.map .snake,
.map .food {
position: absolute;
z-index: 1;
display: block;
width: 20px;
height: 20px;
background-color: red;
border-radius: 50%;
overflow: hidden;
transition: all 1s;
}
#start {
z-index: 10000;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 140px;
height: 40px;
background-color: #00AEEC;
border: none;
border-radius: 20px;
color: #eee;
position: absolute;
}
#start:active {
background-color: #00a1ec;
}
.snake:nth-child(2) {
z-index: 111;
transform: scale(1.5);
background-image: url(data:image/png;base64,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);
background-size: contain;
}
.sad {
background-image: url(data:image/png;base64,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) !important;
}
.map .food {
left: 30px;
transform: translate(50%, 50%);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAC/VBMVEUAAADdiyg6FlHpvX/jrWLtsVjuoT1tQhFuQhAAAAAKBQBzLZ/z0Jjup0fupEJwRhQAAAB6NqTyyov01aOGP7Q4FU+DPLBvRBJxSxt+Oa1pSR96Nal7NqgAAAAAAAAAAAAAAAAAAAB0MZ4GAwABAQCYXxd4MKbDh06KQr54MKGYT8PmrFLnnTz11qTyy4/vvnDxsGPwrF30tVbup06TSb32pT6FOrCOTXTtsWl6MKSNR6mJQrY9Gko9GktvRBGIQ6OOUFm3gC1/Oax+OauTWD95Nad5NKV3NKWERH63hUGUXDEAAABwLat2MqQAAACdZhzDhj12MqRyL58AAAD/xV7/wlr+vVP/u079mCWXWL3/4KCCPJz/4JnDf4f/wFf9qUb9pkH/rDP/qS39mir/6bP/5611LqBoJZBeHoj/zXv+u2v+t2b/vVD/uEn/rziwadeaUcX/78CTSr//7LyPRrn/6reJPrWKRrOZWLJ+N6r+5qn/4qmQS6iOSKd6NKb/4qT31qR4MKRqJ5L/0JBlJo7/24xrNIxZHIX/04D+xX5XHX7+wnj/yWX9tmL/vVX/ulT+rUr+sUH+rD78my7+pi3+oyr+myf8lCK8d+O2b92fV8icTcikYsKXTcKTTrqcXbiRUbiZV7eWUrabXLSSS7SGNrT/56+DP6+VU656MKqBPamKRKKHPKGHQZ94NZz30pttKJeYUpHGgoXHhX7/z3D9vG//yW72v272umP/xmH2t1/9slz1sFT+r1P+s0//sz/8oTb2nTb0lTX0ki/+ni79oCn8mSiybNqTQ8GQTLmJObb/9LX/87WXVLWINbX/5LGDOrF8M6+SUK2AMqz53ar32qr/6aeVTab/76P/2Z9oJp9xMZr/2Jj+0JdxMZf2z5b/3ZP/2ZL3zpJcIJH2yonJhYf+zIb+yYXFgYH1xoCDSoC8f3ija3X/z3T9vXP2vWn+wWT+ul71s1f9sVfNjlX1r07+tUT/tkP9qEP1o0D0mj72pj39qDj9ojL+pS37qU/iAAAAVHRSTlMADwQODvDwzsZIGg/w8PC2DP7w7dfXwryzrZuOfWNeVzMpJSQgDwn+/fnx8fHw8PDw8PDw7+7s6+jn5djV07+9vbyyno5sZltXVkFAPz09NycbFwv4u8FCAAACbElEQVQoz2KgCuCWcXJlgjADpSXd0WSDxApm5juDmUoix2fOlUaVlpw7a0Z+kQwTNze3WFH+jFlFbsiyviVN7bdPrtI00zKxFFxV3tIlaK2GJO2jUZne3nKv8cTs2ac2rMvI2FAmgizN4GFVuy6jK23p0nMAXU7vSo+usVdClvV3Md9Ye/FxRnpTU0v7rQvXNzp4Icl6qm+OjY3dtPlNW1vbq9dPN8XGvvjiGACTZRYuPHP6WkxMzJU5BQVzqm60dnRkZnZasMCkdQuLi8/fbW5uWFJWtqQhpvvd1qzsLANGhO7S0pTqm/VXF5WULFr/oDsrK7s32xAuzVOckrIsNbWqYeG8eWcftWZm9+7eu9cYIV26LLW6uj5q/fzIyIVPOjI/TEj40c8LkwaIhSelqj4qKirmPlC6YntPSEhoX1goQlov9c7zzmcPW18uBkrvCAkNjQsL70NIC0V1dm/d/XHL9sULFqzYFRoWlhOeG86HkG7u/TwhPr7nfUV5+aU9kw4cmJT7LRcuzai/LT4+PmHCzh0rli+v+XVk8uTkP/u/I6RZ3+5LSEjoD9lVU1m5+tCRycnHkvP2syGkt+zs39cXGveptq5u7aFpycciIhLzkKS3hYQAXZuzZ3VdI2DRh6dFREyfhiLdEweUDA//urYxLfpgxPTpEVOSEuHSqkYhIK9MzPsZnZYW/Tvp6NGkpCmJpqpQaS7t8IkTJ/1Njji8ZuXKNQeTpvybOnVqog4XOGEzBatISUjwi3NwsLPbiorasLNzcNiJ8/NLKQtA5JkEuFQUFfw4OeXlZGXl5Dk5vRUUlbkEmICylAEAdm70hcx7l6IAAAAASUVORK5CYII=);
background-size: contain;
}
</style>
</head>
<body>
<button id="start">开始游戏</button>
<div class="map">
<!-- <span class="snake"></span> -->
</div>
<script>
//随机工具类
var Tools = {
getRandom: function(min, max) {
//min和max都能取到
return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + min
}
};
</script>
<script>
//独立作用域
(() => {
//记录上次创建的食物
let elements = [];
// 食物对象
function Food(options) {
//防止传参为空
options = options || {};
this.x = options.x || 0;
this.y = options.y || 0;
this.width = options.width || 40;
this.height = options.height || 40;
this.color = options.color || 'transparent';
}
//渲染食物
Food.prototype.render = function(map) {
//删除之前创建的食物
remove();
//随机设置食物位置
this.x = Tools.getRandom(0, (map.offsetWidth / this.width - 1) * this.width);
this.y = Tools.getRandom(0, (map.offsetHeight / this.height - 1) * this.height);
//动态创建元素,我选择用span来显示食物
let span = document.createElement('span');
//设置样式s
span.style.left = this.x + 'px';
span.style.top = this.y + 'px';
span.style.backgroundColor = this.color;
span.classList.add('food');
map.appendChild(span);
//保存食物
elements.push(span);
};
//删除食物
function remove() {
while (elements.length > 0) {
elements[elements.length - 1].parentNode.removeChild(elements[elements.length - 1]);
elements.splice(elements.length - 1, 1);
}
}
//把构造函数添加到window对象下,外部就可以访问了
window.Food = Food;
})();
</script>
<script>
//蛇对象
(() => {
//记录上次创建的蛇
let elements = [];
function Snake(options) {
//防止传参为空
options = options || {};
//蛇节
this.width = options.width || 20;
this.height = options.height || 20;
//蛇的移动方向
this.direction = options.direction || 'right';
//蛇身
this.body = [{
x: 12,
y: 2,
color: 'transparent'
}, {
x: 11,
y: 2,
color: `rgba(${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},1)`
}, ];
};
//渲染
Snake.prototype.render = function(map) {
//删除之前创建的蛇
remove();
//渲染蛇节
for (let i = 0, len = this.body.length; i < len; i++) {
//蛇节
let obj = this.body[i];
//创建元素
let span = document.createElement('span');
//设置样式
span.style.width = this.width + 'px';
span.style.height = this.height + 'px';
//obj.x * this.width 表示x个蛇节宽度这么多的距离
span.style.left = (obj.x * this.width) + 'px';
span.style.top = (obj.y * this.height) + 'px';
span.style.backgroundColor = obj.color;
span.classList.add('snake');
map.appendChild(span);
elements.push(span);
}
};
//删除蛇方法
function remove() {
while (elements.length > 0) {
elements[elements.length - 1].parentNode.removeChild(elements[elements.length - 1]);
elements.splice(elements.length - 1, 1);
}
}
//蛇移动
Snake.prototype.move = function(food, map) {
//控制蛇的身体移动(当前蛇节到上一个蛇节的位置)
for (let i = this.body.length - 1; i > 0; i--) {
this.body[i].x = this.body[i - 1].x;
this.body[i].y = this.body[i - 1].y;
}
//控制蛇头的移动
//判断蛇移动的方向
let head = this.body[0];
switch (this.direction) {
case 'right':
head.x += 0.2;
break;
case 'left':
head.x -= 0.2;
break;
case 'up':
head.y -= 0.2;
break;
case 'down':
head.y += 0.2;
break;
}
//判断蛇头是否在食物的坐标范围内
let snakeX = (head.x * (this.width))
let snakeY = (head.y * (this.height));
let leftPaddingIsTrue = ((snakeX >= food.x) && (snakeX <= (food.x + food.width))) && ((snakeY >= food.y) && (snakeY <= (food.y + food.height)))
let rightPaddingIsTrue = ((snakeX + this.width / 2 >= food.x) && (snakeX + this.width / 2 <= (food.x + food.width))) && ((snakeY + this.height / 2 >= food.y) && (snakeY + this.height / 2 <= (food.y + food.height)))
if (leftPaddingIsTrue || rightPaddingIsTrue) {
//蛇加一节
//复制蛇的最后一节
let lastNode = this.body[this.body.length - 1];
for (let i = 0; i < 10; i++) {
this.body.push({
x: lastNode.x,
y: lastNode.y,
color: `rgba(${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},${Tools.getRandom(0,255)},.7)`
});
}
//随机在地图上增加食物
food.render(map);
}
}
//把构造函数添加到window对象下,外部就可以访问了
window.Snake = Snake;
})();
</script>
<script>
//主游戏对象
(() => {
var that;
//创建食物和蛇对象的构造函数
function Game(map) {
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
//开始游戏方法
Game.prototype.start = function() {
//渲染食物和蛇
this.food.render(this.map);
this.snake.render(this.map);
runSnake();
//开始游戏逻辑
//让蛇动起来
//通过键盘控制蛇移动的方向
//当蛇遇到食物 做相应的处理
//当蛇遇到边界游戏结束
};
//让蛇润起来
function runSnake() {
var timer = setInterval(function() {
//这里请注意this指向
that.snake.move(that.food, that.map);
that.snake.render(that.map);
//当蛇遇到边界游戏结束
//只需要判断蛇头的坐标即可
let headX = that.snake.body[0].x;
let headY = that.snake.body[0].y;
let maxX = Math.floor(that.map.offsetWidth / that.snake.width) - 0.5;
let maxY = Math.floor(that.map.offsetHeight / that.snake.height) - 0.5;
if (headX >= maxX || headY >= maxY) {
//设置异步,避免alert卡帧
setTimeout(() => {
// alert('你创到墙啦,游戏结束');
document.querySelector('.snake:nth-child(2)').classList.add('sad');
btn.style.display = 'block';
}, 100);
clearInterval(timer);
}
if (headX <= 0 || headY <= 0) {
setTimeout(() => {
// alert('你创到墙啦,游戏结束');
document.querySelector('.snake:nth-child(2)').classList.add('sad');
btn.style.display = 'block';
}, 100);
clearInterval(timer);
}
//判断是否吃到了自己
snakeBody = that.snake.body;
for (let i = 1; i < snakeBody.length; i++) {
if ((snakeBody[0].x == snakeBody[i].x) && (snakeBody[0].y == snakeBody[i].y)) {
setTimeout(() => {
// alert('你咬到自己啦,游戏结束');
document.querySelector('.snake:nth-child(2)').classList.add('sad');
}, 100);
//clearInterval(timer);
break;
}
}
}, 10);
}
//蛇控制
function keyControl() {
document.addEventListener('keyup', function(e) {
switch (e.code) {
case 'KeyD':
//蛇不能180度掉头
if (that.snake.direction != 'left') {
that.snake.direction = 'right';
}
break;
case 'KeyA':
if (that.snake.direction != 'right') {
that.snake.direction = 'left';
}
break;
case 'KeyS':
if (that.snake.direction != 'up') {
that.snake.direction = 'down';
}
break;
case 'KeyW':
if (that.snake.direction != 'down') {
that.snake.direction = 'up';
}
break;
}
}, false); //事件冒泡
}
keyControl();
//当蛇遇到食物 做相应的处理
window.Game = Game;
})();
</script>
<script>
var btn = document.querySelector('#start');
btn.addEventListener('click', function() {
this.style.display = 'none';
var map = document.querySelector('.map');
var game = new Game(map);
game.start();
})
</script>
</body>
</html>