html小遊戲——看你有多色

前幾天一個朋友問了我要作看你有多色這樣的一個遊戲須要怎麼學,我也就本身寫了一下。javascript

我有放在本身的我的網站上:查看遊戲php

源代碼也放在了github上:查看源碼css

如今開始說明制過程:html


項目結構

注:偷懶用了jquery,其實代碼很少,徹底能夠原生js,另外,因爲此次我沒有使用圖片,因此img裏面的內容是空的java

game 
    -index.html     -css         -index.css     -js         -index.js         -jqeuery.js     -img 

遊戲界面

  • loading: 主要用於加載遊戲資源
  • 啓動遊戲: 能夠寫些遊戲規則,點擊開始遊戲就開始遊戲
  • 遊戲中:遊戲進行的頁面
  • 遊戲暫停: 遊戲暫停的頁面
  • 遊戲結束: 遊戲結束的頁面

每一個頁面使用一個div表示,進行到哪一步就將哪個頁面div的display變爲block,從而顯示。jquery


代碼展現

index.html:css3

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>找找看</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1">
    <link href="./css/index.css" rel="stylesheet">
</head>
<body>
    <!--加載頁面-->
    <div class="page loading" style="display: none">
        <p>加載中...</p>
    </div>
    <!--開始遊戲頁面 -->
    <div class="page index" style="display: none">
        <h1>找找看</h1>
        <p class="tip">
            找出全部色塊裏顏色不一樣的一個
        </p>
        <button class="start-game">
            開始遊戲
        </button>
    </div>
    <!--遊戲中-->
    <div class="page room" style="display: block;">
        <div class="top">
            <span class="score">得分:0</span>
            <span class="time">60</span>
            <span class="btn btn-pause">暫停</span>
        </div>
        <div id="box"></div>
    </div>
    <!--暫停-->
    <div class="page pause">
        <h1>遊戲暫停</h1>
        <button class="continue">
            繼續遊戲
        </button>
    </div>
    <!--遊戲結束-->
    <div class="page over">
        <h1>遊戲結束</h1>
        <p class="result">
            總分:0
        </p>
        <button class="restart">
            從新開始
        </button>
    </div>
    <script src="./js/jquery-1.7.1.min.js"></script>
    <script src="./js/index.js"></script>
</body>
</html>

index.cssgit

/* 重置樣式 */
html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
table{border-collapse:collapse;border-spacing:0;}
caption,th{text-align:left;font-weight:normal;}
html,body,fieldset,img,iframe,abbr{border:0;}
i,cite,em,var,address,dfn{font-style:normal;}
[hidefocus],summary{outline:0;}
li{list-style:none;}
h1,h2,h3,h4,h5,h6,small{font-size:100%;}
sup,sub{font-size:83%;}
pre,code,kbd,samp{font-family:inherit;}
q:before,q:after{content:none;}
textarea{overflow:auto;resize:none;}
label,summary{cursor:default;}
a,button{cursor:pointer;}
h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:normal;}
del,ins,u,s,a,a:hover{text-decoration:none;}
body,textarea,input,button,select,keygen,legend{font:16px/1 "Microsoft Yahei", Arial, Helvetica, Sans-Serif,\5b8b\4f53;color:#333;outline:0;}
a,a:hover{color:#444;}
button{padding:0;margin:0;border:0;background-color:#fff;}

html, body { height: 100%; width: 100%; overflow: hidden;}
body { background-color: rgb(18, 149, 73);}
.page { display: none; position: relative; height: 100%; max-width: 600px; margin: 0 auto; color: #fff; text-align: center; }
.loading { display: block;}
.loading p { position: absolute; top: 50%; left: 50%; width: 200px; height: 30px; margin-left: -100px; margin-top: -15px; line-height: 30px; font-size: 26px; }
.index h1 { font-size: 30px; padding: 30px 0; }
.index p { height: 40px; line-height: 40px; font-size: 20px; color: #adffe0; text-align: center;}
.index button, .pause button, .over button{ display: block; position: absolute; bottom: 100px; left: 50%; height: 50px; width: 220px; margin-left: -110px; border-radius: 7px; line-height: 50px; box-shadow: 0 5px #da9622; color: inherit; cursor: pointer; font-weight: 700; font-size: 20px; background: #fcad26; }
#box { position: absolute; top: 50%; left: 50%; width: 500px; height: 500px; margin-left: -260px; margin-top: -260px; border-radius: 10px; padding: 10px; background-color: #ddd; }

@media only screen and (max-width: 500px) and (min-width: 414px) {
    #box { width: 380px; height: 380px; margin-left: -200px; margin-top: -200px; }
}
@media only screen and (max-width: 414px) and (min-width: 375px) {
    #box { width: 340px; height: 340px; border-radius: 8px; margin-left: -180px; margin-top: -180px; }
}
@media only screen and (max-width: 375px) {
    #box { width: 300px; height: 300px; border-radius: 5px; margin-left: -160px; margin-top: -160px; }
}
#box span { display: block; float: left; border-radius: 10px; cursor: pointer; border: 5px solid #ddd; position: relative; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
#box.lv2 span { width: 50%; height: 50%; }
#box.lv3 span { width: 33.3333%; height: 33.3333%; }
#box.lv4 span { width: 25%; height: 25%; }
#box.lv5 span { width: 20%; height: 20%; }
#box.lv6 span { width: 16.666%; height: 16.666%; }
#box.lv7 span { width: 14.285%; height: 14.285%; }
.score { position: absolute; top: 10px; left: 5px; color: #adffe0; }
.time { position: absolute; top: 5px; left: 50%; display: block; color: #fff; width: 50px; margin-left: -25px; height: 24px; line-height: 24px; border-radius: 10px; text-align: center; font-size: 20px; font-weight: 700; background-color: rgb(117, 214, 171); }
.btn-pause{ display: block; position: absolute; top: 5px; right: 5px; height: 24px; width: 60px; border-radius: 7px; line-height: 24px; box-shadow: 0 4px #da9622; color: inherit; cursor: pointer; font-weight: 500; font-size: 16px; background: #fcad26; }
.pause h1, .over h1{ height: 150px; line-height: 150px; font-size: 30px; }
.over p { font-size: 26px; }

index.jsgithub

var game = {};
//緩存
game.pages = $('.page');
game.startBtn = $('.start-game').eq(0);
game.pauseBtn = $('.btn-pause').eq(0);
game.continueBtn = $('.continue').eq(0);
game.restartBtn = $('.restart').eq(0);
game.blockBox = $('#box');
game.scoreBox = $('.score').eq(0);
game.timeBox = $('.time').eq(0);
game.resultBox = $('.result').eq(0);
game.eventType = document.ontouchstart ? 'touchstart' : 'click';
game.imgUrls = [];
game.time = 60;
game.score = 0;
game.level = 0;
game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7];
game.colorDiff = [115, 100, 100, 85, 85, 85, 70, 70, 70, 70, 55, 55, 55, 55, 55, 40, 40, 40, 40, 40, 40, 25, 25, 25, 25, 25, 25, 25, 10, 10, 10, 10, 10, 10, 10, 10];
game.diffIndex = 0;
//加載遊戲
game.loading = function () {
    var imgCounts = this.imgUrls.length;
    if ( imgCounts == 0) {
        this.switchPage(1);
        this.initEvent();
    } else {
        var num = 0,
            self = this;
        function count () {
            num++;
            if ( num == imgCounts ) {
                self.switchPage(1);
                self.initEvent();
            }
        }
        for ( var i = 0; i < imgCounts; i++ ) {
            var img = new Image();
            img.onload = count;
            img.src = this.imgUrls[i];
        }
    }
};
//初始化事件
game.initEvent = function () {
    this.startBtn.on(this.eventType, this.start.bind(this));
    this.restartBtn.on(this.eventType, this.start.bind(this));
    this.blockBox.on(this.eventType, this.clickBlock.bind(this));
    this.pauseBtn.on(this.eventType, this.pause.bind(this));
    this.continueBtn.on(this.eventType, this.continue.bind(this));
};
//點擊方塊事件
game.clickBlock = function ( event ) {
    if ( event.target.tagName.toLowerCase() === 'span' ) {
        //選對了
        if ( $(event.target).index() == this.diffIndex ) {
            this.level++;
            this.score++;
            this.render();
        } else {
            this.over()
        }
    }
};
//開始遊戲
game.start = function () {
    this.switchPage(2);
    this.render();
    this.timeCount();
};
//遊戲界面渲染
game.render = function () {
    //獲取有n*n
    var num = this.levelMap[this.level] ? this.levelMap[this.level] : this.levelMap[this.levelMap.length - 1],
        colorDiff = this.colorDiff[this.level] ? this.colorDiff[this.level] : this.colorDiff[this.colorDiff.length - 1],
        color = [],
        lvColor = [];
    //分數
    this.scoreBox.html('得分:' + this.score);
    //時間
    this.timeBox.html(this.time);
    //給box添加類名
    this.blockBox[0].className = 'lv' + num;
    //獲得不一樣塊的index
    this.diffIndex = Math.floor(Math.random() * num * num);
    //獲取顏色
    color = this.getColor(257 - colorDiff);
    lvColor = this.getLvColor(color[0], colorDiff);
    //添加block
    var str = '';
    num *= num;
    for ( var i = 0; i < num; i++ ) {
        if ( i == this.diffIndex ) {
            str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
        } else {
            str += '<span style="background-color: ' + color[1] + ';"></span>';
        }
    };
    this.blockBox.html(str);
};
//獲得隨機顏色
game.getColor = function (max) {
    var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
    return [t, "rgb(" + t.join(",") + ")"];
};
//獲得不一樣的顏色
game.getLvColor = function (color, diff) {
    var r = [];
    r[0] = color[0] + diff;
    r[1] = color[1] + diff;
    r[2] = color[2] + diff;
    return [r, "rgb(" + r.join(",") + ")"];
};
//遊戲結束處理
game.over = function () {
    this.switchPage(4);
    this.resultBox.html('總分:' + this.score);
    clearInterval(this.timer);
    this.time = 60;
    this.score = 0;
    this.level = 0;
};
//遊戲暫停處理
game.pause = function () {
    clearInterval(this.timer);
    this.switchPage(3);
};
//繼續遊戲
game.continue = function () {
    this.switchPage(2);
    this.timeCount();
};
//計時器
game.timeCount = function () {
    var self = this;
    game.timer = setInterval(function(){
        self.time--;
        self.timeBox.html(self.time);
        if ( self.time == 0 ) {
            self.over.call(self);
        }
    }, 1000)
};
//換頁
game.switchPage = function ( index ) {
    this.pages.css('display', 'none');
    this.pages.eq(index).css('display', 'block');
};

//遊戲入口,觸發加載
game.loading();

你們能夠看到js代碼,全部的變量和函數都添加到了game={}這個對象上,以防發生全局污染。web

遊戲加載

有遊戲加載這個步驟的主要目的是在遊戲加載資源的時候讓用戶知道具體的加載過程,省得加載過慢時用戶離開頁面。

代碼爲:

...
game.imgUrls = [];
...
//加載遊戲
game.loading = function () {
    var imgCounts = this.imgUrls.length;
    if ( imgCounts == 0) {
        this.switchPage(1);
        this.initEvent();
    } else {
        var num = 0,
            self = this;
        function count () {
            num++;
            if ( num == imgCounts ) {
                self.switchPage(1);
                self.initEvent();
            }
        }
        for ( var i = 0; i < imgCounts; i++ ) {
            var img = new Image();
            img.onload = count;
            img.src = this.imgUrls[i];
        }
    }
};

這段代碼並不難理解,game.imgUrls爲存放圖片url的數組,遊戲加載的時候經過獲取到這個數組的長度,判斷是否進行圖片加載。

若是不須要加載就切換到開始遊戲的界面,而且添加事件處理。

其中,this.switchPage函數的代碼爲:

...
game.pages = $('.page');
...
//換頁
game.switchPage = function ( index ) {
    this.pages.css('display', 'none');
    this.pages.eq(index).css('display', 'block');
};

當加載圖片存在時,即imgUrls不爲空數組,那麼開始加載圖片

var num = 0,
    self = this;
    function count () {
        num++;
        if ( num == imgCounts ) {
            self.switchPage(1);
            self.initEvent();
        }
    }
    for ( var i = 0; i < imgCounts; i++ ) {
        var img = new Image();
        img.onload = count;
        img.src = this.imgUrls[i];
    }

代碼中,循環遍歷了imgUrls,將src賦給一個img對象,而後onload(加載完成)就將計數+1,當計數和圖片數量一致時說明所有加載完成,而後就換頁和添加事件。


開始遊戲界面

這個界面主要功能是顯示提示信息,和點擊開始遊戲按鈕時開始遊戲。

這裏寫圖片描述

添加事件都放在game.initEvent函數中

...
game.startBtn = $('.start-game').eq(0);
...
game.eventType = document.ontouchstart ? 'touchstart' : 'click';
...
//初始化事件
game.initEvent = function () {
    ...
    this.startBtn.on(this.eventType, this.start.bind(this));
    ...
};

給圖中的「開始遊戲」按鈕綁定了touchstart(click)事件,處理爲game.start()——開始遊戲


遊戲進行中的處理

這裏寫圖片描述

遊戲元素不多,有4個:得分、時間、暫停按鈕、裝方塊的盒子。

思路爲:

當遊戲開始時,等級默認爲0,等級爲0的方塊爲 2 x 2 放置,其餘等級n x n 由 levelMap肯定,當level超過數組長度時,取7.

game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7];

而後生成對應數字的方塊html,放進裝方塊的盒子,同時給每一個方塊生成顏色,其中一個不一樣,當點擊方塊時判斷是否選到不一樣,選對則晉級,選錯則遊戲結束。

開始講解代碼:

game.time = 60;     //遊戲時間
game.score = 0;     //得分
game.level = 0;     //等級
game.levelMap = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7]; // n x n 的方塊
game.colorDiff = [115, 100, 100, 85, 85, 85, 70, 70, 70, 70, 55, 55, 55, 55, 55, 40, 40, 40, 40, 40, 40, 25, 25, 25, 25, 25, 25, 25, 10, 10, 10, 10, 10, 10, 10, 10]; // 色差,等級越高,色差越小
game.diffIndex = 0; //不一樣顏色方塊的index
...
//開始遊戲(點擊開始遊戲就觸發這個函數)
game.start = function () {
    this.switchPage(2);   //換頁到遊戲界面
    this.render();        //render函數處理遊戲界面渲染,主要包括生成方塊,顏色等等
    this.timeCount();     //開啓計時器
};
//遊戲界面渲染
game.render = function () {
    /** * num 爲n * n 的方塊中的n,由等級決定,等級超過數組最大就取最後一個 * colorDiff 爲色差,由等級決定,等級超過數組最大就取最後一個 */
    var num = this.levelMap[this.level] ? 
                this.levelMap[this.level] : 
                this.levelMap[this.levelMap.length - 1],
        colorDiff = this.colorDiff[this.level] ? 
                        this.colorDiff[this.level] : 
                        this.colorDiff[this.colorDiff.length - 1],
        color = [],
        lvColor = [];
    //顯示分數
    this.scoreBox.html('得分:' + this.score);
    //顯示時間
    this.timeBox.html(this.time);
    //給box添加類名(主要是css須要,不一樣數量的方塊寬高應該不同,好比 2 * 2,每一個方塊爲50%)
    this.blockBox[0].className = 'lv' + num;
    //獲得不一樣顏色塊的index
    this.diffIndex = Math.floor(Math.random() * num * num);
    //獲取顏色
    color = this.getColor(257 - colorDiff);
    lvColor = this.getLvColor(color[0], colorDiff);
    //添加block
    var str = '';
    num *= num;
    for ( var i = 0; i < num; i++ ) {
        if ( i == this.diffIndex ) {
            str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
        } else {
            str += '<span style="background-color: ' + color[1] + ';"></span>';
        }
    };
    this.blockBox.html(str);
};
//獲得隨機顏色
game.getColor = function (max) {
    var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
    return [t, "rgb(" + t.join(",") + ")"];
};
//獲得不一樣的顏色
game.getLvColor = function (color, diff) {
    var r = [];
    r[0] = color[0] + diff;
    r[1] = color[1] + diff;
    r[2] = color[2] + diff;
    return [r, "rgb(" + r.join(",") + ")"];
};

思路不難,先知道方塊是n×n的佈局,而後在 n×n個方塊中隨機生成一個不一樣的方塊,記錄在diffIndex這個變量裏。

這裏說一下Math.randon()是生成[0,1)的函數,可能等於0,不會等於1,若是是想生成n之內的一個整數(不包括n),寫爲:

Math.floor(Math.randon() * n)

Math.floor()表示向下取整,即捨去小數位。

而後生成隨機顏色,全部方塊共有兩種顏色,一個方塊不一樣,其餘相同。

//獲得隨機顏色
game.getColor = function (max) {
    var t = [Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)];
    return [t, "rgb(" + t.join(",") + ")"];
};

這個函數返回一個數組,array(0)也是一個數組,保存了rgb的值,array(1)爲字符串,型如:」rgb(0,0,0)」。

render函數中是下面這樣的,緣由爲另外一個顏色是這個顏色加上色差獲得,這樣保證最大不超過256

color = this.getColor(257 - colorDiff);

另外一個顏色:

//獲得不一樣的顏色
game.getLvColor = function (color, diff) {
    var r = [];
    r[0] = color[0] + diff;
    r[1] = color[1] + diff;
    r[2] = color[2] + diff;
    return [r, "rgb(" + r.join(",") + ")"];
};

獲得了兩種顏色,就能夠給方塊添加:

//獲取顏色
color = this.getColor(257 - colorDiff);
lvColor = this.getLvColor(color[0], colorDiff);
//添加block
var str = '';
num *= num;
for ( var i = 0; i < num; i++ ) {
    if ( i == this.diffIndex ) {
        str += '<span style="background-color: ' + lvColor[1] + ';"></span>';
    } else {
        str += '<span style="background-color: ' + color[1] + ';"></span>';
    }
};
this.blockBox.html(str);

方塊生成後,天然想到點擊方塊要判斷是否正確,這裏使用事件委託的方式,將點擊事件綁定在方塊盒子上:

this.blockBox.on(this.eventType, this.clickBlock.bind(this));
//點擊方塊事件
game.clickBlock = function ( event ) {
    if ( event.target.tagName.toLowerCase() === 'span' ) {
        //選對了
        if ( $(event.target).index() == this.diffIndex ) {
            this.level++;
            this.score++;
            this.render();
        } else {
            this.over()
        }
    }
};

代碼結構一眼看去就瞭解什麼意思了,先判斷點的是否是方塊,若是是,獲得方塊的index,而後和diffIndex進行對比,看是否選對。

選對了就加level,加分數,從新渲染遊戲界面

選錯了就執行over()函數,遊戲結束。

講一下游戲開始後執行的定時器函數:

//計時器
game.timeCount = function () {
    var self = this;
    game.timer = setInterval(function(){
        self.time--;
        self.timeBox.html(self.time);
        if ( self.time == 0 ) {
            self.over.call(self);
        }
    }, 1000)
};

判斷是否時間到達0,是就執行over函數,否就繼續執行,減時間並顯示。

在遊戲界面中還有一個暫停按鈕:


暫停頁面

這裏寫圖片描述

this.pauseBtn.on(this.eventType, this.pause.bind(this));
//遊戲暫停處理
game.pause = function () {
    clearInterval(this.timer);
    this.switchPage(3);
};

很簡單,只是關閉定時器,而後換頁就行了

繼續遊戲的按鈕綁定continue函數

this.continueBtn.on(this.eventType, this.continue.bind(this));
//繼續遊戲
game.continue = function () {
    this.switchPage(2);
    this.timeCount();
};

換頁,再開啓定時器就好了

遊戲結束處理

這裏寫圖片描述

須要作的事情有:

一、顯示得分

二、初始化遊戲參數:score、level等等

三、點擊從新開始,從新開始遊戲

//遊戲結束處理
game.over = function () {
    this.switchPage(4);
    this.resultBox.html('總分:' + this.score);
    clearInterval(this.timer);
    this.time = 60;
    this.score = 0;
    this.level = 0;
};
this.restartBtn.on(this.eventType, this.start.bind(this));

到此遊戲講解完畢,再補充點css中用得比較多的東西:

一、讓width,height已知水平,垂直都居中顯示:

div-parent { position: relative; }

div { position: absolute; top: 50%; left: 50%; width: 300px; height: 200px; margin-left: -150px; margin-top: -100px; }

width和height未知的話,垂直居中須要用到css3的知識。

二、再來一個n*n方塊的css,這裏用2*2做爲例子:

.lv1 span { height: 50%; width: 50%; }

/* span做爲一個方塊 */
span { display: block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; /* box-sizing IE8+支持 */ float: left; position: relative; border: 5px solid #ddd; border-radius: 10px; cursor: pointer; }

box-sizing改變盒模型:

border-box:width = border + padding + 內容(IE6及之前瀏覽器默認)

content-box: width = 內容的寬度(現代瀏覽器默認)

相關文章
相關標籤/搜索