有一天午睡突然突发奇想写个贪吃蛇玩一玩,一开始是想用c来写,然后弄一个8*8的点阵屏来玩的,但是又觉得太过于麻烦,所以就想着用最简单的方法来实现,所以就选择了JavaScript和HTML来实现,简述一下实现原理和提出代码
示例demo
snake-game
建议用手机打开,当然电脑也做了上下左右键盘控制,但是显示效果是为了手机显示适应的
效果图
实现原理
我觉得弄这个需要一点点的面相对象的思维就能简简单单的实现,首先我们需要有一个地图,所以就需要在这个地图上建立坐标系,不让我们的贪吃蛇抛出我们的坐标系,所以我就选择了二维数组来建立我们的坐标系,然后给每个坐标都设定一个值(我设定的就是x轴左边加y轴坐标的字符串),然后我们还需要一条贪吃蛇,和砖块,这里其实可以看成一部分,其实砖块就是我们坐标里面对应的值,而我们的贪吃蛇就是这个砖块的数组,所以我们可以理解成以下样子
地图:
一个二维数组
贪吃蛇
一个包含在地图里面的一维数组 ==> 多个砖块的拼接组成的一个数组
砖块
一个地图里面对应的准确的值
所以看到这里就很简单了,所谓的贪吃蛇其实就是在操作我们熟知的数组
上述的是我们游戏里面涉及到的元素,接下来我们讲讲我们涉及到的一些动作
蛇的行动范围
这个其实很简单,主要就是对蛇头做判断(数组第一个),只要蛇头不大于地图数组,游戏便可以继续下去
蛇的位移
其实蛇移动比较容易理解,例如 向下移动的时候y轴坐标+1,x轴坐标不动 其他方向同理,这样就能实现蛇的整体位移
看图比较容易看懂,就是蛇头以后得元素需要向之前的移动
蛇的成长
这里我们有使用数据结构中比较高级的插入方式,使用了我比较喜欢的渣渣方式,就是直接在数组的后面添加一个元素,实现蛇吃砖块长大的方式
砖块的随机生成
这里需要确保不会和我门蛇的数组位置冲突,需要做一些判断
蛇吃自己
这里只需要判断蛇里面没有重复的元素便可以了
视图渲染
每次蛇的移动完成以后都生成一个0和1组成的二维数组,遍历数组为HTML添加颜色就可以了
写在最后
其实实现起来远比我说明的这些要容易的多,毕竟我是一个喜欢讲废话的人,我个人觉得看了代码就知道这个东西确实是挺简单的
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="user-scalable=0">
<title>snake game</title>
<style>
* {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#score {
font-size: 300%;
display: flex;
align-items: center;
justify-content: center;
}
#handle {
display: flex;
flex-direction: column;
overflow: hidden;
font-size: 150%;
}
.game-row {
display: flex;
flex-direction: row;
}
.game-column {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
border: 1px #ce53d2 solid;
}
.game-column-snake {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
border: 1px #ce53d2 solid;
background: black;
}
.game-column-block {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
border: 1px #ce53d2 solid;
background: lightgreen;
}
.center {
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body id="body" style="display: flex;flex-direction: column">
<div id="score">分数</div>
<div id="game"></div>
<div id="handle">
<div class="center" style="height: 30%;" "handle('up')">上</div>
<div style="display: flex;flex-direction: row;height: 60%;">
<div class="center" "handle('left')">左</div>
<div class="center" "handle('start')">重新开始</div>
<div class="center" "handle('right')">右</div>
</div>
<div class="center" style="height: 30%;" "handle('down')">
下
</div>
</div>
</body>
<script>
var w = 0,//页面的宽度
h = 0,//页面的高度
block = '00',//砖块
snake = [],//蛇
map = [], //实际坐标系
xy = [],//渲染坐标系
hanld = 'right', //走动方向
mapSize = 10, //地图大小
score = 0,//游戏积分
level = 500,//游戏等级,默认是800毫秒走一次
endflag = false,
runStatus = 0;//自动运行标记
main();
/**
* 主方法
*/
function main() {
initShow();
initMap();
genSnake();
genBlock();
gen01();
next();
}
/**
* 初始化页面信息
*/
function initShow() {
//获取body的高度和宽度
var dom = document.getElementById("body");
w = dom.offsetWidth, h = dom.offsetHeight;
var h_w = h - w;
//自适应分数显示区域的高度
var score = document.getElementById('score');
score.style.height = parseInt(h_w) * 0.2 + 'px';
//自适应操作示区域的高度
var handle = document.getElementById('handle');
handle.style.height = parseInt(h_w) * 0.8 + 'px';
//自适应游戏区域的高度和宽度
var game = document.getElementById('game');
game.style.width = parseInt(w) + 'px';
game.style.height = parseInt(w) + 'px';
}
/**
*初始化地图
*/
function initMap() {
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = splitStr(y, x);
}
}
}
/**
* 生成随机数
* @param filter 需要过滤掉的数字
* @returns {number}
*/
function rand(filter) {
var rand = parseInt(Math.random() * 10);
if (rand == filter) {
rand(filter);
}
return rand;
}
/**
* 将坐标系转换成0/1的数组
*/
function gen01() {
var overflag = false;
for (var i = 0; i < mapSize; i++) {
xy[i] = [];
for (var j = 0; j < mapSize; j++) {
xy[i][j] = 0;
for (var s = 0; s < snake.length; s++) {
if (snake[s] == map[i][j]) {
xy[i][j] = 1;
break;
}
}
if (block == map[i][j]) {
xy[i][j] = 2;
}
if (snake[0] == map[i][j]) {
overflag = true;
}
}
}
if (!overflag) {
//游戏结束
showover();
} else {
if (!endflag) {
//生成进制以后就将数据渲染到HTML中去
show(xy);
}
}
}
/**
* 生成小蛇
*/
function genSnake() {
snake.push(splitStr(rand(), rand()));
}
/**
* 生成随机砖块
*/
function genBlock() {
block = splitStr(rand(), rand());
//确保生成砖块不会生成到和蛇一样的,否则就重新生成
for (var i in snake) {
if (block == snake[i]) {
genBlock();
}
}
}
/**
* 蛇向下一步移动
*/
function next() {
clearTimeout(runStatus);
changeSnakeHead();
eatself();
eatblock();
gen01();
runStatus = setTimeout(function () {
next();
}, level);
}
/**
* 判断蛇是否吃自己
*/
function eatself() {
for (var s = 0; s < snake.length; s++) {
if (s > 0 && snake[s] == snake[0]) {
showover();
break
}
}
}
/**
* 修改蛇的身体
*/
function changeSnakeHead() {
var tempa = snake[0];
for (var i = 0; i < snake.length; i++) {
var a = snake[i][0], b = snake[i][1];
if (i == 0) {
switch (hanld) {
case 'up':
snake[i] = splitStr(a, parseInt(b) - 1);
break;
case 'down':
snake[i] = splitStr(a, parseInt(b) + 1);
break;
case 'left':
snake[i] = splitStr(parseInt(a) - 1, b);
break;
case 'right':
snake[i] = splitStr(parseInt(a) + 1, b);
break;
}
} else {
var tempb = tempa;
tempa = snake[i];
snake[i] = tempb;
}
}
}
/**
* 吃砖块
*/
function eatblock() {
if (snake[0] == block) {
var tail = snake[snake.length - 1], temp = [], a = tail[0], b = tail[1];
switch (hanld) {
case 'up':
temp = splitStr(a, parseInt(b) + 1);
break;
case 'down':
temp = splitStr(a, parseInt(b) - 1);
break;
case 'left':
temp = splitStr(parseInt(a) + 1, b);
break;
case 'right':
temp = splitStr(parseInt(a) - 1, b);
break;
}
snake.push(temp);
addscore();
genBlock();
}
}
/**
* 修改蛇的身体结构
* @param x
* @param y
*/
function splitStr(x, y) {
return x + '' + y;
}
/**
* 键盘按下事件绑定
*/
document.onkeydown = function (e) {
var e = window.event || e;
switch (e.keyCode) {
case 37: //左
hanld = hanld != 'left' && hanld != 'right' ? 'left' : hanld;
break;
case 38: //上
hanld = hanld != 'up' && hanld != 'down' ? 'up' : hanld;
break;
case 39: //右
hanld = hanld != 'left' && hanld != 'right' ? 'right' : hanld;
break;
case 40: //下
hanld = hanld != 'up' && hanld != 'down' ? 'down' : hanld;
break;
}
}
/**
* 按键事件处理
*/
function handle(e) {
if (e == 'start') {
if (endflag) {
//只有输掉游戏才能重新开始游戏
window.location.reload();
}
} else {
if ((hanld == 'left' || hanld == 'right')) {
if (e == 'up' || e == 'down') {
hanld = e;
}
} else {
if (e == 'left' || e == 'right') {
hanld = e;
}
}
}
}
/**
* 添加游戏积分,目前的积分就是蛇的长度
*/
function addscore() {
var score = parseInt(snake.length) - 1;
//根据游戏得分修改游戏等级,一共分五个等级,
if (score > 20) {
level = 250;
} else if (score > 15) {
level = 300;
} else if (score > 10) {
level = 350;
} else if (score > 5) {
level = 400;
} else if (score > 1) {
level = 450;
} else {
level = level;
}
document.getElementById('score').innerHTML = '分数:' + score;
}
/**
* 将数据渲染在页面上去
* @param xy
*/
function show(xy) {
var html = '',
height = parseInt(w) / mapSize;
for (var i = 0; i < mapSize; i++) {
html += '<div class="game-row" style="height:' + height + 'px;">'
for (var j = 0; j < mapSize; j++) {
if (xy[i][j] == 1) {
html += '<div class="game-column-snake"></div>';
} else if (xy[i][j] == 2) {
html += '<div class="game-column-block"></div>';
} else {
html += '<div class="game-column"></div>';
}
}
html += '</div>';
}
document.getElementById('game').innerHTML = html;
}
/**
* 游戏结束
*/
function showover() {
document.getElementById('game').innerHTML = '<h1 align="center" style="font-size: 500%;color:red;">game over!</h1>';
endflag = true;
}
</script>
</html>