原生js寫一個貪吃蛇小遊戲

寫一個貪吃蛇小遊戲

上下左右鍵盤移動貪吃蛇吃葡萄
結果 gif 圖 ,吃了5個葡萄,遊戲結束時左上角爲總得分。
在這裏插入圖片描述
界面和css代碼這裏就不加贅述了,主要貼js代碼(加了註釋):

var config = {
	width: 20,   //一個格子的寬度
	height: 20,   //一個格子的高度
	tr: 30,   //行數
	td: 30    //列數
}
var snake = null, //Snake的實例
    food = null,  //Food的實例
    game = null;  //遊戲的實例

//我們把蛇移動的整個區域設置成一個具有30列30行的網格座標
//方塊(格子)座標位置
/**
0,0   (0,0)
20,0  (1,0)
40,0  (2,0)
*/
function Square(x, y, className) {
	this.x = x*config.width;
	this.y = y*config.height;
	this.className = className;
	this.contentDom = document.createElement('div');//該位置的方塊對應的DOM元素
	this.contentDom.className = this.className;
	this.parent = document.getElementsByClassName("innerSnake")[0];

}
Square.prototype.create = function() { //創建方塊並添加到頁面
	this.contentDom.style.position = 'absolute';
	this.contentDom.style.width = config.width + 'px';
	this.contentDom.style.height = config.height + 'px';
	this.contentDom.style.left = this.x + 'px';
	this.contentDom.style.top = this.y + 'px';

	this.parent.appendChild(this.contentDom);
};
Square.prototype.remove = function() { //移除方塊
	this.parent.removeChild(this.contentDom);
};

//蛇
function Snake() {
	this.head = null; //蛇頭
	this.tail = null; //蛇尾
	this.pos = []; //二維數組,存儲蛇身上每個節點(方塊)
	this.directionKey = { //存儲蛇走的方向
		left: {   //往左走
			x: -1, //橫座標減1,一個座標表示一個格子
			y: 0,   //縱座標不變
			rotate: 90
		},
		right: {   //往右走
			x: 1,
			y: 0,
			rotate: -90
		},
		up: {    //往上走
			x: 0,
			y: -1,
			rotate: 180
		},
		down: {    //往下走
			x: 0,
			y: 1,
			rotate: 0 //蛇頭圖片方向,順時針爲正
		}
	}
}
Snake.prototype.init = function() { //初始化蛇
	//蛇頭
	var snakeHead = new Square(2,0,"head");
	snakeHead.create();
	this.head = snakeHead; //存儲蛇頭信息
	this.pos.push([2,0]);  //存儲蛇頭座標

	//蛇的第1節身體
	var snakeBody1 = new Square(1,0,"body");
	snakeBody1.create();
	this.pos.push([1,0]);

	//蛇的尾巴
	var snakeTail = new Square(0,0,"body");
	snakeTail.create();
	this.tail = snakeTail;
	this.pos.push([0,0]);

	//形成鏈表關係
	snakeHead.prev = null;
	snakeHead.next = snakeBody1;

	snakeBody1.prev = snakeHead;
	snakeBody1.next = snakeTail;

	snakeTail.prev = snakeBody1;
	snakeTail.next = null;

	//初始蛇的走向,後面想改變蛇的走向即改變this.direction
	this.direction = this.directionKey.right; //默認向右走

};

//獲取蛇頭下一個位置對應的元素,根據元素做下一個動作
Snake.prototype.getNextPos = function() {
	var nextPos = [ //獲取蛇頭走的下一個點的座標
	    this.head.x / config.width + this.direction.x,
	    this.head.y / config.height + this.direction.y
	];

	//判斷下一個點是自己or食物or圍牆or無障礙?
	var self = false; //設置下一個點是否是自己
	this.pos.forEach(function(val) { //val即二位數組中的一個座標
		if(val.toString() === nextPos.toString()) { //下一個座標等於蛇全部身體的一個,即下一個點是自己
             self = true;
	    }
	});
	if(self) {
		// console.log('撞到自己了!');
		this.collide.end.call(this); //game over

		return;
	} else if(nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > config.td-1 || nextPos[1] > config.tr-1) {
		// console.log('撞到牆壁了!');
		this.collide.end.call(this); //game over

		return;
	} else if (food && food.pos[0] === nextPos[0] && food.pos[1] === nextPos[1]) {
		console.log('撞到食物了!');
		this.collide.eat.call(this);
	} else {
		// console.log('啥都沒遇到!');
		this.collide.move.call(this, false); //注意:.call(this)重新設置this指向,使其指向當前實例對象Snake
	}
	

};

//處理碰撞後的事件
Snake.prototype.collide = {
	/*
	碰到自己or牆壁,遊戲結束end();
	碰到食物,eat();
	啥都沒遇到,move();
	*/
	move: function(isEat) {   //isEat 是否吃了食物,不是則刪除蛇尾
	/*
	掐頭去尾:
	create新蛇頭,remove舊蛇頭;
	create一個新身體,放在(替代)舊蛇頭的位置;
	remove蛇尾,蛇尾prev的元素變成新蛇尾
	*/
		var x = this.head.x / config.width + this.direction.x,
		    y = this.head.y / config.height + this.direction.y;
		//聲明一個新身體
		var newBody = new Square(this.head.x/config.width, this.head.y/config.height, "body");
		//更新鏈表關係
		newBody.next = this.head.next;
		newBody.next.prev = newBody;
		newBody.prev = null;

		this.head.remove(); //刪除舊蛇頭
		newBody.create(); //添加蛇身體,替代在舊蛇頭位置

		//聲明一個新蛇頭(下一個走的點)
	    var newHead = new Square(x, y, "head");
	    //更新鏈表關係
	    newHead.prev = null;
	    newHead.next = newBody;
	    newBody.prev = newHead;

	    this.pos.unshift([x, y]); //更新蛇節點的座標this.pos
	    this.head = newHead; //更新this.head的信息
      
        newHead.contentDom.style.transform = `rotate(${this.direction.rotate}deg)`
	    newHead.create(); //添加蛇頭

	    //刪除蛇尾:吃食物則不刪
	    if(!isEat) { //沒有吃食物,刪除蛇尾
	    	this.tail.remove();
	    	this.tail = this.tail.prev;

	    	this.pos.pop(); //更新蛇節點座標
	    }
	    // console.log(this.pos); //打印數組,驗證
	},
	eat: function() {
		this.collide.move.call(this, true); //傳參true,表示此時爲吃操作
		food.remove();
		game.score ++; //記錄分數
		createFood();
	},
	end: function() {
		console.log('end');
		game.gameOver();
	}

}

snake = new Snake();

//創建食物
function createFood() {
	var x = null, y = null;
	var include = true; //表示食物的位置是否在蛇身上
	var random = function(max, min) { //產生一個隨機數
		return Math.floor(Math.random()*(max - min + 1))
	};
	while(include) {
		x = random(config.tr - 1, 0);
		y = random(config.td - 1, 0);

		snake.pos.forEach(function(val) {
			if(x != val[0] && y != val[1]) {
				include = false;
			}
		});
	}

	//生成食物
	food = new Square(x, y, "food");
	food.pos = [x, y]; //記錄食物座標
	food.create();
}

//遊戲邏輯
function Game() {
    this.score = 0; //分數
	this.timer = null; //計時器
}
Game.prototype.init = function() {
	snake.init();
    // snake.getNextPos(); //獲取下一個點座標
	createFood();

	document.onkeydown = function(event) {
		if(event.which == 37 && snake.direction != snake.directionKey.right) { 
		   //鼠標左鍵,蛇不能是正在往右走
			snake.direction = snake.directionKey.left;
		} else if (event.which == 38 && snake.direction != snake.directionKey.down) { 
			//鼠標上鍵
			snake.direction = snake.directionKey.up;
		} else if (event.which == 39 && snake.direction != snake.directionKey.left) { 
			//鼠標右鍵
			snake.direction = snake.directionKey.right;
		} else if (event.which == 40 && snake.direction != snake.directionKey.up) { 
			//鼠標下鍵
			snake.direction = snake.directionKey.down;
		}
	}
	this.start();
};
game = new Game();
//開始遊戲
Game.prototype.start = function() {
	this.timer = setInterval(function() {
		snake.getNextPos();
	}, 200);
};
//遊戲結束
Game.prototype.gameOver = function() {
	console.log("gameOver");
	clearInterval(this.timer);
	var gameOver = document.querySelector('.gameOver');
	var gameScore = document.querySelector('.gameOver .score');
	gameOver.style.display = 'block';
	gameScore.innerHTML = `${this.score}`;
};

//開啓遊戲
function startGame() {
	var startBtn = document.querySelector('.btn button');
	var snakeWrap = document.querySelector('.snakeWrap');
	startBtn.onclick = function() {
		startBtn.parentNode.style.display = 'none';
        snakeWrap.style.display = 'block';
        game.init();

	}
}
startGame();

主要用到鏈表數據結構,後續項目代碼會上傳到gitee上~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章