完全自己寫的貪吃蛇,先試試沒有參考別人的方法,自己的思路是怎麼樣的。
個人覺得貪吃蛇最難的地方是蛇移動,考慮到蛇移動可能轉換方向,最好的方式,是把尾部去了截,在頭部按當前蛇的方向增加一截,這樣看起來蛇就移動了。
具體看註釋。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>貪吃蛇</title>
<style>
/*canvas居中*/
#myCanvas {
position: absolute;
margin: auto auto;
top: 5px;
right: 5px;
bottom: 5px;
left: 5px;
border: 1px solid black;
}
</style>
<script>
//啓用javascript嚴格模式,執行效率高
"use strict";
//定義全局變量
var gird_length=10;//每一格的寬度
var rol_gird=60;//橫行60格
var col_grid=40;//一列40格
window.addEventListener("load",function(){
var myCanvas=document.getElementById("myCanvas");
var context=myCanvas.getContext("2d");
//設置canvas寬度
myCanvas.width=rol_gird*gird_length;
myCanvas.height=col_grid*gird_length;
//聲明 蛇喜歡吃的點心
var food;
//得分
var score=0;
//格子類
function Grid(x,y,dir){
this.color="blue";
this.strokeColor="white";
this.x=x;
this.y=y;
if(dir==undefined){
dir="right";
}
this.dir=dir;
};
//格子顯示
Grid.prototype.draw= function(){
context.save();
context.fillStyle=this.color;
context.fillRect(this.x,this.y,gird_length,gird_length);
//加grid邊框
context.strokeStyle = this.strokeColor;
context.strokeRect(this.x,this.y,gird_length,gird_length);
context.restore();
};
//格子移動
Grid.prototype.move= function(){
if(this.dir==="up"){
this.y=this.y-gird_length;
}else if(this.dir==="left"){
this.x=this.x-gird_length;
}else if(this.dir==="down"){
this.y=this.y+gird_length;
}else if(this.dir==="right"){
this.x=this.x+gird_length;
}
this.draw(this.x,this.y,gird_length,gird_length);
};
//格子刪除
Grid.prototype.remove= function(){
context.clearRect(this.x,this.y,gird_length,gird_length);
delete this;
};
//蛇起始出現位置在(3,3)格
var snake={
x:3,
y:3,
gridArr:new Array(),//包含格子數組
dir:"right"
};
//蛇顯示,循環調用格子draw方法
snake.draw= function(){
for(var i=0;i<this.gridArr.length;i++){
this.gridArr[i].draw();
}
};
//蛇移動,本遊戲難點所在
//蛇移動,不是每一個格子向前移動,這樣的話不好把握蛇轉換方向
//正確的方法是,把蛇最後一格去掉,按當前方向生成一個新的格子,加到最前面。
snake.move= function(){
var lastGrid=this.gridArr.shift();//數組的shift方法,刪除array[0],並返回對象
lastGrid.remove();
var firstGrid=this.gridArr[this.gridArr.length-1];
//不允許蛇向反方向移動
var dir=this.dir;
if((firstGrid.dir=="up"&&dir=="down")||(firstGrid.dir=="down"&&dir=="up")
||(firstGrid.dir=="right"&&dir=="left")||(firstGrid.dir=="left"&&dir=="right")){
//如果蛇向反方向,則無效,按原來方向
dir=firstGrid.dir;
}
var g = new Grid(firstGrid.x,firstGrid.y,dir);//按蛇的方向生成一個新格子。
g.move();
//記得把lastGrid加到gridArr,如果不記得調試就可以看出來。
//沒關係,程序是調出來的
this.gridArr.push(g);
};
//蛇吃了點心。向尾部加一個格子,方向和最後一個一樣
snake.eat=function(){
var lastGrid=this.gridArr[0];
var x=lastGrid.x;
var y=lastGrid.y;
//後退一格
if(lastGrid.dir=="up"){
y+=gird_length;
}
else if(lastGrid.dir=="down"){
y-=gird_length;
}else if(lastGrid.dir=="right"){
x+=gird_length;
}else if(lastGrid.dir=="left"){
x-=gird_length;
}
var g = new Grid(x,y,lastGrid.dir);
g.move();
this.gridArr.unshift(g);//Array的unshift方向,向數組0位置插入一個元素
};
//蛇初始五格
snake.init=function(){
for(var i=0;i<5;i++){
this.gridArr.push(new Grid((this.x+i)*gird_length,this.y*gird_length));
}
this.draw();
};
snake.init();
randomFood().draw();
initScore();
//初始化Score
function initScore(){
context.font="20px Georgia";
context.fillText("Score:",3*gird_length,(col_grid-3)*gird_length);
context.fillText(score,9*gird_length,(col_grid-3)*gird_length);
}
//更新分數
function updateScore(){
score+=10;
context.clearRect(9*gird_length,(col_grid-5)*gird_length,3*gird_length,gird_length*2);
context.fillText(score,9*gird_length,(col_grid-3)*gird_length);
}
//檢測蛇是否檢測蛇是否碰到自己和碰到牆
snake.isDead= function(){
var arr = this.gridArr;
//是否碰到自己
for(var i=0;i<arr.length;i++){
var gi= arr[i];
for(var j=0;j<arr.length;j++){
if(i==j)
continue;
var gj=arr[j];
if(gi.x==gj.x&&gi.y==gj.y)
return true;
}
//是否碰到牆
if(gi.x<=0||gi.y<=0||gi.x>=myCanvas.width-gird_length||gi.y>=myCanvas.height-gird_length)
return true;
}
return false;
};
//定時移動蛇
window.timer=window.setInterval(function(){
snake.move();
//每次移動後,首先檢測蛇是否碰到自己和碰到牆
if(snake.isDead()){
//刪除定時器
clearInterval(timer);
alert("遊戲結束,重新開始,請刷新頁面");
}else{
//snake每一次移動後就檢測下是否吃到food
if(isCollide()){
updateScore();
snake.eat();
//生成新的foot
randomFood().draw();
}
}
},300);
//按鍵改變snake方向
window.addEventListener("keydown",function(e){
var keyCode=e.keyCode;
console.log(keyCode);
if(keyCode===87){
snake.dir="up";
}else if(keyCode===68){
snake.dir="right";
}
else if(keyCode===83){
snake.dir="down";
}
else if(keyCode===65){
snake.dir="left";
}
});
//碰撞檢測
function isCollide(){
var arr = snake.gridArr;
var x=food.x;
var y=food.y;
for(var i=0;i<arr.length;i++){
var g= arr[i];
if(x===g.x&&y===g.y){
return true;
}
}
return false;
}
//隨機生成food;
function randomFood(){
var r=Math.random();
var x=parseInt(r*rol_gird);
var y=parseInt(r*col_grid);
food= new Grid(x*gird_length,y*gird_length);
if(isCollide()){
return randomFood();
}else
return food;
}
});
</script>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>