亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Vue3實(shí)現(xiàn)羊了個(gè)羊的算法

 更新時(shí)間:2022年09月21日 15:21:30   作者:老驥farmer  
這篇文章主要介紹了使用Vue3實(shí)現(xiàn)羊了個(gè)羊的算法,初始化的隨機(jī)位置算法,通過(guò)實(shí)例代碼介紹了計(jì)算偏移量的方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

這兩天社區(qū)很多羊了個(gè)羊的web實(shí)現(xiàn),雖然各種實(shí)現(xiàn)花里花哨,然而,并沒(méi)有一個(gè)一個(gè)jy能給他說(shuō)清楚到底怎么實(shí)現(xiàn)的,由于可怕的求知欲,自己來(lái)吧!

大綱

羊了個(gè)羊這個(gè)現(xiàn)象級(jí)游戲之所以能成功,不是因?yàn)樗?code>原神一樣,靠著質(zhì)量、體驗(yàn)、劇情你愛(ài)不釋手

他靠的是,讓你愛(ài)不釋手,人家玩的是營(yíng)銷(xiāo),玩的是人性,也許你壓根就過(guò)不了關(guān)!

他的技術(shù)實(shí)現(xiàn),其實(shí)相當(dāng)簡(jiǎn)單,在技術(shù)上從來(lái)沒(méi)有什么高深的東西,

果然,高深的技術(shù)總是顯得這么樸實(shí)無(wú)華!

最難的部分也就是算法了,我也大致的鉆研了一下,但是這個(gè)算法坦率的講不是我發(fā)明的, 我只是站在巨人的肩膀上

他的算法實(shí)現(xiàn)的難點(diǎn)我以為有四方面

  • 1、 初始化的隨機(jī)位置算法
  • 2、 檢查是否被覆算法
  • 3、 三連匹配算法
  • 4、隊(duì)列區(qū)排序算法

在線(xiàn)演示

https://code.juejin.cn/pen/7144922644788297735

初始化的隨機(jī)位置算法

在理解算法之前,我們先大致看元數(shù)據(jù)

他需要包含 一些必備的屬性, 默認(rèn)的覆蓋情況,是否被選中的狀態(tài),icon 圖標(biāo),icon 的唯一id x 坐標(biāo) y坐標(biāo)

const scene=({
      isCover: false, // 默認(rèn)都是沒(méi)有被覆蓋的
      status: 0,// 是否被選中的狀態(tài)
      icon,// 圖標(biāo)
      id: randomString(4), // 生成隨機(jī)id
      x: column * 100 + offset, //x 坐標(biāo)
      y: row * 100 + offset,// y坐標(biāo)
    }

然后再來(lái)說(shuō)算法,他的算法,本質(zhì)上其實(shí)就是限定的畫(huà)布內(nèi),隨機(jī)生成位置

在當(dāng)前這個(gè)算法中他使用一個(gè)8x8的網(wǎng)格中,生成方塊,然后利用隨機(jī)偏移量,來(lái)造成隨機(jī)堆疊的樣子

// 以下感謝大佬們提供的算法
const makeScene = (level) => {
  // 獲取當(dāng)前關(guān)卡
  const curLevel = Math.min(maxLevel, level);
  // 獲取當(dāng)前關(guān)卡應(yīng)該擁有的icon數(shù)量
  const iconPool = icons.slice(0, 2 * curLevel);
  // 算出偏移量范圍具體細(xì)節(jié)范圍
  const offsetPool = [0, 25, -25, 50, -50].slice(0, 1 + curLevel);
  //  最終的元數(shù)據(jù)數(shù)組
  const scene = [];
  // 確定范圍
  //在一般情下 translate 的偏移量,如果是百分比的話(huà),是按照自身的寬度或者高度去計(jì)算的,所以最大的偏移范圍是百分800%
  // 然后通過(guò)Math.random 會(huì)小于百分之八百
  // 所以就會(huì)形成當(dāng)前區(qū)間的隨機(jī)數(shù)
  const range = [
    [2, 6],
    [1, 6],
    [1, 7],
    [0, 7],
    [0, 8],
  ][Math.min(4, curLevel - 1)];
  const randomSet = (icon: string) => {
    // 求偏移量
    const offset = offsetPool[Math.floor(offsetPool.length * Math.random())];
    // 偏移求列數(shù)
    const row = range[0] + Math.floor((range[1] - range[0]) * Math.random());
    // 求偏移行數(shù)
    const column = range[0] + Math.floor((range[1] - range[0]) * Math.random());
    console.log(offset, row, column);
    // 生成元數(shù)據(jù)對(duì)象
    scene.push({
      isCover: false, // 默認(rèn)都是沒(méi)有被覆蓋的
      status: 0,// 是否被選中的狀態(tài)
      icon,// 圖標(biāo)
      id: randomString(4), // 生成隨機(jī)id
      x: column * 100 + offset, //x 坐標(biāo)
      y: row * 100 + offset,// y坐標(biāo)
    });
  };

  // 如果級(jí)別高了就加點(diǎn)icon 花哨一點(diǎn)
  let compareLevel = curLevel;
  while (compareLevel > 0) {
    iconPool.push(...iconPool.slice(0, Math.min(10, 2 * (compareLevel - 5))));
    compareLevel -= 5;
  }
  // 生成元數(shù)據(jù),初始狀態(tài)下 iconPool的內(nèi)容少生 隨著增加,就會(huì)越來(lái)越難
  for (const icon of iconPool) {
    for (let i = 0; i < 6; i++) {
      randomSet(icon);
    }
  }
  // 返回元數(shù)據(jù)
  return scene;
};

解釋一下, 我們?cè)诔跏蓟臅r(shí)候, 會(huì)生成一個(gè)范圍,來(lái)初始化 他的預(yù)計(jì)位置

  const range = [
    [2, 6],
    [1, 6],
    [1, 7],
    [0, 7],
    [0, 8],
  ][Math.min(4, curLevel - 1)];

range 最后的結(jié)果,就表示格子范圍,這里是為了跟關(guān)卡結(jié)合,在初始化的時(shí)候 由于圖標(biāo)少, 所以就會(huì)在 在8x8之內(nèi)的更小的格子

例如這樣:

當(dāng)關(guān)卡越來(lái)越多的時(shí)候就會(huì)如下圖:

以為在后面關(guān)卡的時(shí)候?qū)⑺械母褡訐螡M(mǎn)了為8x8

那么如何計(jì)算偏移量呢?

  const randomSet = (icon: string) => {
    // 求偏移量
    const offset = offsetPool[Math.floor(offsetPool.length * Math.random())];
    // 偏移求列數(shù)
    const row = range[0] + Math.floor((range[1] - range[0]) * Math.random());
    // 求偏移行數(shù)
    const column = range[0] + Math.floor((range[1] - range[0]) * Math.random());
    console.log(offset, row, column);
    // 生成元數(shù)據(jù)對(duì)象
    scene.push({
      isCover: false, // 默認(rèn)都是沒(méi)有被覆蓋的
      status: 0,// 是否被選中的狀態(tài)
      icon,// 圖標(biāo)
      id: randomString(4), // 生成隨機(jī)id
      x: column * 100 + offset, //x 坐標(biāo)
      y: row * 100 + offset,// y坐標(biāo)
    });
  };

其實(shí)偏移量的核心就是 Math.random這個(gè)函數(shù),來(lái)生成0-1的隨機(jī)數(shù),我們需要求 offset基礎(chǔ)偏移量 row列的偏移量 column行的偏移量

由于為了導(dǎo)致位置的總體差異,和細(xì)節(jié)差異,來(lái)達(dá)到符合預(yù)期的亂序效果,所以最終他生成的坐標(biāo)需要 基礎(chǔ)偏移和行列偏移來(lái)結(jié)合

檢查是否被覆算法

檢查是否被覆蓋算法其實(shí)本質(zhì)上來(lái)說(shuō) ,就是祖?zhèn)鞯?code>碰撞檢測(cè)算法

根據(jù)是否碰撞,來(lái)計(jì)算覆蓋情況

代碼如下:

// 檢查是否被覆蓋
const checkCover = (value) => {
  // 深拷貝一份
  const updateScene = value.slice();
  // 是否覆蓋算法
  // 遍歷所有的元數(shù)據(jù)
  // 雙重for循環(huán)來(lái)找到每個(gè)元素的覆蓋情況
  for (let i = 0; i < updateScene.length; i++) {
    // 當(dāng)前item對(duì)角坐標(biāo)
    const cur = updateScene[i];
    // 先假設(shè)他都不是覆蓋的
    cur.isCover = false;
    // 如果status 不為0 說(shuō)明已經(jīng)被選中了,不用再判斷了
    if (cur.status !== 0) continue;
    // 拿到坐標(biāo)
    const { x: x1, y: y1 } = cur;
    // 為了拿到他們的對(duì)角坐標(biāo),所以要加上100
    //之所以要加上100 是由于 他的總體是800% 也就是一個(gè)格子的換算寬度是100
    const x2 = x1 + 100,
      y2 = y1 + 100;
    // 第二個(gè)來(lái)循環(huán)來(lái)判斷他的覆蓋情況
    for (let j = i + 1; j < updateScene.length; j++) {
      const compare = updateScene[j];
      if (compare.status !== 0) continue;


      const { x, y } = compare;
      // 處理交集也就是選中情況
      // 兩區(qū)域有交集視為選中
      // 兩區(qū)域不重疊情況取反即為交集
      if (!(y + 100 <= y1 || y >= y2 || x + 100 <= x1 || x >= x2)) {
        // 由于后方出現(xiàn)的元素會(huì)覆蓋前方的元素,所以只要后方的元素被選中了,前方的元素就不用再判斷了
        // 又由于雙層循環(huán)第二層從j 開(kāi)始,所以不用擔(dān)心會(huì)重復(fù)判斷
        cur.isCover = true;
        break;
      }
    }
  }
  scene.value = updateScene;
};

碰撞檢測(cè)

所謂碰撞檢測(cè),就是計(jì)算兩個(gè)東西的坐標(biāo)有沒(méi)有重疊,也就是求交集

主要算法如下,就是比較他們的各個(gè)方向的位置

   function isButt(obj1,obj2){
         var l1=obj1.offsetLeft;
         var t1=obj1.offsetTop;
         var r1=l1+obj1.offsetWidth;
         var b1=t1+obj1.offsetHeight;
         var l2=obj2.offsetLeft;
         var t2=obj2.offsetTop;
         var r2=l2+obj2.offsetWidth;
         var b2=t2+obj2.offsetHeight;
       return!(r1<l2||b1<t2||r2<l1||b2<t1)
    }

覆蓋算法實(shí)現(xiàn)

覆蓋算法其實(shí)實(shí)現(xiàn)也非常簡(jiǎn)單,就是一個(gè)雙重for循環(huán) 來(lái)將每個(gè)方塊的位置做比較,做一個(gè)碰撞檢測(cè),從而能篩選出來(lái)被遮擋的方塊

值得注意的是

  • 1、j的值需要從i+1開(kāi)始,為了防止已經(jīng)比較過(guò)的方塊再次比較
  • 2、由于元數(shù)據(jù)的渲染,的后方物體天然的會(huì)遮擋前方物體,所以當(dāng)碰撞檢測(cè)成功之后是只需要遮擋前方方塊即可
 for (let i = 0; i < updateScene.length; i++) {
    // 第二個(gè)來(lái)循環(huán)來(lái)判斷他的覆蓋情況
    for (let j = i + 1; j < updateScene.length; j++) {
      // 執(zhí)行碰撞檢測(cè)
    }
  }

三連匹配算法

三連匹配其實(shí)相比于前兩點(diǎn),就非常簡(jiǎn)單了

我們只需要拿到相同的方塊的icon名, 湊夠三個(gè)直接改變方塊樣式即可

// 點(diǎn)擊item
const clickSymbol = async (idx: number) => {
  // 如果已經(jīng)完成了,就不處理
  if (finished.value || animating.value) return;
  // 拷貝一份Scene
  const symbol = scene.value[idx];
  // 覆蓋了和已經(jīng)在隊(duì)列里的也不處理
  if (symbol.isCover || symbol.status !== 0) return;
  //置為可以選中狀態(tài)
  symbol.status = 1;
  queue.value.push(symbol);
  // 制造動(dòng)畫(huà)效果中防止點(diǎn)擊
  animating.value = true;
  //三百毫秒的延遲
  await waitTimeout(300);
  // 拿到與他匹配的所有icon
  const filterSame = queue.value.filter((sb) => sb.icon === symbol.icon);

  // 選中的三個(gè)配對(duì)成功表示已經(jīng)是三連了
  if (filterSame.length === 3) {
    // 由于icon的類(lèi)型一樣,留下隊(duì)列中的不一樣的剩余內(nèi)容重新賦值
    queue.value = queue.value.filter((sb) => sb.icon !== symbol.icon);
    // 隱藏iocn,dom
    for (const sb of filterSame) {
      const find = scene.value.find((i) => i.id === sb.id);
      // 將他們的狀態(tài)變?yōu)? 通過(guò)opacity 屬性 來(lái)隱藏icon
      if (find) find.status = 2;
    }
  }

  // 當(dāng)格子沾滿(mǎn)了,那么久表示已經(jīng)失敗了
  if (queue.value.length === 7) {
    tipText.value = '失敗了'
    finished.value = true;
  }

  if (!scene.value.find((s) => s.status !== 2)) {
    // 如果完成所有關(guān)卡,那就過(guò)了所有關(guān)了
    if (level.value === maxLevel) {
      tipText.value = '完成挑戰(zhàn)';
      finished.value = true
      return;
    }
    //否則加一關(guān)
    level.value = level.value + 1;
    queue.value = []
    // 重新初始化
    checkCover(makeScene(level.value + 1));
  } else {
    // 處理覆蓋情況
    checkCover(scene.value);
  }
  // 動(dòng)畫(huà)結(jié)束
  animating.value = false;
};

以上代碼中,我們只需要 改變?cè)獢?shù)據(jù)的status的狀態(tài)值即可 ,然后再配合css的視覺(jué)效果,來(lái)達(dá)到消失的效果,其實(shí)dom 還是在頁(yè)面中,并沒(méi)有消失移除,因?yàn)樵獢?shù)據(jù)沒(méi)變

隊(duì)列區(qū)排序算法

在隊(duì)列中我們發(fā)現(xiàn)如果湊夠三個(gè)他需要排序,

比如說(shuō)在有一個(gè)叉子,就會(huì)排在米飯的前面然后消失

實(shí)現(xiàn)如下:

// 隊(duì)列區(qū)排序
watchEffect(() => {
  const cache = {};
  // 通過(guò)當(dāng)前的icon的標(biāo)識(shí),將相同的icon歸納到一塊
  // 方便后續(xù)排序
  for (const symbol of queue.value) {
    if (cache[symbol.icon]) {
      cache[symbol.icon].push(symbol);
    } else {
      cache[symbol.icon] = [symbol];
    }
  }
  const temp = [];
  for (const symbols of Object.values(cache)) {
    temp.push(...(symbols as any));
  }
  const updateSortedQueue = {};
  let x = 50;
  // 拿到更新后的隊(duì)列區(qū)數(shù)據(jù),計(jì)算權(quán)重
  for (const symbol of temp) {
    updateSortedQueue[symbol.id] = x;
    x += 100;
  }
  //賦值 ,這個(gè)是為了將選中的排序后的內(nèi)容移動(dòng)到隊(duì)列區(qū)
  sortedQueue.value = updateSortedQueue
  // 檢查覆蓋情況
  checkCover(scene.value);
})

他的實(shí)現(xiàn)原理其實(shí)就是利用緩存對(duì)隊(duì)列計(jì)算先后權(quán)重,從而計(jì)算他排序的位置,其實(shí)他的元數(shù)據(jù)或者選中順序并沒(méi)有變

只是在視覺(jué)上更改了css 的樣式

總結(jié)

到此這篇關(guān)于使用Vue3實(shí)現(xiàn)羊了個(gè)羊的算法的文章就介紹到這了,更多相關(guān)vue羊了個(gè)羊算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決vuex數(shù)據(jù)異步造成初始化的時(shí)候沒(méi)值報(bào)錯(cuò)問(wèn)題

    解決vuex數(shù)據(jù)異步造成初始化的時(shí)候沒(méi)值報(bào)錯(cuò)問(wèn)題

    今天小編大家分享一篇解決vuex數(shù)據(jù)異步造成初始化的時(shí)候沒(méi)值報(bào)錯(cuò)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • vue3+element-plus props中的變量使用 v-model 報(bào)錯(cuò)及解決方案

    vue3+element-plus props中的變量使用 v-model 報(bào)錯(cuò)及解決方案

    這篇文章主要介紹了vue3+element-plus props中的變量使用 v-model 報(bào)錯(cuò)及解決方案,prop 是單向數(shù)據(jù)流,這里只能用:model-value,不能用v-model,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • Vue Element Sortablejs實(shí)現(xiàn)表格列的拖拽案例詳解

    Vue Element Sortablejs實(shí)現(xiàn)表格列的拖拽案例詳解

    這篇文章主要介紹了Vue Element Sortablejs實(shí)現(xiàn)表格列的拖拽案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Vue3在css中使用js變量及其原理解讀

    Vue3在css中使用js變量及其原理解讀

    這篇文章主要介紹了Vue3在css中使用js變量及其原理解讀,結(jié)合實(shí)例代碼介紹了vue3中css使用script中定義的變量的方法,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • elementplus實(shí)現(xiàn)多級(jí)表格(最后一級(jí)展示圖片)

    elementplus實(shí)現(xiàn)多級(jí)表格(最后一級(jí)展示圖片)

    本文主要介紹了elementplus實(shí)現(xiàn)多級(jí)表格(最后一級(jí)展示圖片),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Vue組件通信方式(父?jìng)髯?、子傳父、兄弟通?

    Vue組件通信方式(父?jìng)髯?、子傳父、兄弟通?

    這篇文章主要介紹了Vue組件通信方式(父?jìng)髯?、子傳父、兄弟通?,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue.js select下拉框綁定和取值方法

    vue.js select下拉框綁定和取值方法

    下面小編就為大家分享一篇vue.js select下拉框綁定和取值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vuex刷新后數(shù)據(jù)丟失的解決方法

    vuex刷新后數(shù)據(jù)丟失的解決方法

    這篇文章主要給大家介紹了關(guān)于vuex刷新后數(shù)據(jù)丟失的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Vue框架和前后端開(kāi)發(fā)詳解

    Vue框架和前后端開(kāi)發(fā)詳解

    這篇文章主要為大家介紹了Vue框架和前后端開(kāi)發(fā),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-12-12
  • 關(guān)于vue的element-ui web端引入高德地圖并獲取經(jīng)緯度

    關(guān)于vue的element-ui web端引入高德地圖并獲取經(jīng)緯度

    這篇文章主要介紹了關(guān)于vue的element-ui web端引入高德地圖并獲取經(jīng)緯度,高德地圖首先要去申請(qǐng)key和密鑰,文中提供了部分實(shí)現(xiàn)代碼和解決思路,感興趣的朋友可以學(xué)習(xí)一下
    2023-04-04

最新評(píng)論