123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- <template>
- <view class="rive-ani" id="rive-ani" v-if="state.comVisable" >
- <view class="coin-max-tip" v-if="state.maxTipVisible" :style="{backgroundImage: `url(${staticImg.blockRect})`, top: '3vw'}" >
- 已达上限
- </view>
- <view class="coin-total" :style="{top: '3vw' }" >
- <span>{{wisdomCoinStore.total || 0}}</span>
- <view class="coin-logo" id="coin-logo" :animation="state.heartbeatAni" >
- <img :src="staticImg.coinTotal" alt="">
- </view>
- </view>
- <view class="coin-ani" id="coin-ani" v-if="state.visible" :key="state.aniKey" >
- <view
- class="coin-item"
- v-for="item in state.cointCount"
- :key="item"
- :animation="state.animation[item - 1]"
- :id="`coin-item-${item}`"
- >
- <img :src="staticImg.coinAni" alt="" >
- </view>
- <view class="coin-count" id="coin-count" >+ {{state.cointCount}}</view>
- </view>
- </view>
- </template>
- <script setup lang="ts" name="rive " >
- import { onMounted, ref, reactive, getCurrentInstance, defineExpose, nextTick} from 'vue'
- import { Rive } from "@rive-app/canvas"
- import { useStaticImg, useQueryElInfo, useSchedulerOnce, useNavbarInfo } from '@/hooks/index'
- import { useWisdomCoinStore } from '@/store'
- import { AudioController } from '@/controller/AudioController';
- // import threeStarRiv from '@/ani/three_star.riv'
- enum AniEnum {
- 'one',
- 'two',
- 'three',
- 'four',
- 'five',
- 'six'
- }
- /**
- * 动画逻辑
- * 1. 得几颗星就控制rive动画给几颗星
- * 2. 然后rive动画渐隐
- * 3. 出现金币 +n 的字样
- * 4. 金币飞到右上角金币框
- */
- interface State {
- rive: Rive,
- animation: any,
- visible: boolean,
- heartbeatAni: any,
- cointCount: number,
- comVisable: boolean,
- cardType: 0 | 1,
- maxTipVisible: boolean
- aniKey: number
- }
- const state = reactive<Partial<State>>({
- animation: [],
- visible: false,
- heartbeatAni: null,
- cointCount: 0,
- comVisable: false,
- cardType: 0,
- maxTipVisible: false,
- aniKey: 0
- })
- const staticImg = useStaticImg()
- const wisdomCoinStore = useWisdomCoinStore()
- const navbarInfo = useNavbarInfo()
- const coinLoginRef = ref()
- let rive: Rive
- let _resolve: any
- const initHeartbeatAni = () => {
- var animation = uni.createAnimation({
- timingFunction: "linear",
- transformOrigin: "0% 0%"
- });
- return animation.scale(1.1, 1.1).step({duration: 100}).scale(1, 1).step({duration: 100}).export()
- }
- // 1. 初始化rive动画
- const initRive = () => {
- const canvas = document.createElement('canvas')
- // const scale = window.devicePixelRatio;
- const scale = 1;
- canvas.width = 375 * scale;
- canvas.height = 375 * scale;
-
- canvas.id = 'rive-canvas'
- canvas.style.position = 'absolute'
-
- document.getElementById('rive-ani')?.appendChild(canvas)
-
- rive = new Rive({
- // src: "https://res-game.luojigou.vip/coin1234.riv",
- src: 'https://res-game.luojigou.vip/three_star.riv',
- canvas: canvas,
- autoplay: false,
- stateMachines: "bumpy",
- // artboard: state.cardType === 0 ? 'si-xing' : 'six-xing',
- artboard: 'Three Star Board',
- onLoad: () => {
-
- rive.resizeToCanvas()
- console.log(rive);
- rive.play(AniEnum[state.cointCount! - 1])
- // rive.play('one')
-
- for (let i = 0; i < state.cointCount!; i++) {
-
- useSchedulerOnce( () => {
- AudioController.playCoinLight()
- }, 1200 + i * 100)
- }
-
-
- },
- onStop: () => {
- fadeOutRive()
- useSchedulerOnce(() => {
- state.visible = true
- useSchedulerOnce(() => document.getElementById('coin-count')!.style.display = 'none', 1200)
- useSchedulerOnce(() => goBezier(), 1400)
- }, 1000)
-
- }
- });
- }
- const createAnimationStep = (animation: UniApp.Animation, count: number) => {
- for (let i = 0; i < count; i++) {
- state.animation.push(animation.step({duration: 400 + i * 200}).export())
- useSchedulerOnce(() => {
- if (wisdomCoinStore.remainderWisdomCoin <= 0) {
- state.maxTipVisible = true
- } else {
- wisdomCoinStore.total ++
- wisdomCoinStore.remainderWisdomCoin--
- }
-
- document.getElementById(`coin-item-${i + 1}`)!.style.display = 'none'
- state.heartbeatAni = initHeartbeatAni()
- }, 400 + i * 200)
- }
- }
- // 2. rive动画渐隐消失
- const fadeOutRive = () => {
- const riveCanvas = document.getElementById('rive-canvas')!
- riveCanvas.style.opacity = '0'
- riveCanvas.style.transition = '1s'
- }
- const goBezier = () => {
-
- var animation = uni.createAnimation({
- timingFunction: "linear",
- transformOrigin: "0% 0%"
- });
- animation
- .top(coinLoginRef.value.top )
- .left(coinLoginRef.value.left)
- .scale(0.25, 0.25)
- createAnimationStep(animation, state.cointCount!)
- useSchedulerOnce(() => {
- _resolve()
- state.comVisable = false
- state.visible = false
- state.animation = []
- document.getElementById('coin-count')!.style.display = 'block'
- }, 1200 + state.cointCount! * 600)
- }
- const start = async (starCount: number, cardType: 0 | 1) => {
- state.comVisable = true
- state.cointCount = starCount
- state.cardType = cardType
- state.aniKey = Math.random()
- if (cardType === 0) {
- starCount <= 2 ? AudioController.playFail() : AudioController.playPass()
- } else {
- starCount <= 3 ? AudioController.playFail() : AudioController.playPass()
- }
- useSchedulerOnce(() => {
- useSchedulerOnce(initRive)
- }, 200)
- if (wisdomCoinStore.remainderWisdomCoin == 0) {
- state.maxTipVisible = true
- }
-
- nextTick(() => useQueryElInfo('#coin-logo', (res) => coinLoginRef.value = res, getCurrentInstance()!, false))
- return new Promise((resolve) => {
- _resolve = resolve
- })
- }
- defineExpose({
- start: start
- })
- onMounted(() => {
- })
- </script>
- <style lang="less" scoped >
- .rive-ani {
- width: 100vw;
- height: 100vh;
- position: fixed;
- top: 0;
- left: 0;
- z-index: 200;
- background-color: rgba(0,0,0, .6);
- display: flex;
- align-items: center;
- justify-content: center;
- .coin-max-tip {
- width: 88px;
- height: 33px;
- background-size: 100%;
- position: absolute;
- right: 120px;
- display: flex;
- align-items: center;
- background-repeat: no-repeat;
- font-size: 14px;
- font-family: PingFangSC-Semibold, PingFang SC;
- font-weight: 600;
- color: #FEFBFB;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-top: 2px;
- }
- .coin-total {
- height: 36px;
- background: #414141;
- border-radius: 19px;
- position: absolute;
- right: 2vw;
- display: flex;
- align-items: center;
- padding: 0 8px;
- box-sizing: border-box;
- .coin-logo {
- margin-left: 6px;
- img {
- width: 20px;
- height: 20px;
- display: block;
- }
- }
-
- span {
- font-size: 18px;
- font-family: PingFangSC-Semibold, PingFang SC;
- font-weight: 600;
- color: #FEFBFB;
-
- display: block;
- }
- }
- .coin-ani {
- width: 100vw;
- height: 100vh;
- position: absolute;
- top: 0%;
- left: 0%;
- display: flex;
- align-items: center;
- justify-content: center;
- .coin-item {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- animation: jelly 0.5s;
- transform-origin: top center;
- }
- @keyframes jelly {
- 0% {
- scale: 0;
- }
- 100% {
- scale: 1;
- }
- }
- img {
- width: 30%;
- height: 30%;;
- }
- .coin-count {
- font-size: 200%;
- font-family: PingFangSC-Semibold, PingFang SC;
- font-weight: 600;
- color: #FF8024;
- // margin-left: 250rpx;
- // margin-bottom: 20rpx;
- }
- }
- }
- .uni-canvas-canvas {
- width: 1000px !important;
- }
- </style>
|