#过年不停更# HarmonyOS自定义JS组件——元宵猜灯谜 原创 精华

深开鸿
发布于 2022-2-15 20:48
浏览
5收藏

春节不停更,此文正在参加「星光计划-春节更帖活动」

作者:包月东

前言

又到了一年一度的元宵佳节,首先祝大家元宵节快乐!东风夜放花千树,宝马雕车香满路。逛花市,猜灯谜作为传统节目,经久不衰,今天给大家带来一款猜灯谜的鸿蒙小游戏。

效果图

#过年不停更# HarmonyOS自定义JS组件——元宵猜灯谜-鸿蒙开发者社区

实现思路

首先我们来拆分下区域,如效果图所示,游戏区域分为:头部面板、谜语、谜字、控制按钮、提示、谜底面板(隐藏)

  • 记分面板:左边是一个得分text,右边是一个音乐播放按钮,可以用video实现
  • 谜语:主要是文本,使用text实现
  • 谜字:有一堆text组成,通过for来配置。每次放置的位置、旋转角度通过随机函数设置,不至于沉闷。
  • 控制按钮:查看谜底用来显示谜底面板。上一题,下一题则是改变题库的指针pointer来更改谜语,谜字。
  • 提示:一个简单的text
  • 谜底面板:这里用到了panel,起到弹起收拢的效果。

具体实现

头部面板

   <stack class="music">
        <video show="false" id='videoId' src='/common/Homey.mp3' muted='false'
               autoplay='true' poster='/common/images/music_symbol.png'
               controls="true"
               loop='true'>
        </video>
        <image src="/common/images/music_symbol.png" style="object-fit: contain;"></image>
    </stack>

如上,音乐的播放我们使用video来实现,设置show为false不显示,loop为true表示不断轮播。video是负责后台播放,前台旋转音乐图片使用image实现,旋转动画我们选择CSS动画配置

.music {
    width: 50;
    height: 50;
    position: absolute;
    right: 5%;
    top: 1.5%;
    animation-name: musicrotation;
    animation-duration: 4s;
    animation-delay: 0s;
    animation-fill-mode: forwards;
    animation-iteration-count: -1;
    animation-timing-function: linear
}

@keyframes musicrotation {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg)
    }
}

谜语

<text class="riddle">{{ riddle }}</text>

谜字

<stack id="content"
           style="background-color : yellow; width : 100%; height : 30%;
                   margin-start : 7%;
                   margin-end : 7%;
                   margin-top : 2%;
                   margin-bottom : 2%"
            >
        <text for="{{ (i, v) in selection }}"
              style="top : {{ selection_property[i].top }};
                      left : {{ selection_property[i].left }};
                      transform : rotate({{ selection_property[i].rotate }});
                      color : {{ [i].color }};
                      font-size : 30fp;
                      " onclick="onTextClick(i)">{{ v }}</text>
    </stack>

谜字通过一个for循环动态生成text,这里的selection表示谜字的文本,selection_property表示每个文本的位置、选择,颜色等属性

生成selection_property的代码如下:

//配置selection_property
        let selection_property = []
        const degree_unit = 360 / len
        const degree2Rad = Math.PI / 180
        for (let i = 0;i < len; i++) {
            let d = degree_unit * (i + (Math.random() * 0.3 + 0.3)) * degree2Rad
            let r = (Math.random() * 0.1 + 0.6) * 50
            let left = 50 + r * Math.cos(d) - 5 + '%'
            let top = 50 + r * Math.sin(d) - 10 + '%'
            let rotate = (Math.random() * 2 - 1) * 45 + '%'
            selection_property.push({
                top: top,
                left: left,
                rotate: rotate,
                color: 'black'
            })
        }

这里通过更改selection_property中top,left,rotate,color这几个属性更改text的显示位置,为了生动使用了Math.Random()

判断是否答对

迷字开始是黑色,点击一次变成红色,我们通过遍历selection_property可以查看用户选择了那几个迷字,当迷字和我们的谜底相同时,表示答对

具体代码如下:

 //个数和词都能对上才算答对
    checkIsCorrect() {
        let count1 = 0, count2 = 0;
        for (let i = 0;i < this.selection_property.length; i++) {
            if (this.selection_property[i].color != 'black') {
                count1++
                if (this.answer.includes(this.selection[i])) {
                    count2++;
                }
            }
        }
        return count2 == this.answer.length && count1 == count2;
    },

判断是否通关

当当前谜语的pointer指向最后一个了,当用户答对时,我们认为通关了

onTextClick(i) {
        console.log('i-->' + i)
        this.selection_property[i].color = this.selection_property[i].color == 'red' ? 'black' : 'red'
        if (this.checkIsCorrect()) {
            this.score += 10;
            if (this.pointer == riddles.length - 1) {
                prompt.showToast({
                    message: "恭喜通关,你的总得分是:" + this.score
                })
            } else {
                prompt.showToast({
                    message: "恭喜答对了"
                })
                this.nextStage();
            }
        }
    },

控制面板

    <div style="width : 100%; justify-content : center; flex-direction : row; margin-start : 5%; margin-end : 5%;">
        <button type="capsule" @click="showAnswer">查看谜底</button>
        <button type="capsule" style="margin-start : 10%;" @click="prevStage">上一题</button>
        <button type="capsule" style="margin-start : 10%;" @click="nextStage">下一题</button>
    </div>

查看谜底的click方法是用来显示谜底panel,当然这里是否显示谜底,需要在提示次数和积分够的情况下才行。

showAnswer() {
        if (this.tipCount <= 0 && this.score < 20) {
            prompt.showToast({
                message: "提示次数已用完,得分高于20分才能看谜底额"
            })
            return
        }
        if (this.tipCount > 0) {
            prompt.showToast({
                message: "剩余提示次数:" + this.tipCount
            })
            this.tipCount -= 1;
            setTimeout(() => {
                this.$element('answer').show()
            }, 1000)
        } else {
            this.score -= 20
            this.$element('answer').show()
        }
    },

提示

<text style="font-size : 15px; color : white; bottom : 2%; margin-start : 5%; position : absolute;">提示:点击文字选择词语或者取消
    </text>

谜底面板

<panel id="answer" type="minibar" mode="half" onsizechange="changeMode" miniheight="200px">
        <div class="panel-div">
            <div class="inner-btn">
                <button style="background-color : blue;" type="capsule" value="Close" onclick="closeAnswer"></button>
            </div>
            <div class="inner-txt" onclick="closeAnswer">
                <text class="txt">{{ answer }}</text>
            </div>

        </div>
    </panel>

这里用到了panel,我们通过设置model为half来显示半屏。内部的txt用来显示谜底

源码路径

元宵猜灯谜

参考

【虎年春节特别活动】正月十五灯谜串烧有奖竞猜

transform样式动画

video组件

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-2-25 10:00:28修改
6
收藏 5
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

元宵节能和家人一起以这种形式猜灯谜也是一种乐事。

回复
2022-2-16 10:25:08
大梦初醒丶
大梦初醒丶

666

 

回复
2022-2-16 11:43:40
回复
    相关推荐