使用原生js編寫貪吃蛇小遊戲
貪吃蛇小遊戲大家都不陌生,基本上都玩過,而使用js,也能夠編寫出各種各樣的小遊戲,今天就寫一下貪吃蛇這個經典小遊戲
效果圖:
html程式碼
程式碼沒啥可說的,兩個下拉框分別對應著遊戲棋盤大小和貪吃的速度
css程式碼
原本還用彈性佈局將#box居中的,但截不了那麼長的圖,就省略了,如果感覺不好看,可以自己編寫樣式
下面是加上程式碼,提醒一句,js程式碼太多了(兩百多行),最好單獨寫一個檔案,這裡為了方便,就不更改了,一篇文章寫下來了
js程式碼
// 第一步寫的東西 把遊戲中的 一些公共的資料值 封裝在一個公共的物件裡
var Common = new function () {
this.width = 20; //x方向的格子數 預設是20 可以根據後面的程式中需要改變
this.height = 20;
// speed 速度
this.speed = 250; //這個值越小 蛇跑的越快
this.workThread = null;
}
// 對蛇的行走方向進行封裝
var Direction = new function () {
// 左鍵
this.LEFT = 37;
// 上鍵
this.UP = 38;
// 右鍵
this.RIGHT = 39;
// 下鍵
this.DOWN = 40;
}
// 把位置封裝為一個建構函式
var Position = function (x, y) {
this.X = 0;
this.Y = 0;
if (arguments.length >= 1) this.X = x;
if (arguments.length >= 2) this.Y = y;
}
// 食物的建構函式
function Food() {
// 食物的位置
this.pos = new Position(); //初始化 食物的位置 在0.0; 在後面的程式中要實現位置是隨機的
// 下面的是真正的實現創造食物,建立的過程中必須要考慮三個限制
// 食物的位置是隨機的
// 食物的位置不能出界
// 食物的位置不能在蛇的身上
this.Create = function (snakePos) { //蛇的身體佔據的位置引數的形式傳進來
// 建立食物的第一個步驟 消除上一個食物 消除上一個食物的背景顏色
document.getElementById('box_' + this.pos.X + '' + this.pos.Y).className = '';
var x = 0;
var y = 0;
var flag = false;
// 生成的食物不能在蛇的身上出現
do {
// 搞兩個隨機數座標值
x = Math.round(Math.random() * (Common.width - 1));
y = Math.round(Math.random() * (Common.height - 1));
// 把上面生成的隨機數排除出蛇的身體
if (snakePos instanceof Array) {
for (var i = 0; i < snakePos.length; i++) {
if (x == snakePos[i].X && y == snakePos[i].Y) {
flag = true;
break // 這裡結束的是for迴圈
}
}
}
} while (flag);
// 最後跳出了do while 迴圈得到的x y值就一定不是蛇身上的位置 座標 也是隨機的 也是不出界的
this.pos = new Position(x, y);
document.getElementById('box
}
}
// 定義蛇的建構函式
function Snake() {
// 判斷蛇動的過程中 還是剛剛動完
this.isDone = false;
// 預設蛇移動方向是右邊
this.dir = Direction.RIGHT;
// 預設蛇初始的情況 身體長度為1個格子 位置(0,0)
this.pos = new Array(new Position());
// 實現蛇的移動
this.Move = function () {
// 第一步擦屁股
document.getElementById('box' + this.pos[0].X + '_' + this.pos[0].Y).className = '';
// 第二步 除了蛇頭野外 每一個蛇的身體部分 向前蠕動一步
for (var i = 0; i < this.pos.length - 1; i++) {
console.log(this.pos);
this.pos[i].X = this.pos[i + 1].X;
this.pos[i].Y = this.pos[i + 1].Y;
}
var head = this.pos[this.pos.length - 1]
// 第三步重新給蛇整一個頭
switch (this.dir) {
case Direction.LEFT:
head.X--;
break;
case Direction.RIGHT:
head.X++;
break;
case Direction.UP:
head.Y--;
break;
case Direction.DOWN:
head.Y++;
break;
}
this.pos[this.pos.length - 1] = head;
// 畫蛇 如果蛇在上一步的移動中死掉了 就沒有畫的必要了
// 在畫蛇之前 判斷蛇死沒死
// 1.蛇跑出界 2.咬到自己
for (var i = 0; i < this.pos.length; i++) {
var idExits = false; //蛇有沒有 有沒有咬到自己的標記 true 表示咬到了
for (var j = i + 1; j < this.pos.length; j++) {
if (this.pos[i].X == this.pos[j].X && this.pos[i].Y == this.pos[j].Y) {
idExits = true;
break;
}
}
if (idExits) {
// game over 蛇咬到自己 遊戲結束
this.Over();
break;
}
// 再迴圈中 遊戲沒有結束 證明蛇沒有咬到自己
// 繼續判斷 蛇有沒有跑出界
var std = document.getElementById('box_' + this.pos[i].X + '_' + this.pos[i].Y);
if (std) {
// 表示蛇沒有出界
// 畫出蛇的身體
std.className = "snake";
} else {
// 蛇出界了
this.Over();
break
}
}
this.isDone = true;
}
// 此方法表示遊戲結束
this.Over = function () {
clearInterval(Common.workThread);
alert('遊戲結束')
}
this.isDone = true;
// 設定蛇新的方向
this.setDir = function (dir) {
switch (dir) {
case Direction.UP:
if (this.isDone && this.dir != Direction.DOWN) {
this.dir = Direction.UP;
this.isDone = false;
}
break;
case Direction.DOWN:
if (this.isDone && this.dir != Direction.UP) {
this.dir = Direction.DOWN;
this.isDone = false;
}
break;
case Direction.LEFT:
if (this.isDone && this.dir != Direction.RIGHT) {
this.dir = Direction.LEFT;
this.isDone = false;
}
break;
case Direction.RIGHT:
if (this.isDone && this.dir != Direction.LEFT) {
this.dir = Direction.RIGHT;
this.isDone = false;
}
break;
}
}
this.Eat = function (food) {
var head = this.pos[this.pos.length - 1];
var isEat = false; //false 表示蛇沒得吃 true 表示 蛇有的吃
switch (this.dir) {
case Direction.UP:
console.log(head.X);
console.log(food.pos);
if (head.X == food.pos.X && head.Y == food.pos.Y + 1) {
// console.log(000);
isEat = true;
}
break;
case Direction.RIGHT:
if (head.X == food.pos.X - 1 && head.Y == food.pos.Y) {
// console.log(000);
isEat = true;
console.log(true);
}
break;
case Direction.DOWN:
if (head.X == food.pos.X && head.Y == food.pos.Y - 1) {
// console.log(000);
isEat = true;
console.log(true);
}
break;
case Direction.LEFT:
if (head.X - 1 == food.pos.X && head.Y == food.pos.Y) {
// console.log(000);
isEat = true;
console.log(true);
}
break;
}
if (isEat) {
// 實現吃的動作
// console.log(0);
this.pos[this.pos.length] = new Position(food.pos.X, food.pos.Y)
food.Create(this.pos)
}
}
}
function init() {
var html = [];
html.push("");
for (var y = 0; y < Common.height; y++) {
html.push('')
for (var x = 0; x < Common.width; x++) {
html.push('<td id=box_' + x + '_' + y + '>');
}
html.push('')
}
html.push('
var tableStr = html.join('')
var panel = document.getElementById('panel');
panel.innerHTML = tableStr
}
// window.onload 函式在頁面以及頁面資源剛剛載入完成後立即執行的函式體
window.onload = function () {
// addEventListener() 方法用於向指定元素新增事件控制代碼。
// document.addEventListener('keydown', function (ev) {
// var evt = window.event || ev;
// })
// 初始化格子
init();
document.getElementById('btnSart').onclick = function () {
var snakePos = [new Position(0, 0)];
var food = new Food();
food.Create(snakePos);
var snake = new Snake();
Common.workThread = setInterval(function () {
snake.Eat(food);
snake.Move();
document.addEventListener('keydown', function (evt) {
var evnt = window.event || evt;
snake.setDir(evnt.keyCode);
}, false)
}, Common.speed)
}
document.getElementById('selSize').onchange = function () {
Common.width = this.value;
Common.height = this.value;
init()
}
document.getElementById('selSpeed').onchange = function () {
Common.speed = this.value;
init()
}
}