在 9 月 30號更新的 OpenHarmony3.0 LTS 上,標準系統(tǒng)新增支持了方舟開發(fā)框架(ArkUI)、分布式組網(wǎng)和 FA 跨設(shè)備遷移能力等新特性,因此我們結(jié)合了這三種特性使用 ets 開發(fā)了一款如下圖所示傳炸彈應(yīng)用。
打開應(yīng)用在通過邀請用戶進行設(shè)備認證后,用戶須根據(jù)提示完成相應(yīng)操作,然后通過分布式流轉(zhuǎn)實現(xiàn)隨機傳遞炸彈給下一位用戶的效果。
那么這樣一款傳炸彈應(yīng)用如何進行開發(fā)呢?完整的項目結(jié)構(gòu)目錄如下:
├─entry │└─src │└─main ││config.json//應(yīng)用配置 ││ │├─ets ││└─MainAbility │││app.ets//ets應(yīng)用程序主入口 │││ ││└─pages ││CommonLog.ets//日志類 ││game.ets//游戲首頁 ││RemoteDeviceManager.ets//設(shè)備管理類 ││ │└─resources//靜態(tài)資源目錄 │├─base ││├─element │││ ││├─graphic ││├─layout ││├─media//存放媒體資源 │││ ││└─profile │└─rawfile
我們可以分為如下 3 步:
編寫聲明式 UI 界面
添加分布式能力
編寫游戲邏輯
編寫聲明式UI 界面
①新增工程
在 DevEco Studio 中點擊 File→New Project→Standard Empty Ability→Next,Language 選擇 ETS 語言,最后點擊 Finish 即創(chuàng)建成功。
②編寫游戲頁面
效果圖如下可以分為兩部分:
頂部狀態(tài)提示欄:
首先在 @entry 組件入口 build() 中使用 Stack 作為容器,達到圖片和文字堆疊的效果。
接著依次寫入 Image 包裹的兩個 Text 組件。
Stack(){
Image($r("app.media.title")).objectFit(ImageFit.Contain).height(120)
Column(){
Text(this.duration.toString()+'ms').fontColor(Color.White)
Text(this.touchText).fontColor(Color.White)
}
}
中間游戲炸彈九宮格區(qū)域:
使用 Grid 網(wǎng)格容器來編寫九宮格區(qū)域。
在 GridItem 中 Stack (容器依次添加方塊背景圖片和炸彈圖片。
在 visibility 屬性中用 bombIndex 變量值來決定炸彈顯示的位置。
通過 onClick 點擊事件和 GestureGroup 組合手勢加入單擊、雙擊和長按的監(jiān)聽事件。
Stack(){
Image($r("app.media.background")).objectFit(ImageFit.Contain)
Grid(){
ForEach(this.grid,(item)=>{
GridItem(){
Stack(){
Image($r("app.media.squares")).objectFit(ImageFit.Contain)
Image($r("app.media.bomb"))
.width('50%')
.objectFit(ImageFit.Contain)
.visibility(this.bombIndex==item?Visibility.Visible:Visibility.Hidden)
//炸彈點擊事件
.onClick((event)=>{
//單擊
this.judgeGame(RuleType.click)
})
.gesture(
GestureGroup(GestureMode.Exclusive,
LongPressGesture({repeat:false})
.onAction((event:GestureEvent)=>{
//長按
this.judgeGame(RuleType.longPress)
}),
TapGesture({count:2})
.onAction(()=>{
//雙擊
this.judgeGame(RuleType.doubleClick)
})
)
}
}.forceRebuild(false)
},item=>item)
}
.columnsTemplate('1fr1fr1fr')
.rowsTemplate('1fr1fr1fr')
.columnsGap(10)
.rowsGap(10)
.width('90%')
.height('75%')
}.width('80%').height('70%')
 ③添加彈窗
創(chuàng)建規(guī)則游戲彈窗:通過@CustomDialog 裝飾器來創(chuàng)建自定義彈窗,使用方式可參考《自定義彈窗文檔》:
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/js-reference/ts-based-declarative-development-paradigm/ts-methods-custom-dialog-box.md
規(guī)則彈窗效果如下,彈窗組成由兩個 Text 和兩個 Image 豎向排列組成,所以我們可以在 build() 下使用 Column 容器來包裹。
組件代碼如下:
@CustomDialog structRuleDialog{ controller:CustomDialogController confirm:()=>void invite:()=>void @ConsumedeviceList:RemoteDevice[] build(){ Column(){ Text('游戲規(guī)則').fontSize(30).margin(20) Text('炸彈會隨機出現(xiàn)在9個方塊內(nèi),需要在規(guī)定時間內(nèi)完成指定操作(點擊、雙擊或長按),即可將炸彈傳遞給下一個人,小心炸彈可是會越來越快的喔!') .fontSize(24).margin({bottom:10}) Image($r("app.media.btn_start")).objectFit(ImageFit.Contain).height(80).margin(10) .onClick(()=>{ console.info(TAG+'Clickstartgame') if(checkTrustedDevice(this.remoteDeviceModel)){ this.controller.close() this.confirm() } }) Image($r("app.media.btn_Invite")).objectFit(ImageFit.Contain).height(80).margin(10) .onClick(()=>{ this.invite() }) }.width('90%') .margin(20) .backgroundColor(Color.White) } }
在 @entry 創(chuàng)建 CustomDialogController 對象并傳入彈窗所需參數(shù),后面可通過該對象 open() 和 close() 方法進行打開和關(guān)閉彈窗。
@ProvidedeviceList:RemoteDevice[]=[]
privateruleDialog:CustomDialogController=newCustomDialogController({
builder:RuleDialog({
invite:()=>this.InvitePlayer(),
confirm:()=>this.startGame(),
deviceList:this.deviceList
}),
autoCancel:false
})
創(chuàng)建游戲失敗彈窗,并添加動畫效果,如下圖:
編寫彈窗布局:將游戲失敗文本、炸彈圖片和再來一局按鈕圖片放置于 Column 容器中。
用變量來控制動畫起始和結(jié)束的位置:用 Flex 容器包裹炸彈圖片,并用 @State 裝飾變量 toggle,通過變量來動態(tài)修改 [Flex] 的 direction 屬性。
@Statetoggle:boolean=true
privatecontroller:CustomDialogController
@ConsumedeviceList:RemoteDevice[]
privateconfirm:()=>void
privateinterval=null
build(){
Column(){
Text('游戲失敗').fontSize(30).margin(20)
Flex({
direction:this.toggle?FlexDirection.Column:FlexDirection.ColumnReverse,
alignItems:ItemAlign.Center
})
{
Image($r("app.media.bomb")).objectFit(ImageFit.Contain).height(80)
}.height(200)
Image($r("app.media.btn_restart")).objectFit(ImageFit.Contain).height(120).margin(10)
.onClick(()=>{
this.controller.close()
this.confirm()
})
}
.width('80%')
.margin(50)
.backgroundColor(Color.White)
}
設(shè)置動畫效果:使用 animateTo 顯式動畫接口炸彈位置切換時添加動畫,并且設(shè)置定時器定時執(zhí)行動畫。
aboutToAppear(){
this.setBombAnimate()
}
setBombAnimate(){
letfun=()=>{
this.toggle=!this.toggle;
}
this.interval=setInterval(()=>{
animateTo({duration:1500,curve:Curve.Sharp},fun)
},1600)
}
 
添加分布式流轉(zhuǎn)
分布式流轉(zhuǎn)需要在同一網(wǎng)絡(luò)下通過 DeviceManager 組件進行設(shè)備間發(fā)現(xiàn)和認證。
獲取到可信設(shè)備的 deviceId 調(diào)用 FeatureAbility.startAbility(parameter),即可把應(yīng)用程序流轉(zhuǎn)到另一設(shè)備。
原本分布式流轉(zhuǎn)應(yīng)用流程如下:
創(chuàng)建 DeviceManager 實例。
調(diào)用實例的 startDeviceDiscovery(),開始設(shè)備發(fā)現(xiàn)未信任設(shè)備。
設(shè)置設(shè)備狀態(tài)監(jiān)聽 on('deviceStateChange',callback),監(jiān)聽設(shè)備上下線狀態(tài)。
設(shè)置設(shè)備狀態(tài)監(jiān)聽 on('deviceFound',callback),監(jiān)聽設(shè)備發(fā)現(xiàn)。
傳入未信任設(shè)備參數(shù),調(diào)用實例 authenticateDevice 方法,對設(shè)備進行 PIN 碼認證。
若是已信任設(shè)備,可通過實例的 getTrustedDeviceListSync() 方法來獲取設(shè)備信息。
將設(shè)備信息中的 deviceId 傳入featureAbility.startAbility 方法,實現(xiàn)流轉(zhuǎn)。
流轉(zhuǎn)接收方可通過 featureAbility.getWant() 獲取到發(fā)送方攜帶的數(shù)據(jù)。
注銷設(shè)備發(fā)現(xiàn)監(jiān)聽 off('deviceFound')。
注銷設(shè)備狀態(tài)監(jiān)聽 off('deviceStateChange')。
項目中將上面設(shè)備管理封裝至 RemoteDeviceManager,通過 RemoteDeviceManager 的四個方法來動態(tài)維護 deviceList 設(shè)備信息列表。
項目實現(xiàn)分布式流轉(zhuǎn)只需如下流程:
①創(chuàng)建 RemoteDeviceManager 實例
導入 RemoteDeviceManager:
import{RemoteDeviceManager}from'./RemoteDeviceManager'
聲明 @Provide 裝飾的設(shè)備列表變量 deviceList,和創(chuàng)建 RemoteDeviceManager 實例。
@ProvidedeviceList:RemoteDevice[]=[] privateremoteDm:RemoteDeviceManager=newRemoteDeviceManager(this.deviceList)
②刷新設(shè)備列表
在生命周期 aboutToAppear 中,調(diào)用刷新設(shè)備列表和開始發(fā)現(xiàn)設(shè)備。
aboutToAppear 定義:函數(shù)在創(chuàng)建自定義組件的新實例后,在執(zhí)行其 build 函數(shù)之前執(zhí)行。
aboutToAppear(){
this.remoteDm.refreshRemoteDeviceList()//刷新設(shè)備列表
this.remoteDm.startDeviceDiscovery()//開始發(fā)現(xiàn)設(shè)備
}
③設(shè)備認證
代碼如下:
invitePlayer(remoteDevice:RemoteDevice){
if(remoteDevice.status==RemoteDeviceStatus.ONLINE){
prompt.showToast({message:"Alreadyinvited!"})
return
}
this.remoteDm.authDevice(remoteDevice).then(()=>{
prompt.showToast({message:"Invitesuccess!deviceName="+remoteDevice.deviceName})
}).catch(()=>{
prompt.showToast({message:"Invitefail!"})
})
}
④跨設(shè)備流轉(zhuǎn)
從 deviceList 中獲取設(shè)備列表在線的設(shè)備 Id,通過 featureAbility.startAbility 進行流轉(zhuǎn)。
asyncstartAbilityRandom(){
letdeviceId=this.getRandomDeviceId()//隨機獲取設(shè)備id
CommonLog.info('featureAbility.startAbilitydeviceId='+deviceId);
letbundleName=awaitgetBundleName()
letwantValue={
bundleName:bundleName,
abilityName:'com.sample.bombgame.MainAbility',
deviceId:deviceId,
parameters:{
ongoing:true,
transferNumber:this.transferNumber+1
}
};
featureAbility.startAbility({
want:wantValue
}).then((data)=>{
CommonLog.info('featureAbility.startAbilityfinished,'+JSON.stringify(data));
featureAbility.terminateSelf((error)=>{
CommonLog.info('terminateSelffinished,error='+error);
});
});
}
 ⑤注銷監(jiān)聽
在聲明周期 aboutToDisappear 進行注銷監(jiān)聽。
aboutToDisappear 定義:函數(shù)在自定義組件析構(gòu)消耗之前執(zhí)行。
aboutToDisappear(){
this.remoteDm.stopDeviceDiscovery()//注銷監(jiān)聽
}
 
編寫游戲邏輯
①開始游戲
代碼如下:
startGame(){
CommonLog.info('startGame');
this.randomTouchRule()//隨機游戲點擊規(guī)則
this.setRandomBomb()//隨機生成炸彈位置
this.stopCountDown()//停止倒計時
if(this.transferNumber10)?{
????this.duration?=?3000?-?this.transferNumber?*?100
??}?else?{
????this.duration?=?2000
??}
??const?interval:?number?=?500
??//?開始倒計時
??this.timer?=?setInterval(()?=>{
if(this.duration<=?interval)?{
??????this.duration?=?0
??????clearInterval(this.timer)
??????this.timer?=?null
??????this.gameFail()
????}?else?{
??????this.duration?-=?interval
????}
??},?interval)
}
②判斷輸贏
編寫判斷邏輯,用于不同的點擊事件中調(diào)用。
/**
*判斷游戲輸贏
*@paramoperation點擊類型
*/
judgeGame(operation:RuleType){
this.stopCountDown()
if(operation!=this.ruleText){
this.gameFail()
}else{
prompt.showToast({message:"finish"})
this.bombIndex=-1
this.startAbilityRandom()
}
}
③游戲失敗
游戲失敗,彈出游戲失敗彈框。
gameFail(){
prompt.showToast({
message:'GameFail'
})
CommonLog.info('gameFail');
this.gameFailDialog.open()
}
 
項目下載和導入
項目倉庫地址:
https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Entertainment/BombGame
①git 下載:
gitclonehttps://gitee.com/openharmony-sig/knowledge_demo_temp.git
②項目導入:打開 DevEco Studio,點擊 File→Open→下載路徑/FA/Entertainment/BombGame。
約束與限制
①設(shè)備編譯約束
獲取 OpenHarmony 源碼(OpenHarmony 版本須 3.0LTS 以上):
https://www.openharmony.cn/pages/0001000202/#%E5%AE%89%E8%A3%85%E5%BF%85%E8%A6%81%E7%9A%84%E5%BA%93%E5%92%8C%E5%B7%A5%E5%85%B7
安裝開發(fā)板環(huán)境:
https://www.openharmony.cn/pages/0001000400/#hi3516%E5%B7%A5%E5%85%B7%E8%A6%81%E6%B1%82
開發(fā)板燒錄:
https://www.openharmony.cn/pages/0001000401/#%E4%BD%BF%E7%94%A8%E7%BD%91%E5%8F%A3%E7%83%A7%E5%BD%95
②應(yīng)用編譯約束
參考《應(yīng)用開發(fā)快速入門》:
https://www.openharmony.cn/pages/00090000/
集成開發(fā)環(huán)境:DevEco Studio 3.0.0.601 版本以上,下載地址:
https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta
OpenHarmony SDK 3.0.0.0 以上。
作者:林嘉成 OpenAtom OpenHarmony
原文標題:OpenHarmony上玩“傳炸彈”小游戲
文章出處:【微信公眾號:HarmonyOS技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
- 
                                容器
                                +關(guān)注關(guān)注 0文章 521瀏覽量 22759
- 
                                OpenHarmony
                                +關(guān)注關(guān)注 31文章 3900瀏覽量 20547
原文標題:OpenHarmony上玩“傳炸彈”小游戲
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
JTAG開發(fā)板與ST-Link是如何進行連接的
HarmonyOS與OpenHarmony應(yīng)用開發(fā)差異
應(yīng)用熱更新如何進行嵌入式設(shè)備開發(fā)調(diào)試?
OpenHarmony標準設(shè)備應(yīng)用開發(fā)筆記匯總
如何進行 OpenHarmony 設(shè)備開發(fā)?
趙海鵬:如何進行 OpenHarmony 音頻特性架構(gòu)設(shè)計和開發(fā)工作
STM32單片機如何進行開發(fā)環(huán)境的搭建
 
    
openharmony開發(fā)企業(yè)有哪些
如何進行OPCDCOM配置
 
    
OpenHarmony開發(fā)體系內(nèi)容介紹
基于ArkTS語言的OpenHarmony APP應(yīng)用開發(fā):HelloOpenharmony
 
    
 
           
        
 
         OpenHarmony傳***應(yīng)用如何進行開發(fā)
OpenHarmony傳***應(yīng)用如何進行開發(fā) 
                 
  
     
     
            
             
             
                 
             工商網(wǎng)監(jiān)
工商網(wǎng)監(jiān)
        
評論