天天看點

#夏日挑戰賽# HarmonyOS - 基于ArkUI(JS)實作打地鼠遊戲

作者 : 尹寶榮

本文正在參加星光計劃3.0–夏日挑戰賽

前言

初學 HarmonyOS ArkUI(JS) ,對于FA的開發還是不太熟悉,單純看文檔,不使用起來的話,始終掌握不了,代碼還是要多敲多思考才能進步。是以周末突發奇想利用HarmonyOS 寫了一個簡單的打地鼠遊戲。

實作效果

#夏日挑戰賽# HarmonyOS - 基于ArkUI(JS)實作打地鼠遊戲

遊戲說明

點選開始按鈕之後,頂部剩餘時間會從60秒開始倒計時,命中數和得分數清0,同時格子中會随機出現地鼠,點選格子出現錘子敲擊地鼠,打中地鼠之後命中數+1,分數根據難度相應增加。難度分為四個星級,玩家可以根據自己的手速選擇相應難度,難度越高擊中得分越高,地鼠消失的間隔時間越短。60秒倒計時結束之後,地鼠不再出現,彈框提示遊戲結束,并顯示最終得分。

項目說明

主要用到知識:animation,倒計時,HarmonyOS 基礎元件

圖檔來源: iconfont-阿裡巴巴矢量圖示庫

實作步驟

  1. 繪制4x4的格子,每個格子中有一張地鼠的圖檔和一張錘子的圖檔,都預設隐藏。錘子的圖檔定位在地鼠頭上
  2. 點選開始按鈕的時候
  • 開始60秒倒計時
  • 每隔一段時間随機顯示一張地鼠圖檔,根據難度顯示幾秒後隐藏
  1. 點選“地鼠”時
  • 錘子出現并有一個向下打擊的animation動畫效果
  • 根據目前格子中地鼠的圖檔和錘子的圖檔是否顯示,判斷是否打中地鼠
  1. 如果打中地鼠,命中次數+1,得分相應增加
  2. 難度切換後,命中單個地鼠的得分改變,地鼠消失的時間間隔改變
  3. 60秒倒計時結束後,遊戲結束,地鼠不再出現,倒計時停止,彈框提示得分

代碼實作

1. hml部分

1.1 最上面是一些計數資訊資料,用到了 input 元件

<div class="container">

<!-- 頭部計數資訊子產品-->
    <div class="game-title">
        <text class="title-text">打地鼠遊戲</text>
    </div>
    <div class="header-info">

    <!--   剩餘   -->
        <div class="input-box">
            <text class="input-title">剩餘:</text>
            <input class="input" type="text" value="{{ timeInt }}"></input>
            <text class="input-unit">秒</text>
        </div>

    <!--  命中    -->
        <div class="input-box">
            <text class="input-title">命中:</text>
            <input class="input" type="text" value="{{ countInt }}"></input>
            <text class="input-unit">個</text>
        </div>

    <!--   共計   -->
        <div class="input-box">
            <text class="input-title">共計:</text>
            <input class="input" type="text" value="{{ scoreInt }}"></input>
            <text class="input-unit">分</text>
        </div>

           

1.2 難度星級設定,用到了 rating 元件

<!--   難度選擇-->
        <div class="hard-container">
            <text class="input-title">難度設定:</text>
            <rating numstars="4" rating="{{ hardRating }}" stepsize="1" @change="changeRating" id="rating">
            </rating>
        </div>

    <!--    過關分數說明    -->
        <div class="pass-score">
            <text class="pass-text">目前難度: {{hardRating}} 星   命中單個得分:{{ passScore }} 分</text>
        </div>
    </div>
           

附表:rating元件的屬性和事件

#夏日挑戰賽# HarmonyOS - 基于ArkUI(JS)實作打地鼠遊戲
#夏日挑戰賽# HarmonyOS - 基于ArkUI(JS)實作打地鼠遊戲

1.3 打地鼠的格子區域 ,是用資料for循環出來的,寫的時候沒有考慮周全,代碼有一些備援,感興趣的夥伴可以把這塊代碼重構一下,看起來會更簡潔

<!--  打地鼠區域  -->
    <div class="game-area">

    <!-- 第1行-->
        <div class="game-tr1">
            <div class="game-td" for="item in trOne[0]" on:click="showHammer({{ item }})">
                <image class="hammer-pic cover" id="{{ item.idValue }}" src="common/images/hammer.png"
                       show="{{ item.showHammer }}">
                </image>
                <image class="game-pic cover" src="common/images/dishu.png" show="{{ item.showMose }}">
                </image>
            </div>
        </div>

    <!--    第2行   -->
        <div class="game-tr1">
            <div class="game-td" for="item in trOne[1]" on:click="showHammer({{ item }})">
                <image class="hammer-pic cover" id="{{ item.idValue }}" src="common/images/hammer.png"
                       show="{{ item.showHammer }}">
                </image>
                <image class="game-pic cover" src="common/images/dishu.png" show="{{ item.showMose }}">
                </image>
            </div>
        </div>

    <!--    第3行    -->
        <div class="game-tr1">
            <div class="game-td" for="item in trOne[2]" on:click="showHammer({{ item }})">
                <image class="hammer-pic cover" id="{{ item.idValue }}" src="common/images/hammer.png"
                       show="{{ item.showHammer }}">
                </image>
                <image class="game-pic cover" src="common/images/dishu.png" show="{{ item.showMose }}">
                </image>
            </div>
        </div>

    <!--     第4行    -->
        <div class="game-tr1 last-tr">
            <div class="game-td" for="item in trOne[3]" on:click="showHammer({{ item }})">
                <image class="hammer-pic cover" id="{{ item.idValue }}" src="common/images/hammer.png"
                       show="{{ item.showHammer }}">
                </image>
                <image class="game-pic cover" src="common/images/dishu.png" show="{{ item.showMose }}">
                </image>
            </div>
        </div>
    </div>

           

1.4 開始按鈕和彈框,用到了 button 元件和 dialog 元件

<!--  開始按鈕  -->
    <div class="btn-area">
        <button class="btn-start" value="開始" on:click="startGame">
        </button>
    </div>

<!--  提示框  -->
    <dialog id="hintDialog" style="margin-bottom : 50%;">
        <div class="dialog-div">
            <div class="inner-txt">
                <text class="txt">GAME OVER</text>
            </div>
            <text class="text">遊戲得分:{{ scoreInt }}</text>
            <div class="inner-btn">
                <button type="text" value="确定" onclick="closeDialog" class="btn-txt">                   </button>
            </div>
        </div>
    </dialog>
</div>
           

2. css部分

.container {
    padding-top: 20px;
    flex-direction: column;
}

/*頭部資訊樣式*/
.game-title {
    display: flex;
    justify-content: center;
    color: chocolate;
    margin-bottom: 20px;
}

.header-info {
    flex-direction: column;
}

.input-title {
    font-size: 18px;
}

.input {
    width: 100px;
    height: 30px;
}

.input-unit {
    font-size: 18px;
    margin-left: 8px;
}

.input-box {
    margin-bottom: 14px;
    margin-left: 20px;
}

/*難度系數選擇樣式*/
.hard-container{
    margin-left: 20px;
    margin-bottom: 15px;
}
rating {
    width: 160px;
    height: 40px;
}

.pass-score{
    margin-left: 20px;
}

.pass-text{
    font-size: 16px;
    color: mediumblue;
}

/*遊戲區域樣式*/
.game-area {
    border: 1px solid black;
    flex-direction: column;
    margin: 20px;
    background-color: lightgreen;
}

.game-tr1 {
    height: 80px;
    border-bottom: 1px solid black;

}

.last-tr {
    border-bottom: none;
    flex: 1;
}

.game-td {
    position: relative;
    width: 80px;
    height: 80px;
    border-right: 1px solid black;
    display: flex;
    justify-content: center;
    align-items: center;
}

.game-pic {
    width: 85%;
    height: 85%;
}

.hammer-pic {
    position: absolute;
    top: 0px;
    left: 20px;
    width: 60px;
    height: 60px;
    z-index: 99;
}

/*按鈕樣式*/

.btn-area {
    display: flex;
    justify-content: center;
    margin-top: 10px;
}

.btn-start {
    width: 100px;
    height: 30px;
}

/*彈框樣式*/
.dialog-div {
    flex-direction: column;
    align-items: center;
}

.area {
    width: 88%;
    border-radius: 5px;
}

.inner-txt {
    width: 80%;
    height: 100px;
    align-items: center;
    flex-direction: column;
    justify-content: space-around;
}

.txt {
    font-size: 18px;
    color: #000000;
    font-weight: bold;
}

.text {
    font-size: 16px;
}

.inner-btn {
    width: 80%;
    height: 100px;
    align-items: center;
    justify-content: space-around;
}
           

3. js部分

export default {
    data: {
        timeInt: 60, //剩餘時間
        countInt: 0, //命中個數
        scoreInt: 0, //得分
        animation: '', //敲擊動畫
        //地鼠資料
        trOne: [
            [{
                 tr: 1,
                 id: 1,
                 idValue: 'A1',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 1,
                 id: 2,
                 idValue: 'A2',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 1,
                 id: 3,
                 idValue: 'A3',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 1,
                 id: 4,
                 idValue: 'A4',
                 showHammer: false,
                 showMose: false
             },],

            [{
                 tr: 2,
                 id: 1,
                 idValue: 'A5',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 2,
                 id: 2,
                 idValue: 'A6',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 2,
                 id: 3,
                 idValue: 'A7',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 2,
                 id: 4,
                 idValue: 'A8',
                 showHammer: false,
                 showMose: false
             },],
            [{
                 tr: 3,
                 id: 1,
                 idValue: 'A9',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 3,
                 id: 2,
                 idValue: 'A10',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 3,
                 id: 3,
                 idValue: 'A11',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 3,
                 id: 4,
                 idValue: 'A12',
                 showHammer: false,
                 showMose: false
             },],
            [{
                 tr: 4,
                 id: 1,
                 idValue: 'A13',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 4,
                 id: 2,
                 idValue: 'A14',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 4,
                 id: 3,
                 idValue: 'A15',
                 showHammer: false,
                 showMose: false
             },
             {
                 tr: 4,
                 id: 4,
                 idValue: 'A16',
                 showHammer: false,
                 showMose: false
             },]
        ], 
        hardRating: 1, //難度等級(預設為1)
        passScore: 1, //命中單個得分
        disAppearTime: 2500, //消失時間
        hardList: [
            {
                hardId: 1,
                add: 1,
                disappear: 2500,
            },
            {
                hardId: 2,
                add: 2,
                disappear: 2000,
            },
            {
                hardId: 3,
                add: 3,
                disappear: 1500,
            },
            {
                hardId: 4,
                add: 5,
                disappear: 500,
            }
        ],
    },
    onInit() {

    },
    onShow() {
        this.hardRating = 1
    },
    //打開彈框
    showDialog(e) {
        this.$element('hintDialog').show()
    },
    //關閉彈框
    closeDialog(e) {
        this.$element('hintDialog').close()
    },
    //開始按鈕 資料清零
    startGame() {
        this.timeInt = 60;
        this.countInt = 0;
        this.scoreInt = 0;
        //生成地鼠
        let moseTimer = setInterval(this.showMose, 100)
        //遊戲時間倒計時
        let countDown = setInterval(() => {
            this.timeInt--;
            //倒計時結束清除定時器
            if (this.timeInt === 0) {
                clearInterval(countDown);
                clearInterval(moseTimer);
                //彈出遊戲結束彈框
                this.showDialog();
            }
        }, 1000)

    },
    //随機生成地鼠
    showMose() {
        let i = Math.round(Math.random() * 3);
        let j = Math.round(Math.random() * 3);
        this.trOne[j][i].showMose = true;
        //根據難度決定隔多少毫秒地鼠消失
        setTimeout(() => {
            this.trOne[j][i].showMose = false;
        }, this.disAppearTime)
    },
    //敲擊地鼠動畫效果
    showHammer(item) {
        this.trOne[item.tr-1][item.id-1].showHammer = true;
        var options = {
            duration: 50,
            easing: 'friction',
            delay: 0,
            fill: 'forwards',
            iterations: 2,
            direction: 'normal',
        };
        var frames = [
            {
                transform: {
                    rotate: '0deg'
                }, opacity: 0.1, offset: 0.0
            },
            {
                transform: {
                    rotate: '-30deg'
                }, opacity: 1.0, offset: 1.0
            }
        ];
        this.animation = this.$element(item.idValue).animate(frames, options);
        this.animation.play();

        //命中數及分數變化
        this.countHander()

        //錘子消失
        setTimeout(() => {
            this.trOne[item.tr-1][item.id-1].showHammer = false;
        }, 300)

    },
    //命中數及分數變化
    countHander() {
        this.trOne.forEach((item, index) => {
            item.forEach((_item, _i) => {
                if (_item.showHammer == true && _item.showMose == true) {
                    this.countInt++;
                    //根據難度計算得分
                    this.scoreInt += this.passScore
                }
            })
        })
    },
    //難度改變
    changeRating(e) {
        this.hardRating = e.rating;
        //命中得分改變
        this.passScore = this.hardList[this.hardRating-1].add;
        //地鼠消失時間改變
        this.disAppearTime = this.hardList[this.hardRating-1].disappear
    }
}

           

總結

對于FA目前還在摸索的路上,這個遊戲寫的比較簡單,思考的不夠全面,還有很多不足之處。希望大家有什麼想法和意見可以提出來,共同進步。

更多原創内容請關注:中軟國際 HarmonyOS 技術團隊

入門到精通、技巧到案例,系統化分享HarmonyOS開發技術,歡迎投稿和訂閱,讓我們一起攜手前行共建鴻蒙生态。

繼續閱讀