欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于vite2+vue3制作個(gè)招財(cái)貓游戲

 更新時(shí)間:2022年05月26日 15:34:20   作者:jsmask  
端午將至,大家都開(kāi)始吃粽子了么?本文將用vite2與vue3開(kāi)發(fā)出一個(gè)招財(cái)貓小游戲,在圖案不停滾動(dòng)的同時(shí)選出可以轉(zhuǎn)出不同的素材最終得到粽子獎(jiǎng)勵(lì),康康你能用多少次才會(huì)轉(zhuǎn)出自己喜愛(ài)口味的粽子吧

介紹

端午將至,大家都開(kāi)始吃粽子了么,你是喜歡吃北方的甜的紅棗粽?還是南方的大肉粽呢?

本期我們將使用vite2與vue3開(kāi)發(fā)出一個(gè)招財(cái)貓小游戲,通過(guò)考驗(yàn)眼力和預(yù)判能力,在圖案不停滾動(dòng)的同時(shí)選出可以轉(zhuǎn)出不同的素材最終得到粽子獎(jiǎng)勵(lì),康康你能用多少次才會(huì)轉(zhuǎn)出自己喜愛(ài)口味的粽子吧~

演示

預(yù)覽地址:jsmask.gitee.io/dwgame_laohuji/

正文

游戲分析

在開(kāi)發(fā)之前,我們要想好游戲設(shè)計(jì)和規(guī)則是如何,才能進(jìn)行往下進(jìn)行。通過(guò)上圖的演示和規(guī)則介紹,我們大致可以了解游戲流程了。

然后,根據(jù)了解的流程,進(jìn)行拆解,接下來(lái)我們主要會(huì)講解這些問(wèn)題:

  • 招財(cái)貓css3幀動(dòng)畫(huà)。
  • 圖案條帶中的素材在vite2的批量加載。
  • 老虎機(jī)圖案自定義條帶生成。
  • 老虎機(jī)無(wú)限滾動(dòng)。
  • 讓老虎機(jī)停止并且獲取抽獎(jiǎng)碼。
  • 獲得粽子后的紙屑飛舞效果的實(shí)現(xiàn)。

招財(cái)動(dòng)畫(huà)

下圖是本期用的所有素材,招財(cái)貓招手的是由四張圖拼湊而成的,用了一些在線的雪碧圖生成工具。在里面我們會(huì)得到每張圖對(duì)應(yīng)的 background-position , 最后再用 animation 來(lái)完成這個(gè)幀動(dòng)畫(huà)。其中,animation-timing-function:steps(1, end) 是幀動(dòng)畫(huà)實(shí)現(xiàn)的核心,steps() 函數(shù)符號(hào)定義了一個(gè)階梯函數(shù),將輸出值的域劃分為等距階梯。第一個(gè)值是需要傳入正數(shù),表示等距的數(shù),而后一個(gè)表示插值的位置。

.cat {
  width: 574px;
  height: 630px;
  margin: 0px auto;
  position: relative;
  background-image: url("../assets/image/cat.png");
  background-position: -10px -10px;
  &.active {
    animation: play-game 0.64s steps(1, end) infinite;
  }
  @keyframes play-game {
    0% {
      background-position: -10px -10px;
    }
    33% {
      background-position: -604px -10px;
    }
    66% {
      background-position: -1198px -10px;
    }
    100% {
      background-position: -10px -660px;
    }
  }
}

素材加載

我們后面需要通過(guò)canvas合成條帶,所以要先加載出需要轉(zhuǎn)出的圖案來(lái)。

按照原始的方案來(lái),我們要手寫(xiě)好多圖片資源文件的引入,所以十分麻煩。

import item0 from "../assets/image/item_0.png"
import item1 from "../assets/image/item_1.png"
import item2 from "../assets/image/item_2.png"
// ...more
import item9 from "../assets/image/item_9.png"

但是,Vite 中提供了 import.meta.glob 的語(yǔ)法糖來(lái)解決這種批量導(dǎo)入的問(wèn)題,一次性加載出這些圖片文件來(lái)。

const imgs = import.meta.globEager("../assets/image/item_*.png");

let num = Object.keys(imgs).length;
let items = Object.values(imgs).map((mod) => {
  let img = new Image();
  img.onload = () => --num <= 0 && initGame();
  img.src = mod.default;
  return img;
});

當(dāng)然我們這里用 import.meta.globEager 來(lái)可以同步加載這些資源。

條帶生成

所謂的條帶,就是老虎機(jī)中滾動(dòng)的背景圖,不停改變 backgroundPositionY 來(lái)實(shí)現(xiàn)滾動(dòng)效果,是老虎機(jī)的核心,所使用到的條帶自然就是重中之重,但在我們平時(shí)開(kāi)發(fā)條帶一般都是設(shè)計(jì)給的圖片,但經(jīng)常替換圖片后又要重新問(wèn)他們要新圖甚是麻煩。所以,這里我想用 canvas 把剛才的那十張圖案拼接起來(lái),形成條帶供我們使用。上一步,我們已經(jīng)把資源加載完成了,接下來(lái),可以需要寫(xiě)一個(gè) createBackgroundImage 函數(shù)。

function createBackgroundImage({items = [], w = 45, h = 60, size = 40,test=false}) {
  let canvas = document.createElement("canvas");
  let ctx = canvas.getContext("2d");
  canvas.width = ctx.width = w;
  canvas.height = ctx.height = h * items.length;
  let BackgroundImage = [...items];
  BackgroundImage.forEach((img, i) => {
    ctx.save();
    ctx.drawImage(img, (w - size) / 2, (h - size) / 2 + h * i, size, size);
    if(test){
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.font = "bold 36px Baloo Bhaijaan";
      ctx.fillText(i, w / 2, h * i + h / 2 + 5, w);
    }
    ctx.restore();
  });
  return convertCanvasToImage(canvas);
}

function convertCanvasToImage(canvas) {
  var image = new Image();
  image.src = canvas.toDataURL("image/png");
  return image;
}

export default createBackgroundImage;

這里我們不光可以傳入資源數(shù)組,而且可以傳入塊的寬和高,還有圖案的大小,為了方便測(cè)試后面驗(yàn)證開(kāi)獎(jiǎng)碼的正確性,加入 test 字段,如果開(kāi)啟,則會(huì)繪制上對(duì)應(yīng)的數(shù)字編號(hào)。

無(wú)限滾動(dòng)

當(dāng)我們點(diǎn)擊開(kāi)始游戲按鈕后,剛才生成出的條帶就會(huì)不停的改變 backgroundPositionY ,那有什么好辦法可以輕松控制這件事呢?

這里我推薦使用anime.js ,它一個(gè)功能強(qiáng)大且輕量級(jí)的 JavaScript 動(dòng)畫(huà)庫(kù)。

# NPM
npm i animejs -S
# YARN
yarn add animejs
# PNPM
pnpm i animejs -S
<ul class="content">
    <li
        ref="block"
        v-for="(item, index) in 3"
        :key="index"
        :style="{ backgroundImage: `url(${backgroundImage.src})` }"
        >
        <button :disabled="stops[index]" @click="handleStop(index)">
            Stop
        </button>
    </li>
</ul>
import anime from "animejs";
function play() {
  if (isActive.value) return false;
  isActive.value = true;
  count.value += 1;
  block.value.forEach((el, index) => {
    setTimeout(() => {
      stops.value[index] = false;
      let y = parseInt(el.style.backgroundPositionY || "0", 10);
      animes.value[index] = anime({
        targets: el,
        backgroundPositionY: [h / 2, h * items.length + h / 2],
        loop: true, // 循環(huán)播放
        direction: "normal", // 方向
        easing: "linear", // 時(shí)間曲線
        duration: 1200, // 播放時(shí)間
        autoplay: true, // 是否立即播放
      });
    }, index * 240);
  });
}

play 方法時(shí),我們獲取當(dāng)綁定好條帶的元素塊,通過(guò) animejsbackgroundPositionY 屬性設(shè)置一個(gè)數(shù)組,這個(gè)數(shù)組第0位代表起始狀態(tài),第1位代表要到達(dá)的狀態(tài)。然后把 loop 屬性設(shè)置 true 。那么一個(gè)簡(jiǎn)單的條帶無(wú)限滾動(dòng)就完成了。

中獎(jiǎng)判定

function handleStop(index) {
  stops.value[index] = true;
  let el = block.value[index];
  let y = parseInt(el.style.backgroundPositionY || "0", 10);
  animes.value[index].remove(el);
  let n = Math.round((y - h / 2) / h);
  el.style.backgroundPositionY = n * h + h / 2 + "px";
  giftCode.value[index] = (10 - n) % 10;
  if (stops.value.find((item) => !item) === undefined) {
    getResult();
  }
}

當(dāng)我們每按停一個(gè)時(shí),我們會(huì)迅速移除對(duì)應(yīng)元素 animejs 動(dòng)畫(huà),計(jì)算并賦值給最數(shù)值最接近的坐標(biāo)點(diǎn)。然后獲取到其對(duì)應(yīng)的數(shù)字編號(hào)存起來(lái)形成抽獎(jiǎng)碼數(shù)組,當(dāng)三個(gè)全部停止時(shí),會(huì)調(diào)用 getResult 方法來(lái)根據(jù)剛才得到的抽獎(jiǎng)碼來(lái)開(kāi)獎(jiǎng)。

const giftData = [
    {
        name: "紅棗粽",
        score: 100,
        show: true,
        type:1,
        value: ["012", "025", "126", "256"],
    },
    // ...
]
function getResult() {
  let str = giftCode.value.sort().join("");
  let _obj = giftData.find((item) => item.value.includes(str));
  if (!_obj) return (isActive.value = false);
  if (_obj.show) {
    giftObj.value = _obj;
    ruleShow.value = false;
    giftShow.value = true;
  } else {
    confetti();
    hideGift();
  }
}

這里,我們把得到的抽獎(jiǎng)碼進(jìn)行從小往大排列生成字符串,然后在 giftData 數(shù)組中找尋配合的組合,達(dá)成后進(jìn)行不同的獎(jiǎng)勵(lì)畫(huà)面。

紙屑飛舞

這里我使用了 canvas-confetti,它是專(zhuān)門(mén)來(lái)制作紙屑飛散的動(dòng)畫(huà)庫(kù)。其原理是在頁(yè)面創(chuàng)建了canvas (也可以指定容器), 然后在里面繪制了幾種形狀可供選擇,通過(guò)數(shù)學(xué)計(jì)算,模擬了很多物理運(yùn)動(dòng)來(lái)完成紙屑動(dòng)畫(huà)多彩的效果。

# NPM
npm i canvas-confetti -S
# YARN
yarn add canvas-confetti
# PNPM
pnpm i canvas-confetti -S
import confetti from "canvas-confetti";
function handleSucces() {
  let endTime = Date.now() + 3 * 1000;
  const colors = ["#bb0000", "#ffffff"];
  (function frame() {
    confetti({
      particleCount: 2,
      angle: 45,
      spread: 155,
      origin: { x: 0 },
      colors: colors,
    });
    confetti({
      particleCount: 2,
      angle: 135,
      spread: 60,
      origin: { x: 1 },
      colors: colors,
    });
    if (Date.now() < endTime) {
      requestAnimationFrame(frame);
    }
  })();
}

結(jié)語(yǔ)

現(xiàn)在已經(jīng)把大家開(kāi)發(fā)這類(lèi)項(xiàng)目可能遭遇的問(wèn)題或者方案大致給大家講述完了。不知道,給你帶來(lái)的幫助是多是少,也不知道大家點(diǎn)擊了多少次才得到喜歡吃的粽子了,但不管是什么,開(kāi)心快樂(lè)就好,最后祝大家端午安康,財(cái)運(yùn),福運(yùn)多多,幸福滿(mǎn)滿(mǎn)。

到此這篇關(guān)于基于vite2+vue3制作個(gè)招財(cái)貓游戲的文章就介紹到這了,更多相關(guān)vite2 vue3招財(cái)貓游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue項(xiàng)目預(yù)覽excel表格功能(file-viewer插件)

    vue項(xiàng)目預(yù)覽excel表格功能(file-viewer插件)

    這篇文章主要介紹了vue項(xiàng)目預(yù)覽excel表格功能(file-viewer插件),本文分步驟結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-10-10
  • vuex命名空間的使用

    vuex命名空間的使用

    本文主要介紹了vuex命名空間的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Vue2單一事件管理組件通信

    Vue2單一事件管理組件通信

    這篇文章主要為大家詳細(xì)介紹了Vue2單一事件管理組件通信的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Vue + Echarts頁(yè)面內(nèi)存占用高的問(wèn)題解決方案

    Vue + Echarts頁(yè)面內(nèi)存占用高的問(wèn)題解決方案

    點(diǎn)擊左側(cè)的菜單可以切換不同的看板,有些看板頁(yè)面中的報(bào)表比較多,用戶(hù)多次切換后頁(yè)面的內(nèi)存占用可以上升為GB級(jí),嚴(yán)重時(shí)導(dǎo)致頁(yè)面內(nèi)存溢出,使得頁(yè)面崩潰,極大影響了用戶(hù)體驗(yàn),本文給大家介紹Vue + Echarts頁(yè)面內(nèi)存占用高的問(wèn)題解決方案,感興趣的朋友一起看看吧
    2024-02-02
  • Vue組件之自定義事件的功能圖解

    Vue組件之自定義事件的功能圖解

    本文通過(guò)圖文并茂的形式給大家介紹了Vue組件之自定義事件的功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • vue項(xiàng)目,代碼提交至碼云,iconfont的用法說(shuō)明

    vue項(xiàng)目,代碼提交至碼云,iconfont的用法說(shuō)明

    這篇文章主要介紹了vue項(xiàng)目,代碼提交至碼云,iconfont的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • vue設(shè)置全局訪問(wèn)接口API地址操作

    vue設(shè)置全局訪問(wèn)接口API地址操作

    這篇文章主要介紹了vue設(shè)置全局訪問(wèn)接口API地址操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • vue實(shí)現(xiàn)input框禁止輸入標(biāo)簽

    vue實(shí)現(xiàn)input框禁止輸入標(biāo)簽

    這篇文章主要介紹了vue實(shí)現(xiàn)input框禁止輸入標(biāo)簽,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue中addEventListener()?監(jiān)聽(tīng)事件案例講解

    Vue中addEventListener()?監(jiān)聽(tīng)事件案例講解

    這篇文章主要介紹了Vue中addEventListener()?監(jiān)聽(tīng)事件案例講解,包括語(yǔ)法講解和事件冒泡或事件捕獲的相關(guān)知識(shí),本文結(jié)合示例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • vue項(xiàng)目前端加前綴(包括頁(yè)面及靜態(tài)資源)的操作方法

    vue項(xiàng)目前端加前綴(包括頁(yè)面及靜態(tài)資源)的操作方法

    這篇文章主要介紹了vue項(xiàng)目前端加前綴(包括頁(yè)面及靜態(tài)資源)的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12

最新評(píng)論