今天早上坐地鐵13號線,到西二旗站下車後,看見了一個身穿印有科比曼巴標誌的紫金外套的小姐姐,瞬間吸引了我,還戴着棒球帽,在這疫情肆虐的時期,真是人羣中的一股清流,一股溫暖。
真想上去搭訕,奈何人羣中我只看了她一眼,而她,早已煙消雲散。
於是乎我打算用JS寫個和黑曼巴有關的東西,於是就想到了寫個貪吃蛇吧。紀念一下老大。
話不多說,進入正題
先欣賞一下效果圖吧
紫金模式
暗黑模式
技術
- Jquery
- Js
- Htmll
- Css
- Bootstrap
- SKPlayer
實現功能
- 開始/暫停/繼續遊戲
- 遊戲得分
- 排行榜
- 暗黑/紫金模式切換
- 集成SKPlayer組件
- 附贈3首SQ無損品質音樂
- 夜空中最亮的星(純音樂鋼琴版)
- See You Again(Charlie Puth/Wiz Khalifa)
- Because Of You(Kelly Clarkson)
遊戲原理
- 首先有個遊戲區域,例如在900*600內的區域遊戲
- 以XY點座標來實現蛇和事物的定位
- 蛇行走的路線通過定時器來實現,例如蛇頭往左移動,1秒後,蛇頭的座標X加上1個單元,而座標Y不變,蛇身體裏的座標也都這樣計算,X加1個單元,Y軸不變,這樣就實現了蛇的整體移動
- 吃食物是通過蛇頭和食物的XY座標相等來判斷的,然後讓食物消失,在蛇的尾巴加上一個單元
- 隨機生成食物就是通過隨機XY座標來實現的
- 碰壁,或者撞到自己的身體就遊戲結束,這也是通過XY座標來實現的。
- 遊戲難易程度就是定時器的時間間隔,越難的間隔越短,蛇移動的越快
核心代碼
使用構造方法創建黑曼巴蛇
function BlackMamba() {
//初始化蛇的屬性,是由蛇頭,身體,蛇尾,一個3個單位組成,默認地址在左上角
this.width = snakeIconWidth;
this.height = snakeIconHeight;
this.direction = direction;
this.body = [
{x: 2, y: 0},
{x: 1, y: 0},
{x: 0, y: 0}
];
}
讓蛇在頁面中顯示出來
this.display = function () {
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].x != null) { // 當吃到食物時,x==null,不能新建,不然會在0,0處新建一個
var s = document.createElement('div');
//將節點保存到狀態中,以便於後面刪除
this.body[i].flag = s;
//設置寬高
s.style.width = this.width + 'px';
s.style.height = this.height + 'px';
if (i == 0) {
s.style.backgroundImage = "url(image/snake.png)";
} else {
s.style.backgroundImage = "url(image/body.png)";
}
//設置位置,這裏計算位置的時候一定是30的倍數,這樣吃蛇的時候才能根據座標吻合來判斷
s.style.position = 'absolute';
s.style.left = this.body[i].x * this.width + 'px';
s.style.top = this.body[i].y * this.height + 'px';
//添加到遊戲中
gameArea.appendChild(s);
}
}
};
讓蛇跑起來
//讓蛇跑起來,後一個元素到前一個元素的位置
//蛇頭根據方向處理,所以i不能等於0
this.run = function () {
//後一個元素到前一個元素的位置
for (var 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;
}
//根據方向處理蛇頭
switch (this.direction) {
case "left":
this.body[0].x -= 1;
break;
case "right":
this.body[0].x += 1;
break;
case "up":
this.body[0].y -= 1;
break;
case "down":
this.body[0].y += 1;
break;
}
flag = false;
//判斷是否出界,因爲底圖的寬是900,所以寬度不能大於(900/30)-1=29,高是600,所以高度不能大於(600/30)-1=19
if (this.body[0].x < 0 || this.body[0].x > 29 || this.body[0].y < 0 || this.body[0].y > 19) {
gameOver(this);
return false;
}
//判斷蛇頭吃到食物,判斷的依據是xy座標重合,就是蛇頭和食物的座標一樣
if (this.body[0].x == food.x && this.body[0].y == food.y) {
//蛇加一節,因爲根據最後節點定,下面display時,會自動賦值的
this.body.push({x: null, y: null, flag: null});
scoreNum++;
$("#score").html("玩家分數:" + scoreNum);
// 清除食物,重新生成食物
gameArea.removeChild(food.flag);
food.display();
}
//碰到自己就死亡,從第五個開始與頭判斷,因爲前四個永遠撞不到
for (var i = 4; i < this.body.length; i++) {
if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y) {
gameOver(this);
return false;
}
}
//先刪掉初始的蛇,在顯示新蛇
for (var i = 0; i < this.body.length; i++) {
if (this.body[i].flag != null) { // 當吃到食物時,flag是等於null,且不能刪除
gameArea.removeChild(this.body[i].flag);
}
}
//重新顯示蛇
this.display();
}
隨機創建食物
//隨機創建食物
function Food() {
this.width = snakeIconWidth;
this.height = snakeIconHeight;
this.display = function () {
var food = document.createElement('div');
this.flag = food;
food.style.width = this.width + 'px';
food.style.height = this.height + 'px';
food.style.backgroundImage = "url(image/food.png)";
food.style.position = 'absolute';
//取1-9的隨機數
this.x = randomNum(1,29);
this.y = randomNum(1,19);
//遞歸檢查隨機生成的XY座標是否和 蛇的身體座標重合
if(judgeFoodAndSnakeXYCoincidence(this.x,this.y)){
this.display();
}else{
//這裏計算位置的時候一定是30的倍數,這樣吃蛇的時候才能根據座標吻合來判斷
food.style.left = this.x * 30 + 'px';
food.style.top = this.y * 30 + 'px';
gameArea.appendChild(food);
}
}
}
判斷隨機生成的事物會不會和蛇本身的XY座標重合,不允許重合
function judgeFoodAndSnakeXYCoincidence(x,y){
var flag = false;
for (var i = 0; i < blackMamba.body.length; i++) {
if (blackMamba.body[i].x == x && blackMamba.body[i].y == y) {
flag = true;
break;
console.log(i + '--------' + blackMamba.body[i].x + '---------------' + blackMamba.body[i].y);
}
}
return flag;
}
遊戲結束
//遊戲結束
function gameOver(obg){
// 清除定時器
clearInterval(timer);
//彈出提示框,用的是bootstrap modal
$('#myModal').modal();
//顯示玩家分數
$("#content").html('GAME OVER! 您的成績是 ' + scoreNum + ' 分');
//刪除所有蛇
for (var i = 0; i < obg.body.length; i++) {
if (obg.body[i].flag != null) { // 如果剛吃完就死掉,會加一個值爲null的
gameArea.removeChild(obg.body[i].flag);
}
}
// 回到初始狀態
obg.body = [
{x: 2, y: 0},
{x: 1, y: 0},
{x: 0, y: 0}
];
//初始化蛇
obg.direction = direction;
obg.display();
//把成績添加到排行榜中
var playerName = $("#player").val();
var typeName = '';
var type = $('input:radio[name="inlineRadioOptions"]:checked').val();
switch (type) {
case "500":
typeName = '簡單'
break;
case "300":
typeName = '一般'
break;
case "100":
typeName = '困難'
break;
}
var html = "<tr><td>" + playerName + "</td><td>" + typeName + "</td><td>" + scoreNum + "</td><td>1分鐘前</td></tr>";
$("#tableBody").append(html);
var trLength = $("#tableBody > tr").length;
if(trLength > 5){
$("#tableBody tr").eq(1).remove();
}
//分數清零
scoreNum = 0;
$("#score").html("玩家分數:" + scoreNum);
}
鍵盤方向按鍵事件
//阻塞按鍵事件
var flag = false;
//給body加按鍵事件,上下左右
document.body.onkeydown = function (e) {
if (flag) {
return;
}
// 有事件對象就用事件對象,沒有就自己創建一個,兼容低版本瀏覽器
var ev = e || window.event;
//這裏加入判斷,例如蛇正在往左移動,這是就不能直接往右移動,只能往上或者下
switch (ev.keyCode) {
case 38:
if (blackMamba.direction != 'down') {
blackMamba.direction = "up";
}
break;
case 40:
if (blackMamba.direction != "up") {
blackMamba.direction = "down";
}
break;
case 37:
if (blackMamba.direction != "right") {
blackMamba.direction = "left";
}
break;
case 39:
if (blackMamba.direction != "left") {
blackMamba.direction = "right";
}
break;
}
flag = true;
};
點擊開始按鈕
//點擊開始遊戲按鈕事件
begin.onclick = function () {
//判斷玩家姓名是否爲空
var playerName = $("#player").val();
if (playerName == '' || playerName == undefined || playerName == null) {
$('#myModal').modal();
$("#content").html('請輸入玩家姓名!');
return;
}
clearInterval(timer);
//獲取遊戲難易程度,每次點擊都獲取一遍,這樣在暫停的時候可以修改難易程度
var type = $('input:radio[name="inlineRadioOptions"]:checked').val();
timer = setInterval("blackMamba.run()", type);
};
點擊暫停/繼續按鈕
//點擊暫停,繼續遊戲事件
stop.onclick = function () {
console.log(timer)
if (timer == undefined) {
$('#myModal').modal();
$("#content").html('請先開始遊戲');
return;
} else {
if (this.innerHTML == '繼續遊戲') {
this.innerHTML = '暫停遊戲'
//獲取遊戲難易程度,每次點擊都獲取一遍,這樣在暫停的時候可以修改難易程度
var type = $('input:radio[name="inlineRadioOptions"]:checked').val();
timer = setInterval("blackMamba.run()", type);
} else {
clearInterval(timer);
this.innerHTML = '繼續遊戲'
return;
}
}
}
切換到暗黑模式
callKobe.onclick = function () {
document.body.style.backgroundColor = white
document.body.style.color = black;
gameArea.style.backgroundImage = "url(image/kobe.jpg)";
document.body.style.color = black;
begin.setAttribute('class','btn btn-default btn-kobe');
stop.setAttribute('class','btn btn-default btn-kobe');
jianbian(document.body);
jianbian(gameArea);
skPlayerDom.style.backgroundColor = white;
skPlayerDom.style.color = mp3Black;
document.getElementsByClassName('skPlayer-percent').item(0).style.backgroundColor = mp3Black;
document.getElementsByClassName('skPlayer-percent').item(1).style.backgroundColor = mp3Black;
document.getElementsByClassName('skPlayer-curMusic').item(0).style.backgroundColor = white;
document.getElementsByClassName('skPlayer-list').item(0).style.backgroundColor = white;
}
切換到紫金模式
restKobe.onclick = function () {
document.body.style.backgroundColor = gold;
document.body.style.color = purple;
gameArea.style.backgroundImage = "url(image/bgkb.jpg)";
gameArea.style.filter="alpha(opacity=0)";
gameArea.style.opacity=0;
document.getElementById('kobeTop').style.color = purple;
document.getElementById('leftForm').style.border = '2px solid ' + purple;
begin.setAttribute('class','btn btn-default btn-purple-gold');
stop.setAttribute('class','btn btn-default btn-purple-gold');
jianbian(document.body);
jianbian(gameArea);
skPlayerDom.style.backgroundColor = purple;
skPlayerDom.style.color = gold;
document.getElementsByClassName('skPlayer-percent').item(0).style.backgroundColor = gold;
document.getElementsByClassName('skPlayer-percent').item(1).style.backgroundColor = gold;
document.getElementsByClassName('skPlayer-curMusic').item(0).style.backgroundColor = purple;
document.getElementsByClassName('skPlayer-list').item(0).style.backgroundColor = purple;
}
實現切換漸變效果
//css漸變效果
function jianbian(obj) {
var alpha = 0;
clearInterval(jianBianTimer);
jianBianTimer = setInterval(function () {
alpha++;
obj.style.opacity = alpha / 100;
obj.style.filter = "alpha(opacity=" + alpha + ")";
if (alpha == 100) {
clearInterval(jianBianTimer);
}
}, 10);
}
MP3播放器
var player = new skPlayer({
autoplay: false,
//可選項,自動播放,默認爲false,true/false
listshow: true,
//可選項,列表顯示,默認爲true,true/false
mode: 'singleloop',
//可選項,循環模式,默認爲'listloop'
//'listloop',列表循環
//'singleloop',單曲循環
//可選項配置同上
music: {
//必需項,音樂配置
type: 'file',
//必需項,自配置文件方式指定填'file'
source: [
//必需項,音樂文件數組
{
name: '夜空中最亮的星',
//必需項,歌名
author: '無損純音樂鋼琴版',
//必需項,歌手
src: 'mp3/star.mp3',
//必需項,音樂文件
cover: 'image/haha.jpg'
//必需項,封面圖片
},
{
name: 'See You Again',
//必需項,歌名
author: 'Charlie Puth/Wiz Khalifa',
//必需項,歌手
src: 'mp3/see you again.mp3',
//必需項,音樂文件
cover: 'image/mp2.jpg'
//必需項,封面圖片
},
{
name: 'Because Of You',
//必需項,歌名
author: 'Kelly Clarkson',
//必需項,歌手
src: 'mp3/because of you.mp3',
//必需項,音樂文件
cover: 'image/mp3.jpg'
//必需項,封面圖片
}
]
}
});
獲取源碼
關注公衆號:老王搞BUG,回覆 “貪吃蛇源碼” 即可獲取全部源碼