0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

玩嗨OpenHarmony:基于OpenHarmony的小游戲:一起學做FlappyBird

共熵服務中心 ? 來源:未知 ? 2022-11-14 19:30 ? 次閱讀
51CTO 開源基礎(chǔ)軟件社區(qū) #跟著小白一起學鴻蒙# [番外]《一起學做FlappyBird》

9ce13ec2-640f-11ed-8abf-dac502259ad0.png

1. 項目的背景

Flappy Bird是一款2013年發(fā)布并在2014年特別流行的一款橫向卷抽游戲。玩家控制一只鳥,試圖在綠色管道之間飛行而不撞到它們。

9d401dc0-640f-11ed-8abf-dac502259ad0.jpg

因為OpenHarmony具備多設(shè)備的窗口框架能力,可以支持不同設(shè)備類型的圖形界面的靈活性。今天我們就一起看看如何能用OpenHarmony學習做個FlappyBird。本文中引用的圖片資源均來自與Github。游戲的效果如下:

9d58d680-640f-11ed-8abf-dac502259ad0.gif

項目源碼如下:

https://gitee.com/wshikh/ohosflappybird

2. HAP應用建立

2.1HAP簡介

HAP文件是在OpenHarmony系統(tǒng)下編譯生成的可執(zhí)行文件。HAP 包是由代碼、資源、第三方庫以及應用配置文件打包生成的模塊包,主要分為兩種類型:entry 和 feature。

OpenHarmony 用戶應用程序包可以只包含一個基礎(chǔ)的 entry 包,也可以包含一個基礎(chǔ)的 entry 包和一個或多個功能型的 feature 包。

entry:應用的主模塊,作為 OpenHarmony 應用的入口,提供了應用的基礎(chǔ)功能。
feature:應用的動態(tài)特性模塊,作為應用能力的擴展,可以根據(jù)用戶的需求和設(shè)備的類型進行選擇性安裝。

2.2HAP開發(fā)工具

本開發(fā)采用:DevEco Studio 3.0 Beta4

HUAWEI DevEco Studio For OpenHarmony是基于IntelliJ IDEA Community開源版本打造,面向OpenHarmony全場景多設(shè)備的一站式集成開發(fā)環(huán)境(IDE),DevEco Studio 3.0支持在HarmonyOS 3.0 Beta版上開發(fā)應用及服務,并已適配ArkUI聲明式編程范式、ArkCompiler方舟編譯,同時提供低代碼開發(fā)、雙向預覽、全新構(gòu)建工具、模擬器、調(diào)試調(diào)優(yōu)、信息中心等功能,為開發(fā)者提供工程模板創(chuàng)建、開發(fā)、編譯、調(diào)試、發(fā)布等E2E的OpenHarmony應用/服務開發(fā)。

下載鏈接:

https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta

2.3ETS

ETS是基于TS擴展的聲明式開發(fā)范式的方舟開發(fā)框架是一套開發(fā)極簡、高性能、跨設(shè)備應用的UI開發(fā)框架,支持開發(fā)者高效的構(gòu)建跨設(shè)備應用UI界面。

基于TS擴展的聲明式開發(fā)范式提供了一系列基礎(chǔ)組件,這些組件以聲明方式進行組合和擴展來描述應用程序的UI界面,并且還提供了基本的數(shù)據(jù)綁定和事件處理機制,幫助開發(fā)者實現(xiàn)應用交互邏輯。

@Entry                                //用@Entry裝飾的自定義組件用作頁面的默認入口組件,也可以理解為頁面的根節(jié)點。   一個頁面有且僅能有一個@Entry,只有被@Entry修飾的組件或者其子組件,才會在頁面上顯示。
@Component                            //@Component裝飾的struct表示該結(jié)構(gòu)體具有組件化能力,能夠成為一個獨立的組件,這種類型的組件也稱為自定義組件,在build方法里描述UI結(jié)構(gòu)。
struct Hello {                         //在聲明式UI中,所有的頁面都是由組件構(gòu)成。組件的數(shù)據(jù)結(jié)構(gòu)為struct
    @State myText: string = 'World'
    build() {                          //build函數(shù)用于定義組件的聲明式UI描述,在build方法中以聲明式方式進行組合自定義組件或系統(tǒng)內(nèi)置組件。
        Column() {                     //Column:沿垂直方向布局的容器。
            Text('Hello')              //Text:顯示一段文本的組件。
                .fontSize(30)
            Text(this.myText)
                .fontSize(32)
            Divider()                  //Divider:提供分隔器組件,分隔不同內(nèi)容塊/內(nèi)容元素。
            Button() {                 //Button:按鈕組件,可快速創(chuàng)建不同樣式的按鈕,通常用于響應用戶的點擊操作。
                Text('Click me')
                .fontColor(Color.Red)
            }.onClick(() => {
                this.myText = 'UI'
            })
            .width(500)
            .height(200)
        }
    }
}

2.4HAP基本概念

  • 裝飾器:方舟開發(fā)框架定義了一些具有特殊含義的裝飾器,用于裝飾類、結(jié)構(gòu)、方法和變量。裝飾器就是某一種修飾,給被裝飾的對象賦予某一種能力,比如@Entry就是頁面入口的能力,@Component就是組件化能力。

  • 自定義組件:可重用的UI單元,可以與其他組件組合,如@Component裝飾的struct Hello。

  • UI描述:聲明性描述UI結(jié)構(gòu),例如build()方法中的代碼塊。

  • 內(nèi)置組件:框架中默認內(nèi)置的基本組件和布局組件,開發(fā)者可以直接調(diào)用,僅用于解釋UI描述規(guī)范。如Column、Text、Divider、Button等。

  • 屬性方法:用于配置組件屬性,如fontSize()、width()、height()、color()等。

  • 事件方法:在事件方法的回調(diào)中添加組件響應邏輯。例如,為Button組件添加onClick方法,在onClick方法的回調(diào)中添加點擊響應邏輯。

2.5page文件

基于TS擴展的聲明式開發(fā)范式提供了一系列基礎(chǔ)組件,如:基礎(chǔ)組件,容器組件,媒體組件,繪制組件和畫布組件等,本節(jié)我們主要使用畫布組件。

這里我們就不贅述Hap項目的建立過程,以下就是基礎(chǔ)的Hap的page文件:index.ets

  build() {
    Row() {
      Column() {
        Canvas(this.context)
          .width('100%')
          .height('100%')
          .onClick((ev: ClickEvent) => {
            console.info("click!!")
            //響應鼠標左擊
            this.doClick()
          })
          .onReady(() =>{
            //繪制基礎(chǔ)
            this.context.imageSmoothingEnabled = false
            this.drawBlock()
          })
      }
      .width('100%')
    }
    .height('100%')
    .backgroundImage($r("app.media.backgroundday"))
    .backgroundImageSize(ImageSize.Cover)
  }

build是基礎(chǔ)頁面的構(gòu)造函數(shù),用于界面的元素構(gòu)造,其他的頁面的生命周期函數(shù)如下:

declare class CustomComponent {
  /**
   * Customize the pop-up content constructor.
   * @since 7
   */
  build(): void;


  /**
   * aboutToAppear Method
   * @since 7
   */
  aboutToAppear?(): void;


  /**
   * aboutToDisappear Method
   * @since 7
   */
  aboutToDisappear?(): void;


  /**
   * onPageShow Method
   * @since 7
   */
  onPageShow?(): void;


  /**
   * onPageHide Method
   * @since 7
   */
  onPageHide?(): void;


  /**
   * onBackPress Method
   * @since 7
   */
  onBackPress?(): void;
}
3. Canvas畫布介紹

canvas是畫布組件用于自定義繪制圖形,具體的API頁面如下:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-components-canvas-canvas-0000001333641081

頁面顯示前會調(diào)用aboutToAppear()函數(shù),此函數(shù)為頁面生命周期函數(shù)。

canvas組件初始化完畢后會調(diào)用onReady()函數(shù),函數(shù)內(nèi)部實現(xiàn)小游戲的初始頁面的繪制。

3.1初始化頁面數(shù)據(jù)

  drawBlock() {
    this.context.clearRect(0,0,this.context.width,this.context.height)
    this.context.drawImage( this.baseImg,this.baseX,this.baseY,500,300)
    switch(this.flappyState) {
      case 0:
        this.context.drawImage( this.messageImg,this.startX,this.startY,300,500)
        this.drawBird()
        break;
      case 1:
        this.drawBird()
        this.context.drawImage( this.pipegreenImg,this.pipeX,this.pipeY,50,150)
        break;
      case 2:
        this.context.drawImage( this.gameoverImg,this.startX,this.startY*3,300,90)
        break
    }
}

頁面狀態(tài)有三:

  • 0:等待開始界面

  • 1:游戲進行

  • 2:游戲結(jié)束

3.2繪制Bird

  drawBird() {
    switch(this.birdType) {
      case 0:
        this.context.drawImage( this.midbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break
      case 1:
        this.context.drawImage( this.upbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break;
      case 2:
        this.context.drawImage( this.downbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break;
      default:
        break;
    }
}

小鳥飛行狀態(tài)有三種:

  • 翅膀在中間:0

  • 翅膀在上:1

  • 翅膀在下:2

4. 游戲邏輯

4.1 主體游戲邏輯:

簡單的小游戲主體游戲邏輯為:等待開始,開始,結(jié)束流程圖如下:

graph LR
等待開始 --> click[點擊]
click[點擊] --> 游戲開始
游戲開始 --> 點擊 --> |游戲開始|小鳥飛,水管動 --> |小鳥碰到水管| 游戲結(jié)束 --> 點擊 --> |游戲結(jié)束| 等待開始
小鳥飛,水管動 --> |小鳥沒碰到水管| 游戲繼續(xù) --> 點擊
doClick() {
    switch (this.flappyState) {
      case 0:
        {
          // 開始
          this.flappyState = 1
          break
        }
      case 1:
        {
          //上下飛
          //        this.flappyState = 2
          this.slotY -= this.flyHeight
          console.log(this.slotY.toString())
          break
        }
      case 2:
        {
          //由結(jié)束到待開始
          this.flappyState = 0
          this.slotY = this.slotStartY
          this.pipeX = this.pipeStartX
          break
        }
      default:
        break
    }
    this.drawBlock()
}
4.2 完整游戲邏輯:
@Entry
@Component
struct Index {
  @State message: string = 'Hello World'
  private baseImg:ImageBitmap = new ImageBitmap("common/images/base.png")
  private messageImg:ImageBitmap = new ImageBitmap("common/images/message.png")
  private zeroImg:ImageBitmap = new ImageBitmap("common/images/0.png")
  private gameoverImg:ImageBitmap = new ImageBitmap("common/images/gameover.png")
  private upbirdImg:ImageBitmap = new ImageBitmap("common/images/bluebirdupflap.png")
  private midbirdImg:ImageBitmap = new ImageBitmap("common/images/bluebirdmidflap.png")
  private downbirdImg:ImageBitmap = new ImageBitmap("common/images/bluebirddownflap.png")
  private pipegreenImg:ImageBitmap = new ImageBitmap("common/images/pipegreen.png")
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  private flappyState: number = 0
  private startX = 30;
  private startY = 100;
  private slotStartY = 410;
  private slotX = 50;
  private slotY = this.slotStartY;
  private baseX = 0;
  private baseY = 650;
  private pipeStartX = 330;
  private pipeX = this.pipeStartX;
  private pipeY = 500;
  private birdH = 60;
  private birdW = 50;
  private birdTimer: number;
  private birdType: number = 0;
  private count = 1;
  private flyHeight = 20;
  private pipeMove = 10;




  drawBird() {
    switch(this.birdType) {
      case 0:
        this.context.drawImage( this.midbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break
      case 1:
        this.context.drawImage( this.upbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break;
      case 2:
        this.context.drawImage( this.downbirdImg,this.slotX,this.slotY,this.birdH,this.birdW)
        break;
      default:
        break;
    }
  }


  drawBlock() {
    this.context.clearRect(0,0,this.context.width,this.context.height)
    this.context.drawImage( this.baseImg,this.baseX,this.baseY,500,300)
    switch(this.flappyState) {
      case 0:
        this.context.drawImage( this.messageImg,this.startX,this.startY,300,500)
        this.drawBird()
        break;
      case 1:
        this.drawBird()
        this.context.drawImage( this.pipegreenImg,this.pipeX,this.pipeY,50,150)
        break;
      case 2:
        this.context.drawImage( this.gameoverImg,this.startX,this.startY*3,300,90)
        break
    }
  }


  doClick() {
    switch (this.flappyState) {
      case 0:
        {
          // 開始
          this.flappyState = 1
          break
        }
      case 1:
        {
          //上下飛
          //        this.flappyState = 2
          this.slotY -= this.flyHeight
          console.log(this.slotY.toString())
          break
        }
      case 2:
        {
          //由結(jié)束到待開始
          this.flappyState = 0
          this.slotY = this.slotStartY
          this.pipeX = this.pipeStartX
          break
        }
      default:
        break
    }
    this.drawBlock()
  }


  doFly(): void {
    console.log("dofly ------ !!")
    this.birdType += 1
    if (this.birdType/5 == 0) {
      this.message = "dofly ---555--- !!"
    }
  }


  async sleep(ms: number) {
    return new Promise((r) => {
      setInterval(() => {
        this.birdType += 1
        this.message = this.birdType.toString()
        if (this.birdType == 3) {
          this.birdType = 0
        }
        console.log(this.message)
        if (this.flappyState == 1) {
          this.pipeX -= this.pipeMove
          if (this.pipeX < 0) {
            this.pipeX = 330
          }
          this.slotY += this.flyHeight/5
        }


        if ((((this.pipeX-this.slotX) <= this.birdW) && ((this.pipeY-this.slotY) <= this.birdH)) ||
          this.pipeY >= this.baseY) {
          this.flappyState = 2
        }
        this.drawBlock()
      }, ms)
    })
  }


  aboutToDisappear() {
  }


  aboutToAppear() {
    this.sleep(200)
  }


  build() {
    Row() {
      Column() {
        Canvas(this.context)
          .width('100%')
          .height('100%')
          .onClick((ev: ClickEvent) => {
            console.info("click!!")
            this.doClick()
          })
          .onReady(() =>{
            this.context.imageSmoothingEnabled = false
            this.drawBlock()
          })
      }
      .width('100%')
    }
    .height('100%')
    .backgroundImage($r("app.media.backgroundday"))
    .backgroundImageSize(ImageSize.Cover)
  }
}
5. 游戲的瑕疵
  • 水管只在下層顯示:可以在上層顯示;

  • 地面沒有讓動

  • 游戲聲音問題:目前ohos不支持音頻播放資源音頻,看之后版本是否支持

  • DevEcoy用setInterval重繪canvas會導致ide崩潰

a3c66654-640f-11ed-8abf-dac502259ad0.gif

本文完

寫在最后我們最近正帶著大家玩嗨OpenHarmony。如果你有好玩的東東,歡迎投稿,讓我們一起嗨起來!有點子,有想法,有Demo,立刻聯(lián)系我們:合作郵箱:zzliang@atomsource.org
a3da5f60-640f-11ed-8abf-dac502259ad0.gif

a3eb2db8-640f-11ed-8abf-dac502259ad0.png

a40822ba-640f-11ed-8abf-dac502259ad0.pnga438be84-640f-11ed-8abf-dac502259ad0.pnga46ade5a-640f-11ed-8abf-dac502259ad0.png

a49ec0b2-640f-11ed-8abf-dac502259ad0.png

a4bdbcec-640f-11ed-8abf-dac502259ad0.png

a4de89f4-640f-11ed-8abf-dac502259ad0.png

a529bcbc-640f-11ed-8abf-dac502259ad0.png

a59f1c46-640f-11ed-8abf-dac502259ad0.png

a5db64da-640f-11ed-8abf-dac502259ad0.png

a605dd28-640f-11ed-8abf-dac502259ad0.png

a63d209e-640f-11ed-8abf-dac502259ad0.png

a65666c6-640f-11ed-8abf-dac502259ad0.png

a6a519d8-640f-11ed-8abf-dac502259ad0.png

a6bdc2bc-640f-11ed-8abf-dac502259ad0.png

a72b8a9a-640f-11ed-8abf-dac502259ad0.png

a75f2594-640f-11ed-8abf-dac502259ad0.png


原文標題:玩嗨OpenHarmony:基于OpenHarmony的小游戲:一起學做FlappyBird

文章出處:【微信公眾號:開源技術(shù)服務中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 開源技術(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    389

    瀏覽量

    7978
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3732

    瀏覽量

    16452

原文標題:玩嗨OpenHarmony:基于OpenHarmony的小游戲:一起學做FlappyBird

文章出處:【微信號:開源技術(shù)服務中心,微信公眾號:共熵服務中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    OpenHarmony:基于OpenHarmony的仿生四足狗開發(fā)分享

    OpenHarmony(以下簡稱“OpenHarmony”)系統(tǒng)的機器狗。本文將給大家分享些他開發(fā)過程中的心得體會。 開發(fā)項目簡介 說起人工智能機器
    的頭像 發(fā)表于 10-31 21:50 ?3793次閱讀

    小游戲貪食蛇教程

    小游戲貪食蛇教程,歡迎大家一起來學習
    發(fā)表于 08-07 16:29

    一起來吐槽下學習openharmony的那些事

    歡迎新老入坑openharmony的人來一起吐槽下,看看在學習openharmony的過程中有遇到什么困擾。先吐槽兩點1.過了年了碰碰這
    發(fā)表于 10-14 21:18

    DAYU200 2048 小游戲- OpenHarmony

    。當按某個方向鍵時,所有非空的格子都會往這個方向滑動。如果在滑動的過程中兩個數(shù)字相同的格子碰到一起,那么就會把這兩個數(shù)字相加從而合并成個新格子。只要有格子合并,分數(shù)就會增加?;瑒硬⒑喜⒅?,會從所有
    發(fā)表于 05-10 15:45

    OpenHarmony 生態(tài)動向【潤和軟件】

    OpenHarmony生態(tài)動向【潤和軟件】,多款開發(fā)板展示,其中DAYU200開發(fā)套件實現(xiàn)手機電話短信功能、音樂播放器、攝像機、商城、健康app、小游戲等等。你覺得OpenHarmony手機面世還會遠嗎?
    發(fā)表于 06-01 10:18

    用JS寫OpenHarmony拼圖小游戲

    1. 樣例效果本Demo是基于OpenHarmony3.0 LTS,使用JS語言編寫的拼圖小游戲。
    發(fā)表于 07-27 18:24

    【開發(fā)樣例】用JS寫OpenHarmony拼圖小游戲

    、簡介1.樣例效果本Demo是基于OpenHarmony3.0 LTS,使用JS語言編寫的拼圖小游戲。2.涉及OpenHarmony技術(shù)特性JS UI3.支持
    發(fā)表于 07-29 14:25

    基于 OpenHarmony 拳擊健康游戲應用

    樣例簡介拳擊健康游戲應用是基于OpenHarmony 3.2 Beta標準系統(tǒng)上開發(fā)的eTS應用,本應用運行于RK3568,游戲開始會隨著音樂播放會拳擊方庫進行隨機速度下落,樣例利用NAPI組件獲取
    發(fā)表于 08-31 11:20

    【直播回顧】OpenHarmony知識賦能第八期:手把手教你實現(xiàn)涂鴉小游戲

    【直播回顧】OpenHarmony知識賦能第八期:手把手教你實現(xiàn)涂鴉小游戲OpenHarmony第八期知識賦能直播已經(jīng)在9月29日圓滿落幕!從9月15日,資深OS框架開發(fā)工程師巴延興
    發(fā)表于 10-10 15:58

    Unity中國、Cocos為OpenHarmony游戲生態(tài)插上騰飛的翅膀

    2023年是OpenHarmony游戲生態(tài)百花齊放的年!為了擴展OpenHarmony游戲生態(tài),Ope
    發(fā)表于 10-23 16:15

    基于STM32設(shè)計的拼圖小游戲詳解

    拼圖游戲在小時候還是經(jīng)常,玩法也比較簡單,這里就使用STM32設(shè)計個拼圖小游戲分享出來一起學習。 目前
    的頭像 發(fā)表于 02-28 13:45 ?3380次閱讀
    基于STM32設(shè)計的拼圖<b class='flag-5'>小游戲</b>詳解

    OpenHarmony:基于OpenHarmony的機械狗進階版——聽話的狗子

    原文引自CSDN社區(qū) 《[立創(chuàng)傳智黑馬程序員CSDN]訓練營——仿生機械狗》 編者按 昨天的 《 OpenHarmony:基于OpenHarmony的仿生四足狗開發(fā)分享 》 ,大家
    的頭像 發(fā)表于 11-01 21:25 ?1706次閱讀

    OpenHarmony:基于OpenHarmony的道路維護方案

    抵御災害能力和可持續(xù)的城市和人類住區(qū)中的交通問題,在此提出種基于OpenHarmony實現(xiàn)道路維護的方案,通過深度學習的方式對道路的裂縫進行實時檢測,增加道路的可持續(xù)使用性。 由于傳統(tǒng)的道路裂縫檢測精度和距離有限,大部分仍需要人工檢測,而人工裂縫檢測的過程又十分的繁瑣
    的頭像 發(fā)表于 11-02 21:20 ?1403次閱讀

    OpenHarmony:基于OpenHarmony的貪吃蛇小游戲

    51CTO 開源基礎(chǔ)軟件社區(qū) #夏日挑戰(zhàn)賽# 《 OpenHarmony基于JS實現(xiàn)的貪吃蛇 》 1. 項目簡介 貪吃蛇是款非常經(jīng)典的小游戲,概念起源于1976年由美國家街機
    的頭像 發(fā)表于 11-28 20:50 ?1325次閱讀

    OpenHarmony:基于OpenHarmony的ArkUI翻頁時鐘

    原文引自:51CTO 開源基礎(chǔ)軟件社區(qū) #夏日挑戰(zhàn)賽# OpenHarmony - 《 ArkUI(TS)開發(fā)翻頁時鐘 》 1. 項目背景 翻頁時鐘(Flip Clock)是種有趣的機電數(shù)字計時
    的頭像 發(fā)表于 12-05 20:15 ?1439次閱讀