<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          純前端實現(xiàn)「羊了個羊」小游戲 ……

          共 4668字,需瀏覽 10分鐘

           ·

          2022-10-28 04:12


          作者:QCY

          https://juejin.cn/post/7143897892531486727

          背景

          最近簡單的「羊了個羊」小游戲火到出圈,據(jù)說狂賺幾百幾千萬。這么弱智的玩意,即便是前端,我看也行!

          最終成果

          游戲本體

          如果一直白屏可以換這個地址 https://1enozc.csb.app/

          地圖模擬

          游戲本體長這樣

          可以很明顯的觀察到,卡片是以 1/4 為單位排列的

          1. 單層

          假設有這種布局,模擬成二維數(shù)組應該如下表示,每個格子就是一個數(shù)字元素

          [
              [0, 0, 1, 0, 0, 0
          ],
              [1, 0, 0, 0, 1, 0],
              [0, 0, 0, 0, 0, 0],
          ]

          2. 多層

          [
              // 第1層
              [
                  [1, 0, 0, 0, 1, 0
          ],
                  [0, 0, 0, 0, 0, 0],
             [1, 0, 0, 0, 1, 0],
             [0, 0, 0, 0, 0, 0],
              ],
              // 第2層
              [
             [0, 0, 0, 0, 0, 0
          ],
                  [0, 1, 0, 1, 0, 0],
             [0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0],
              ],
          ]

          地圖生成

          1. 基礎生成

          最基礎的地圖只關乎當前層,假設當前需要判定是否放置卡片的坐標為 [i, j],那么下面四個位置就不能存在卡片,否則就會出現(xiàn)同層卡片重疊

          • [i-1,j] != 1
          • [i,j-1] != 1
          • [i-1, j-1] ! = 1
          • [i-1, j+1] ! = 1

          同時我們加入一個隨機系數(shù),保證每次生成的地圖不同

          • Math.random() < 0.3 === true 的時候該位置才放置卡片

          2. 優(yōu)化地圖

          以一層為例,按上面的邏輯只能生成最簡單的地圖,實際我們觀察游戲,會發(fā)現(xiàn)卡片的放置是有一定規(guī)律的:

          • 左右對稱
          • 從頂層到底層越來越往中心聚集,卡片越來越少
          • 上一層不會完全覆蓋下一層

          加上這兩點優(yōu)化之后,地圖應該如下展示:

          頂層

          底層

          3. 卡片渲染

          每次位置和隨機數(shù)判定合格,我們應該實際放置一張卡片,一個實際的 dom。然后根據(jù)卡片的 x、y、z、寬高 值設置實際位置

          const style = {
          position: "absolute",
          top: (y * CardItem.height) / 2 + offset + "px",
          left: (x * CardItem.width) / 2 + offset + "px",
          width: CardItem.width + "px",
          height: CardItem.height + "px",
          }

          覆蓋關系

          我們可以先按一層的大小初始化一個處理遮擋用的二維數(shù)組 coverMap,然后在之前生成的游戲地圖上,從最后一層往第一層遍歷。

          [
              // 第1層
              [
             [1, 0, 0, 0, 1, 0
          ],
                  [0, 0, 0, 0, 0, 0],
             [1, 0, 0, 0, 1, 0],
             [0, 0, 0, 0, 0, 0],
              ],
              // 第2層
              [
             [0, 0, 0, 0, 0, 0
          ],
                  [0, 1, 0, 1, 0, 0],
             [0, 0, 0, 0, 0, 0],
             [0, 0, 0, 0, 0, 0],
              ],
          ]

          先遍歷第二層,發(fā)現(xiàn) [1,1] 位置有卡片(由于是最上層可以先不考慮本身被遮擋的情況)所以我們把 coverMap 的對應 4 個坐標置為 1,第 [1,4] 位置的卡片也一樣處理。

          處理完頂層之后的 coverMap 結果如下

          const coverMap = [
              [0, 0, 0, 0, 0, 0],
              [0, 1, 1, 1, 1, 0],
              [0, 1, 1, 1, 1, 0],
              [0, 0, 0, 0, 0, 0],
          ]

          第二次(底層)遍歷到 [0,0] 位置發(fā)現(xiàn)有卡片,并且實際會占據(jù):

          • [0,0]
          • [0,1]
          • [1,0]
          • [1,1]

          而其中 [1,1] 位置,是被遮擋的,所以這張卡片也應該被判定成遮擋狀態(tài)。依次處理完這一層所有卡片,同時遮擋數(shù)組更新

          const coverMap = [
              [1, 1, 0, 0, 1, 1],
              [1, 1, 1, 1, 1, 1],
              [1, 1, 1, 1, 1, 1],
              [1, 1, 0, 0, 1, 1],
          ]

          填充數(shù)據(jù)

          整改游戲的核心邏輯是 pending 區(qū)域存在 3 個同樣圖案的卡片時會消除。所以我們有兩個關鍵點要注意

          1. 保證卡片是 3 的倍數(shù)

          之前都是用 0、1 代指卡片,實際之前設置卡片的時候,我們可以新建 CardItem 類的實例,每個卡片實例會記錄自己的位置、樣式、是否被覆蓋等狀況。并且我們可以用一個 cardList 數(shù)組保存下這些實例

          并且在地圖生成完之后,根據(jù)數(shù)組數(shù)量除 3 的余數(shù),從前開始刪除對應數(shù)量的卡片

          可以想想為什么不從后面刪~

          2. 填充卡片類型

          我們需要隨機的把指定種類的卡片類型, 3 的倍數(shù)填充到現(xiàn)有卡片中去

          隨機

          創(chuàng)建一個新數(shù)組,并且隨機交換順序即可

          const tempList = [...this.cardList];
          const listLength = tempList.length;
          for (let i = 0; i < listLength; i++) {
          const j = Math.ceil(Math.random() * listLength);
          const tempItem = tempList[i];
          tempList[i] = tempList[j];
          tempList[j] = tempItem;
          }

          填充

          假設有 cardType 種類型的卡片,那么按 3 張重復填充即可

          for (let i = 0; i < listLength; i++) {
          const item = tempList[i];
          item.setVal(Math.floor(i / 3) % this.cardType);
          }

          點擊交互

          1. 是否可以點擊

          只有頂層可以被點擊,我們之前已經(jīng)判定過卡片是否被覆蓋的邏輯,做對應處理即可。一個簡單的方法是給被覆蓋的卡片設置一個特殊 style

          .covered-item {
          pointer-event: none;
          }

          這樣對應卡片上的任何事件都不會生效

          2. 點擊卡片

          點擊到最上層的卡片之后,我們按如下步驟處理:

          1. 把點擊到的卡片實例 push 到暫存數(shù)組 pendingList

          2. 把卡片實例從 cardMapcardList 中去除

          3. pendingList遍歷

            1. 如果 pendingList 中存在 3 張相同的卡片,則消除這 3 張卡片
            2. 如果不存在,且pendingList 中卡片數(shù)為 7,游戲結束 。本局失敗
            3. 如果 cardList 中的卡片數(shù)量為 0,游戲結束。本局成功

          總結

          到這一步,整個游戲的基礎框架就已經(jīng)搭建好了。剩下的難點還有

          • 道具的實現(xiàn)
            • 暫存道具
            • 隨機道具
            • 撤銷道具
          • 動效的實現(xiàn)
            • 從排堆進入 pendding 區(qū)域
            • 從 pendding 區(qū)域進入暫存區(qū)
            • 使用隨機道具時候的動畫
            • 集齊 3 個卡片時候的消除動畫
          • 樣式美化

          這些基本屬于錦上添花了,感興趣的同學可以自行探索一下。提供的實時代碼里基本已經(jīng)實現(xiàn)了大部分.


          最后,再給大家推薦我之前寫的10萬字Springboot經(jīng)典學習筆記,在Java開發(fā)寶典里回復:筆記,即可領取。
          點贊是最大的支持 

          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美精品性爱视频 | 中国黄色学生妹一级片 | 美女网站17禁入 | 亚州无码中文字幕日韩AV | 亚洲中文字幕在线免费观看视频 |