[360前端星計劃]BlackJack(21點)(純JS,附總部學習筆記)

[360前端星計劃]總部學習筆記(6/6)javascript

[360前端星計劃]詳情跳轉css

遊戲界面預覽

遊戲界面

目錄

一.遊戲介紹

1.起源

2.規則

3.技巧

二.遊戲設計

1.總體UI構思

2.素材採集

3.遊戲總規劃

三.代碼實現

0.編碼規範以及優化記錄

1.HTML文檔結構

2.CSS佈局與動畫

3.JavaScript功能模塊

四.遊戲測試(如下所列皆可正常運行遊戲)

1.PC端

2.移動端

五.番外篇

致謝

版權




一.遊戲介紹

1.起源

    21點又名黑傑克(英文:Blackjack) ,起源於法國,已流傳到世界各地。21點,是一種使用撲克牌玩的賭博遊戲。亦是惟一一種在賭埸中能夠在機率中打敗莊家的一種賭博遊戲。html

2.規則

  • 21點是一張牌面朝上(叫明牌),一張牌面朝下(叫暗牌);給本身發兩張牌,一張暗牌,一張明牌。
  • 玩家手中撲克點數的計算是:K、Q、J 和 10 牌都算做 10 點。
  • A 牌既可算做1 點也可算做11 點,由玩家本身決定。
  • 其他全部2 至9 牌均按其原面值計算。
  • 若是玩家前兩張牌是A 、10點牌,就擁有黑傑克(Blackjack);
  • 若是莊家沒有黑傑克,玩家就能贏得2倍的賭金(1賠2)。
  • 沒有黑傑克的玩家能夠繼續拿牌,能夠隨意要多少張。目的是儘可能往21點靠,靠得越近越好。
  • 若是全部的牌加起來超過21點,玩家就輸了--叫爆掉(Bust),遊戲隨之結束。
  • 若是玩家沒爆掉,又決定再也不要牌了,這時莊家就把他的那張暗牌打開來。
  • 通常到17點或17點以上再也不拿牌,但也有可能15到16點甚至12到13點就再也不拿牌或者18到19點繼續拿牌。(本遊戲採用1號電腦的邏輯爲達到16點便再也不拿牌)
  • 假如莊家爆掉了,那他就輸了.
  • 假如他沒爆掉,那麼你就與他比點數大小,大爲贏。同樣的點數爲平手。

3.技巧

  • 障眼法
    • 這種方法主要適合於閒家,並且在衆多玩家參與的時候適用。
    • 通常在閒家明牌是10點的時候,若是牌底是3~7點,通常拿到這種點數特別難受,若是要牌,有50%的機率會暴,由於閒家暴點是100%輸,不要牌可能也會輸,我暫且把它稱爲尷尬點數。這時候,閒家若是觀察到別的閒家點數都比較大,並且都不要牌的狀況下,能夠跟着不要。這樣一來,就會給莊家很大的壓力,覺得每一位閒家手中的牌都是比較大的點數,若是莊家一樣拿着尷尬點數,這種狀況只能逼着莊家要牌,很明瞭,無形中所用的這個障眼法是把風險轉移給了莊家,輸贏靠天定了,看哪一個運氣好了,若莊家爆了,則閒家贏。
  • 姜太公釣魚法
    • 這種方法主要適合於閒家,並且在衆多玩家參與的時候適用。
    • 通常在閒家明牌是10點的時候,若是牌底是3~7點,通常拿到這種點數特別難受,若是要牌,有50%的機率會暴,由於閒家暴點是100%輸,不要牌可能也會輸,我暫且把它稱爲尷尬點數。這時候,閒家若是觀察到別的閒家點數都比較大,並且都不要牌的狀況下,能夠跟着不要。這樣一來,就會給莊家很大的壓力,覺得每一位閒家手中的牌都是比較大的點數,若是莊家一樣拿着尷尬點數,這種狀況只能逼着莊家要牌,很明瞭,無形中所用的這個障眼法是把風險轉移給了莊家,輸贏靠天定了,看哪一個運氣好了,若莊家爆了,則閒家贏。
  • 補救法
    • 這種方法莊家閒家都適用。
    • 所謂補救,就是拿到的是前面所提到的尷尬點數,輸地可能性極大,在明知道牌點數就比對手點數小的狀況下,咱們只能要牌,由於不要也是輸,而要牌還有一線但願是贏,因此咱們能選擇的就是奔那一線但願,寄但願總比放棄但願好。

二.遊戲設計

1.總體UI構思

  • 背景:我認爲須要一個暗色的、非純色的背景。
  • 桌面:一張記憶中賭博賽事的標準綠色桌子,木質黃色的邊。
  • 按鈕:因而有了簡約風格的畫面,接下來我考慮將按鈕在桌面中。
  • logo:考慮到遊戲叫 21點,因此 應用了簡單卻不失表明性的帶陰影的透明21圖標。
  • 候牌:作兩個等牌區的底框(透明的淡色框),等待發牌,並標註玩家x號。
  • 積分:考慮到籌碼問題,因而在等牌區的一側作一個不太複雜的標註,響應總體簡約的風格。
  • 標題:放在桌面的正中央,遊戲主題的表示,BlackJack(21)足矣。
    • ⚠️不能貼頂,至少產生h1 { margin-top:20px;} 以保持美感。
    • 遊戲界面的色彩搭配靈感部分來源於其餘網絡撲克遊戲
    • (遊戲素材均來自網絡)

2.素材採集

遊戲logo
操做手勢

發牌堆、暗牌
背景
一副撲克牌13*4

3.遊戲總規劃

  • 利用html+css將設計好的總體的佈局+採集到的素材➡️應用到配置、搭建一個初始的頁面,後期再給予精確調整控制。
    • html基本文檔結構
    • css佈局
      根據遊戲的需求來編寫不一樣的css動畫js功能函數以貼近遊戲規則、加強遊戲體驗。
    • css動畫
      • 使用animation keyforms完成動畫:保證每次新局首發牌一人兩張,且1號電腦玩家的第二張牌爲暗牌,後再發牌則進行一人一張動畫。
      • 配合js控制撲克牌發出先後的顯隱,特別是亮牌後1號電腦暗牌的顯示。
  • JavaScript各功能函數設計
    • 實現actions系列按鈕的功能
      • 新局 sendCard()
      • 要牌 sendCard()第二次開始
      • 亮牌 showSend()
      • 退出遊戲 exit()
    • 初始化整副牌的數組,即洗牌,給52個數字從新分配撲克牌的值(花色,數字)
    • 本遊戲設定只有一副牌,即在一個length爲52的數組中抽取牌進行遊戲,也就是說每次新局開始便初始化,保證其有52張牌的相應機率來進行遊戲,屬於不放回遊戲。
    • 每張牌的選取靠js配合for控制量i對每張牌的座標進行計算以保證每次新局初始化時均可以在random的控制下以tmp結果隨機選取一張牌(剩餘的牌堆中)。
    • 實現發牌後css動畫結束前 ,計算相應偏移位置並自動添加html內容,使得動畫結束之時,添加落牌恰好銜接,其中使用了for中的i控制外加settimeout實現單次計時。
  • 本遊戲規則的邏輯設定聲明:
    • 每次開局一人兩張牌,後每次要牌均爲單張發牌動畫。
    • 1號電腦的設定是發牌小於16時,則在2號玩家點擊要牌的同時加一張牌。若大於16,則再也不要牌。2號玩家則自行判斷,任意要牌。
    • Ace牌的1或11,在亮牌時進行智能判斷:
      • 若是按11算不會爆牌則會按照11計算
      • 若是按照11算會爆牌則會按照1來計算
    • 黑傑克:新局初次發牌兩張爲1+10
      • 若爲黑傑克,且莊家沒有黑傑克時,則獲勝時籌碼加倍。
      • 莊家設定爲一號電腦。
    • 若是雙方有一方拿牌爆掉,便斷定另外一方爲獲勝方。
    • 若是都沒有在拿牌過程當中爆掉,則正常比對雙方擁有的點數,小於21點且大的一方:獲勝。
    • Actions操做系列按鈕說明:(從左到右依次)
      • 手掌🖐️爲新局
      • 食指☝️要加牌
      • 兩張牌交換爲兩牌
      • 21點的logo爲退出遊戲
    • 本遊戲 點擊發牌區的牌效果=點擊 新局+要牌按鈕

三.代碼實現

0.編碼規範以及優化記錄

HTML:
    標準的html結構,meta標籤等
    思考佈局方式,合理的結構
    避免使用行內樣式
    事件儘可能採用事件綁定
    頁面樣式儘可能處理的精緻一些(優先級以功能爲主,這些次之)
    本次做品,時間和質量的比重,質量的權重高,因此要優先提高質量

CSS:
    1. 頁面單獨引用xxxx.css
    2. 功能樣式能夠分類(就算不必分頁、也能夠按照功能寫在一塊兒),如:
        2.1 公共樣式:包括字體、h1~h6 p div等會用到的一些樣式
        2.2 佈局樣式:就是佈局相關的css寫在一塊兒,主要處理佈局、結構
        2.3 功能樣式:各個子功能塊樣式,如:桌面、操做圖標,基本思想是按功能分塊
        2.4 編碼相關:儘量少使用id;最好使用class,且其命名有功能性
        (用於綁定事件)
        樣式性(用戶寫樣式),命名語義話(能表達出你這個樣式是幹什麼用的,
        儘可能避免寫flash一、flash2...)(已經改爲sendCardTo)
    動畫相關樣式能夠單獨寫在一個文件裏,進行引用
    手機上不居中可能也是這個緣由,另外手機上能夠設置meta的viewport.
    按鈕問題:能夠給其父元素一個position:relative;
    而後操做元素總體使用position:absolute;bottom:xx;進行定位
    若是手機上要求訪問效果和PC相同,能夠考慮樣式作兩套(根據時間狀況看吧)
        
Js:
     格式得當。
     儘可能簡化代碼。
     簡單封裝一下dom操做:獲取dom、addClass、removeClass、事件綁定等。
     合理的註釋,每一個方法都得有註釋。
     函數命名按照功能命名。

1.HTML文檔結構

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <link rel="stylesheet" href="">
</head>
<body>
    <header></header>
    <section>
        <div></div>
        …… …… …… ……
        <div></div>
    </section>
    <footer></footer>
    <script></script>
</body>
</html>
  • 本結構由html5中語義化標籤構成,使得文檔易讀、結構清晰。
  • 細節則根據題意和規則設計來完善

2.CSS佈局與動畫

  • 動畫
    • 設定路徑實現簡單的翻轉發牌animation動畫
/*繪製透明的綠色桌面以及木質桌面邊緣*/
@keyframes sendCardTo1 
{
    0% { right:-450px;top: 30px; transform: rotate(240deg); }
    100% { right: 0; transform: rotate(0); }
}
@keyframes sendCardTo2 
{
    0% { right:-220px; top:30px; transform: rotate(240deg); }
    100% { right: 0; top:0; transform: rotate(0); }
}
@-moz-keyframes sendCardTo1 /* Firefox */
{sendCardTo1
    0% { right:-450px;top: 30px; transform: rotate(240deg); }
    100% { right: 0; transform: rotate(0); }
}
@-moz-keyframes sendCardTo2 /* Firefox */
{
    0% { right:-220px; top:30px; transform: rotate(240deg); }
    100% { right: 0; top:0; transform: rotate(0); }
}
@-webkit-keyframes sendCardTo1 /* Safari 和 Chrome */
{
    0% { right:-450px;top: 30px; transform: rotate(240deg); }
    100% { right: 0; transform: rotate(0); }
}
@-webkit-keyframes sendCardTo2 /* Safari 和 Chrome */
{
    0% { right:-220px; top:30px; transform: rotate(240deg); }
    100% { right: 0; top:0; transform: rotate(0); }
}
@-o-keyframes sendCardTo1 /* Opera */
{
    0% { right:-450px;top: 30px; transform: rotate(240deg); }
    100% { right: 0; transform: rotate(0); }
}
@-o-keyframes sendCardTo2 /* Opera */
{
    0% { right:-220px; top:30px; transform: rotate(240deg); }
    100% { right: 0; top:0; transform: rotate(0); }
}
  • 佈局
    • 繪製桌面主體以及發牌區牌及牌堆
    • 控制各個部件定位,樣式
    • 調整至能夠正常在移動端(手機端)進行遊戲
.circle {
    background: rgba(7,121,5,0.7);
    border-radius: 50%;
    position: absolute;
    top: -460px;
    left: 145px;
    width: 900px;
    height: 900px;
    border: 30px solid rgba(85,72,4,0.9);
}
/*發牌區動畫的出發點以及牌*/
.send {
    position: absolute;
    top: 531px;
    right: 50px;
    height: 85px;
    width: 60px;
    -ms-transform: rotate(35deg); /* IE 9 */
    -webkit-transform: rotate(35deg); /* Safari and Chrome */
    -o-transform: rotate(35deg); /* Opera */
    -moz-transform: rotate(35deg); /* Firefox */
    transform: rotate(35deg);
    background-color: white;
    z-index: 2;
    border-top: 3px solid white;
    border-right: 2px solid white;
}

3.JavaScript功能模塊

  • sendCard():
    • 利用num來實現第一次發牌爲一人兩張,第二次開始皆爲一張。
    • 使用setTimeout函數來實現一次性的定時操做:使得在動畫結束後的已設定的時刻,依次調用realSend()函數以銜接發牌動做。
    • 實現了防治未開始遊戲便點擊亮牌的錯誤邏輯:新遊戲開始調用sendCard(id)則begain++,若未執行此處,則要牌和亮牌均沒法執行。
//此爲核心代碼,重複部分已省去,詳情見源代碼。
var num = 1;
    if (count[1].count == 0) {
        num = 2;
        //AI
        for (var i = 0; i < num; ++i) {
            setTimeout(function() {realSend(1)}, i * 100);
            setTimeout(function() {
                var n = document.getElementById('p_1')
                .getElementsByClassName('send-card1');
                if (n.length > 0)
                    n[0].classList.remove('send-card1');
            }, i * 100 + 800);
        }
    }
  • showCard():
    • 實現了防止未開始遊戲便點擊亮牌的錯誤邏輯
    • 實現了亮牌後的一系列函數動做:
    • getMax()、alert(count[id].sum)、lose()(已分別註釋)
    • 以及根據結果判斷輸贏並彈出提示。
//此爲核心代碼,重複部分已省去,詳情見源代碼。
var begain = 0;//防止沒開始遊戲直接點擊要牌和亮牌的按鈕

function showCard() {
    if (begain == 0) {} else {
        var hidden = document.getElementById('p_1')
        .getElementsByClassName('card-hidden')[0];
        if (typeof(hidden) != "undefined")
            hidden.result();
        if (over)
            return;
        count[1].sum = getMax(1);
        count[2].sum = getMax(2);
         … … … …
        if(){alert("… …"); }else{alert("… …"); };
}
  • realSend()
    • 經過getPorker()、getPorkerPos()得到初始撲克牌位置真實發牌.
    • 並進行相關的dom操做html以完成真實發牌動做。
    • 若是一開始兩張牌爲1和10則爲黑傑克。
    • 若是2號玩家擁有黑傑克而莊家沒有則籌碼翻倍。
    • 根據count[id].sum > 21與否對lose()進行傳遞id以得到相應提示。
if (id == 1 && count[1].count == 1) {
        /* 莊家第二章暗牌 經過屬性k, v來實現明牌和計算 */
        newNode.className = "send-card" + id + " card-hidden";
        newNode.setAttribute('k', pos);
        newNode.result = function() {
            this.className = "card";
            this.style.backgroundPosition = 
            this.getAttribute('k');
        }
    } else {
        newNode.className = "send-card" + id + " card";
        newNode.style.backgroundPosition = pos;
    }
    if (count[id].count == 1)
        newNode.setAttribute('v', card.value);
    node.appendChild(newNode);

    ++count[id].count;
    /* 對A單獨處理 */
    if (card.value != 1) {
        if (card.value > 10)
            count[id].sum += 10;
        else
            count[id].sum += card.value;
    } else ++count[id].A;

    var ai = count[1];
    var pl = count[2];
    if (pl.A == 1 && pl.count == 2 && pl.sum == 10)
    //若是一開始兩張牌爲1和10則爲黑傑克。
        blackjack = 1;
    if (blackjack == 
    1 && ai.A != 1 && ai.count != 2 && ai.sum != 10)
        scale = 2;   
        //若是2號玩家擁有黑傑克而莊家沒有則籌碼翻倍。

    /* 先斷定是否已經結束 不然調用機器人函數 */
    if (count[id].sum > 21)
        lose(id);
    else if (count[id].sum + count[id].A > 21)
        lose(id);
    else if (id != 1 && count[2].count > 2)
        AI();
  • getPorker()
    • 抽牌函數。
    • 每次從開局時定義好的52個數的數組中不放回(porker.pop();)抽牌。
    • 返回tmp關聯數組供getPorkerPos調用。
  • getPorkerPos()
    • 接受傳入的tmp參數以獲取背景座標
function getPorkerPos(tmp) {
    // console.log(tmp.value);
    return porkerPos[tmp.suit.toString()
     + tmp.value.toString()];
}
  • getMax()
    • 在sendCard中調用,爲的是實現每次傳入id值算總和時智能斷定將A算做1或者11,得到最大的優點。
    • 若是把A算做11大於21,則將其算爲1,不然,算11。
    • 隨後返回sum。
  • lose()
  • 接受由realCard()傳入的id參數,以銜接彈窗提示判斷輸贏。
  • 根據不一樣狀況,編寫不一樣的獲勝提示,以二號玩家爲操做玩家的角度提示。前端

  • init()
    • 初始化遊戲,將候牌區的清空並替換成玩家編號提示。
    • 重置blackjack,scale,over值。
  • AI()
    • 函數功能:當sendCard()觸發AI執行邏輯:
    • 若1號電腦拿牌總和小於16或者A牌通過getMax()智能處理後依舊小於16時,執行realSend(1)以繼續要牌,這是一個智能判斷,增長了遊戲的可玩性。
    • 同時配合動畫刪除發牌區中的待發牌,而後一張隨機抽取的牌顯示在相應的位置。
function AI() {
    if (noneed)
        return;
    if (count[1].sum + count[1].A < 16 || getMax(1) < 16) {
        realSend(1);
        setTimeout(function() {
            var n = document.getElementById('p_1')
            .getElementsByClassName('send-card1');
            if (n.length > 0)
                n[0].classList.remove('send-card1');
        }, 800);
    } else
        noneed = 1;
}
  • DOM操做實現Actions按鈕及發牌堆首張牌的點擊功能函數的事件綁定:
// 給[btnName]按鈕 添加fn()功能併發牌功能
function addFn(btnName,fn) {
var btnName = document.getElementById("btnName");
    btnName.onclick = function() {
        if (begain == 0) {} else {
            fn();
        }
    }
}

四.遊戲測試(如下所列皆可正常運行遊戲)

1.PC端

  • Mac os x
    • chrome
    • firefox
    • safari
    • IE11
    • Edge
  • Windows 10
    • chrome
    • firefox
    • safari
    • IE11
    • Edge

2.移動端

  • Android:5.1
    • 自帶瀏覽器
  • ios:9.3
    • Safari

五.番外篇

異常:若遇到任何問題致使沒法正常瀏覽源代碼

  • 請您及時與我聯繫
    • 手機號:15594980508
    • 郵箱:451323138@qq.com
  • 您也能夠訪問個人我的小站進行測試下載:
  • 同時這份產品文檔也將置頂在個人技術博客之中:

致謝:

感謝北京奇虎360能夠給我此次展現本身的機會,不管結果如何。

版權:

本遊戲僅爲奇虎360公司前端星計劃編寫,任何人未徵得本人贊成
以前請勿使用本代碼做商業用途。


[360前端星計劃]總部學習筆記(6/6)html5

相關文章
相關標籤/搜索