123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827 |
- <template>
- <view class="luojigou-board-v2" :style="{width: widget.boardWidth + 'px', height: widget.boardHeight + 'px'}">
- <canvas canvas-id='canvasId' id="canvasId" style="width: 111px;height: 584px;position: fixed;left: -2000px;" ref="canvasDom" ></canvas>
- <view class="board" >
- <view class="process" >
- <view class="count" >{{process + 1}}</view>
- <view class="symbol" >/</view>
- <view>6</view>
- </view>
- <view class="button-list" >
- <view class="button" :style="{opacity: index < process ? 0.4 : 1 }" v-for="(item, index) in buttonListCpd" :key="item" >
- <image class="icon" :src="staticImg[item]" alt="" />
- <image v-if="index < process" class="right-icon" :src="staticImg.rightIcon" alt="" />
- </view>
- </view>
- <view class="question-card" >
- <view :class="questionCardAni" >
- <image class="ques-item-url" :src="quesCard.current" />
- </view>
- <view class="ques-card-next" >
- <image class="ques-item-url" :src="quesCard.next" />
- </view>
- <view :class="questionAni" @click="previewCard" >
- <image class="card" :src="props.card.board.quesUrl" alt="" />
- <image class="open-icon" v-if="aniState" :src="staticImg.openIcon" />
- </view>
- </view>
- </view>
- <view class="answer" >
- <!-- :key="keyCount" -->
- <view class="answer-list" >
- <view
- class="answer-item"
- v-for="(item, index) in ansList"
- :key="item.id"
- :style="{top: item.top + 'px', left: item.left + 'px'}"
- :animation="aniListRef[index]"
- @click="selectAnswer(item)"
- >
- <image class="ans-img" :src="item.url" />
- <view :class="ansResultClass" v-if="item.select" >
- <image :src="ans === 1 ? staticImg.success : staticImg.wrong" />
- </view>
- <image class="hand" v-if="tipState && item.isAns" :src="staticImg.hand" />
- </view>
- </view>
- </view>
- </view>
- <view class="opra-container" >
- <view class="read" :style="{opacity: !readState ? 0 : 1}" id="lottie-dom-read" @click="stopReadQuestion" > </view>
- <image class="read" v-if="!readState" @click="readQuestion" :src="staticImg.read" />
- <image class="tip" @click="openTip" :src="staticImg.tip" />
- </view>
- <view class="lottie-dom" id="lottie-dom-wrong"></view>
- <view class="lottie-dom" id="lottie-dom-success"></view>
- <view class="preview-card" v-if="previewState" @click="previewCard" >
- <image :src="props.card.board.quesUrl" />
- </view>
- </template>
- <script setup lang="ts" >
- import { useStaticImg,useScheduler, useSchedulerOnce, useAudioMange } from '@/hooks'
- import { computed, ref, nextTick, watch, onMounted, getCurrentInstance } from 'vue';
- import { useCalcQuantityV2Store } from '@/store/gameTool';
- import ao from '@/audio/ao.mp3'
- import successMp3 from '@/audio/success.mp3'
- import wrongMp3 from '@/audio/wrong.mp3'
- import timeoutMp3 from '@/audio/timeout.mp3'
- import lottie from 'lottie-web'
- import { onHide, onShow } from '@dcloudio/uni-app';
- interface IProps {
- card: {
- board: API.BoardV2,
- cardAble: string
- cardDesc: string
- cardName: string
- cardType: number
- audio: string
- }
- }
- interface AnsList {
- top: number,
- left: number,
- url: string,
- isAns: boolean,
- select: boolean
- id: string
- }
- const {
- proxy: { $forceUpdate },
- }: any = getCurrentInstance();
- const { windowWidth, windowHeight } = uni.getSystemInfoSync()
- const isPad = windowHeight / windowWidth > 0.6
- const posValue = isPad ? 180 : 125
- const ansListData: AnsList[] = [
- {top: 0, left: 0, url: '', isAns: false, select: false, id: '0' },
- {top: 0, left: posValue, url: '', isAns: false, select: false, id: '1'},
- {top: posValue, left: 0, url: '', isAns: false, select: false, id: '2'},
- {top: posValue, left: posValue, url: '', isAns: false, select: false, id: '3'}
- ]
- const props = defineProps<IProps>()
- const staticImg = useStaticImg()
- const audioMange = useAudioMange()
- const luojigouBoardV2Dom = ref()
- const calcQuantityV2Store = useCalcQuantityV2Store()
- const process = ref(0)
- const buttonList = ['red', 'green', 'blue', 'orange', 'purple', 'yellow']
- const buttonListCpd = computed(() => buttonList.slice(0, process.value + 1))
- const keyCount = ref(0)
- const canvasDom = ref()
- const ans = ref(0) // 0 未选择 1 正确 2 错误
- const ansList = ref<AnsList[]>(JSON.parse(JSON.stringify(ansListData)))
- const answerPictureList = ref<string[]>([])
- const tipState = ref<boolean>(false)
- const questionAni = ref(['ques-url'])
- const ansResultClass = ref(['result'])
- const questionCardAni = ref(['ques-card-current'])
- const aniState = ref(false)
- const previewState = ref(false)
- const widget = { boardWidth: 581 / (812 / windowWidth), boardHeight: 398 / (812 / windowWidth)}
- const emits = defineEmits(['loadingStart', 'loadingEnd', 'gameover'])
- const readState = ref(false)
- const stopReadQuestion = () => {
- readState.value = false
- audioMange.destroy()
- }
- const readQuestion = () => {
- audioMange.play(props.card.audio)
- readState.value = true
- audioMange.onplayend(() => {
- lottieReadRef.value.stop()
- readState.value = false
- })
- lottieReadRef.value.play()
- }
- const ansPictureRandom = () => {
- const r: number[] = []
- const arr = [0, 1, 2, 3, 4, 5]
- const count = 3
- const ansIndex = props.card.board.list[process.value].ansIndex
- const randomArr = arr.filter( item => item !== ansIndex )
- for (let i = 0; i < count; i++) {
- const randomCount = randomArr[ Math.floor(Math.random() * 5)]
- if (r.includes(randomCount)) {
- i--
- } else {
- r.push(randomCount)
- ansList.value[i].url = answerPictureList.value[randomCount]
- ansList.value[i].isAns = false
- }
- }
- const rc = Math.floor(Math.random() * 4)
- ansList.value[3].url = ansList.value[rc].url
- ansList.value[3].isAns = false
- ansList.value[rc].url = answerPictureList.value[ansIndex]
- ansList.value[rc].isAns = true
- console.log( ansList.value[rc].url);
- $forceUpdate()
- }
- const reset = () => {
- ansResultClass.value = ['result']
-
- useSchedulerOnce(() => {
- emits('gameover', process.value, () => {
- ansList.value.forEach( item => item.id = Math.random().toString(16).slice(2) )
- questionCardAni.value.push('ques-card-ani')
- useSchedulerOnce(() => {
- process.value++
- useSchedulerOnce(() => {
- questionCardAni.value.pop()
- }, 1000)
- }, 1000)
- useSchedulerOnce(() => {
- ansPictureRandom()
- }, 1000)
-
- })
- }, 1200)
- }
- const clearTimeRef = ref()
- const selectAnswer = (record: {isAns: boolean, select: boolean}) => {
- // 关闭一些状态
- readState.value = false
- tipState.value = false
- ansList.value.forEach( item => item.select = false)
- if (ansResultClass.value.length === 2) ansResultClass.value.pop()
- record.select = true
- lottieReadRef.value.stop()
- clearTimeRef.value && clearTimeRef.value()
- // 关闭一些状态
- if (record.isAns) {
- emits('loadingStart')
- ansResultClass.value.push('success')
- ans.value = 1
- lottieSuccessRef.value.play()
- if (calcQuantityV2Store.wrongCount <= 1) {
- audioMange.play(successMp3)
- } else {
- audioMange.play(wrongMp3)
- }
- clearTimeRef.value = useSchedulerOnce(() => {
- reset()
- record.select = false
- ans.value = 0
- }, 1000)
- } else {
- ansResultClass.value.push('wrong')
- ans.value = 2
- audioMange.play(ao)
- calcQuantityV2Store.wrongCount++
- clearTimeRef.value = useSchedulerOnce(() => {
- record.select = false
- ansResultClass.value.pop()
- ans.value = 0
- }, 2000)
- lottieWrongRef.value.stop()
- lottieWrongRef.value.play()
- }
- calcQuantityV2Store.totalCount++
- }
- const quesCard = computed(() => {
- if (props.card.board.list && process.value <= 6) {
- return {
- current: props.card.board.list[process.value].quesImg,
- next: process.value === 6 ? '' : props.card.board.list[process.value].quesImg,
- }
- }
- return {
- current: '',
- next: ''
- }
- })
- watch(
- () => props.card.board.ansUrl,
- async () => {
- console.log('card.board.quesUrl:', props.card.board.ansUrl);
-
- if ( props.card.board.quesUrl) {
- nextTick(async () => {
- await croppingPicture(props.card.board.ansUrl)
- nextTick(() => {
- ansPictureRandom()
- readQuestion()
- questionAni.value.push('question-card-ani')
- useSchedulerOnce(() => {
- questionAni.value.push('question-card-small')
- aniState.value = true
- }, 1700)
- })
- })
- }
- },
- {
- deep: true,
- // immediate: true
- }
- )
- // 预览题卡
- const previewCard = () => previewState.value = !previewState.value
- const openTip = () => {
- console.log('tipState.value = true');
-
- tipState.value = true
- }
- const aniListRef = ref()
- // 动画列表
- const aniList = () => {
- const a1 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
- const a2 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
- const a3 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
- const a4 = uni.createAnimation({duration: 300, timingFunction: 'ease'})
- return [
- a1.top(60).left(60).step({delay: 0}).top(0).left(0).step({delay: 300}).export(),
- a2.top(60).left(60).step({delay: 0}).top(0).left(posValue).step({delay: 300}).export(),
- a3.top(60).left(60).step({delay: 0}).top(posValue).left(0).step({delay: 300}).export(),
- a4.top(60).left(60).step({delay: 0}).top(posValue).left(posValue).step({delay: 300}).export(),
- ]
- }
- aniListRef.value = aniList()
- // 切割答案的图片
- const croppingPicture = (img: string) => {
- return new Promise((resolve) => {
- const ctx = uni.createCanvasContext('canvasId')
- const imgae = new Image()
- imgae.src = img
- imgae.onload = () => {
- console.log(imgae.width, imgae.height);
- // const imgPng = img.endsWith('jpeg') ? img.replace('jpeg', 'png') : img
- // console.log('imgPng:', imgPng);
-
- uni.downloadFile({
- url: img,
- header: {
- "Content-Type": "application/x-www-form-urlencoded",
- "Content-Disposition": 'attachment;filename=',
- },
- success(result) {
- nextTick(() => {
- console.log('会出错嘛:', result);
-
- //
- // canvasDom.value.width = imgae.width / 4
- // canvasDom.value.height = imgae.height / 4
- // ctx.drawImage(result.tempFilePath, 0, 0, 222, imgae.height / 2)
- ctx.drawImage(result.tempFilePath, 0, 0, imgae.width / 8, imgae.height / 8)
- ctx.draw(false, () => {
- useSchedulerOnce(() => {
- for (let i = 0; i < 6; i++) {
- uni.canvasToTempFilePath({
- x: 0,
- y: 184 * i / 4 + 12 * i / 4,
- width: 222 / 4,
- height: 184 / 4,
- canvasId: 'canvasId',
-
- success: function(res) {
-
- answerPictureList.value.push(res.tempFilePath)
- resolve(true)
- },
- fail(result) {
- console.log('canvasToTempFilePath:', result);
-
- },
- complete(result) {
- console.log('complete--->canvasToTempFilePath:', result);
- },
- })
- }
- }, 5)
- })
-
- })
- },
- fail(result) {
- console.log('downloadFile:', result);
-
- },
- })
- }
- })
- }
- const lottieWrongRef = ref()
- const lottieSuccessRef = ref()
- const lottieReadRef = ref()
- // lottie-web
- const initLottieWeb = () => {
- lottieWrongRef.value = lottie.loadAnimation({
- container: document.getElementById('lottie-dom-wrong'),
- renderer: 'svg',
- loop: false,
- autoplay: false,
- path: 'https://luojigou-game-res.luojigou.vip/lottie-wrong.json',
- })
- lottieWrongRef.value.onComplete = function () {lottieWrongRef.value.stop() }
- lottieSuccessRef.value = lottie.loadAnimation({
- container: document.getElementById('lottie-dom-success'),
- renderer: 'svg',
- loop: false,
- autoplay: false,
- path: 'https://luojigou-game-res.luojigou.vip/lottie-success-1.json'
- })
- lottieSuccessRef.value.onComplete = function () {lottieSuccessRef.value.stop() }
- lottieReadRef.value = lottie.loadAnimation({
- container: document.getElementById('lottie-dom-read'),
- renderer: 'svg',
- loop: true,
- autoplay: false,
- path: 'https://luojigou-game-res.luojigou.vip/trump.json'
- })
- lottieReadRef.value.stop()
- }
- onMounted(() => {
- initLottieWeb()
- })
- const stx = useScheduler(() => audioMange.play(timeoutMp3), 15000)
- stx.start()
- document.body.addEventListener('click', () => {
- stx.stop()
- stx.start()
- })
- onShow(() => {
- audioMange.setVolume(1)
- })
- onHide(() => {
- audioMange.setVolume(0)
- })
- // window['stopScheduler'] = () => {
- // audioMange.setVolume(0)
- // }
- // window['playScheduler'] = () => {
- // audioMange.setVolume(1)
- // }
- </script>
- <style lang="less" scoped >
- .luojigou-board-v2 {
- position: relative;
- .board {
- width: 60%;
- height: 100%;
- background: url('@/assets/GameViewV2/board.png') no-repeat top left;
- background-size: 100%;
- position: relative;
- top: 10%;
- .process {
- width: 10.5%;
- height: 16.33%;
- background: #FFC047;
- position: absolute;
- top: 16.33%;
- left: -10.5%;
- z-index: 2;
- // font-size: 90%;
- font-family: PingFang SC-Semibold, PingFang SC;
- font-weight: 400;
- color: #FFFFFF;
- white-space: normal;
- display: flex;
- justify-content: center;
- align-items: center;
- border-top-left-radius: 14rpx;
- border-bottom-left-radius: 14rpx;
- vertical-align: bottom;
- .count {
- font-size: 130%;
- font-weight: 600;
- vertical-align: bottom;
- margin-bottom: 6%;
- }
- .symbol {
- margin-bottom: 6%;
- }
- view {
- display: inline-block;
- line-height: 24px;
- vertical-align: bottom;
- }
- }
- .button-list {
- width: 20%;
- height: 60%;
- position: absolute;
- top: 6%;
- right: -6%;
- .button {
- width: 55%;
- height: 16%;
- margin-bottom: 17%;
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- .icon {
- width: 100%;
- height: 100%;
- display: block;
- }
- .right-icon {
- width: 60%;
- height: 60%;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- }
- }
- }
- .question-card {
- width: 78%;
- height: 72%;
- position: absolute;
- top: 6%;
- left: 4%;
- // background-color: #fff;
- border-radius: 6%;
- z-index: 11;
- .ques-card-current {
- width: 100%;
- height: 100%;
- background-color: #fff;
- border-radius: 6%;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index: 11;
- transform-origin: 50% 50%;
- .ques-item-url {
- width: 76%;
- height: 79%;
- display: block;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index: 1;
- border-radius: 6%;
- }
- }
- .ques-card-ani {
- animation: ques-card-current-ani 0.9s;
- }
- @keyframes ques-card-current-ani {
- 0% {
- rotate: 0deg;
- left: 50%;
- opacity: 1;
- }
- 33% {
- rotate: 4deg;
- left: 50%;
- opacity: 1;
- }
- 66% {
- rotate: 0deg;
- left: 50%;
- opacity: 1;
- }
- 100% {
- opacity: 0;
- left: 20%;
- }
- }
- .ques-card-next {
- width: 100%;
- height: 100%;
- background-color: #fff;
- border-radius: 6%;
- .ques-item-url {
- width: 76%;
- height: 79%;
- display: block;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index: 1;
- border-radius: 6%;
- }
- }
- .ques-url {
- width: 100%;
- height: 100%;
- display: block;
- position: absolute;
- top: 0%;
- left: 0%;
- z-index: 22;
- transform-origin: 96% 4%;
- border-radius: 6%;
- display: flex;
- justify-content: center;
- align-items: center;
- background-color: #fff;
- .card {
- width: 58%;
- height: 100%;
- border-radius: 6%;
- object-fit: contain;
- }
- .open-icon {
- width: 30%;
- height: 30%;
- position: absolute;
- bottom: 2vw;
- right: 8vw;
- }
- }
- }
- .question-card-ani {
- animation: card-ani 1s ease 0.9s;
- }
- .question-card-small {
- transform: scale(32%) translateX(20%);
- background-color: transparent !important;
- .card {
- border: 2px solid #D0D0D0;
- }
- }
- }
- .answer {
- width: 45%;
- height: 60%;
- position: absolute;
- top: 50%;
- left: 66%;
- transform: translateY(-50%);
- .answer-list {
- display: grid;
- grid-template-columns: 11vw 6vw 11vw;
- grid-template-rows: 11vw 6vw 11vw;
- // width: 34%;
- // height: 37%;
- .answer-item {
- width: 11vw;
- height: 11vw;
- background-color: #fff;
- box-shadow: 0px 0px 1vw 0px #FFC04C;
- border-radius: 16%;
- border: 0.5vw solid rgba(255, 192, 76, 0.2);
- position: absolute;
- box-sizing: border-box;
- // overflow: hidden;
- .ans-img {
- width: 100%;
- height: 100%;
- border-radius: 16%;
- object-fit: cover;
- }
- .hand {
- width: 6vw;
- height: 6vw;
- position: absolute;
- top: 50%;
- left: 50%;
- animation: hand-ani 1s infinite;
- }
- .result {
- width: 100%;
- height: 100%;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- display: flex;
- justify-content: center;
- align-items: center;
- border-radius: 16%;
- image {
- width: 37.5%;
- height: 37.5%;
- display: block;
- }
- }
- .success {
- background: rgba(34,193,52,0.5);
- border: 0.5vw solid #22C134;
- }
- .wrong {
- background: rgba(234,71,71,0.5);
- border: 0.5vw solid #EA4747;
- }
- }
- }
- }
- }
- .opra-container {
- position: fixed;
- right: 3vw;
- bottom: 3vw;
- display: flex;
- flex-direction: column;
- .read {
- width: 5.5vw;
- height: 5.5vw;
- position: absolute;
- bottom: 6.5vw;
- }
- image {
- width: 5.5vw;
- height: 5.5vw;
- margin-top: 2vw;
- }
- }
- .lottie-dom {
- width: 24vw;
- height: 24vw;
- position: fixed;
- left: 0;
- bottom: 0;
- z-index: 120;
- }
- .preview-card {
- width: 100vw;
- height: 100vh;
- background-color: rgba(0, 0, 0, 0.6);
- position: fixed;
- top: 0;
- left: 0;
- z-index: 11;
- display: flex;
- justify-content: center;
- align-items: center;
- image {
- width: 58vh;
- height: 100vh;
- }
- }
- @keyframes hand-ani {
- 0% {
- transform: translate(0vw, 0vw)
- };
- 50% {
- transform: translate(2vw, 2vw)
- };
- 100% {
- transform: translate(0vw, 0vw)
- }
- }
- @keyframes card-ani {
- 0% {
- transform: scale(100%);
- };
- 78% {
- transform: scale(100%);
- background-color: #fff;
- };
- 80% {
- background-color: transparent;
- };
- 100% {
- transform: scale(32%) translateX(20%);
- background-color: transparent;
- }
- }
- </style>
|