<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      使用 Flutter 與 Firebase 制作 I/O 彈球游戲

      文/ Very Good Ventures 團隊,5 月 11 日發表于 Flutter 官方博客

      為了今年的 Google I/O 大會,Flutter 團隊使用 Flutter 以及 Firebase 構建了一款經典的彈球游戲。下面將會介紹我們是如何通過 Flame 游戲引擎將 I/O 彈球游戲 帶到 Web 端的。

      游戲開發要點

      使用 Flutter 打造用戶交互類型的游戲是一個很棒的選擇,例如拼圖或者文字游戲這樣的游戲。Flame 是一個在 Flutter 上構建的 2D 游戲引擎,當涉及到使用游戲循環的游戲時它會非常有用。I/O 彈球游戲使用了 Flame 提供的一系列特性,例如動畫、物理引擎、碰撞檢測等等,同時還借助了 Flutter 框架的基礎架構。如果你能用 Flutter 構建應用,你就獲得 Flame 構建游戲所需的基礎。

      游戲循環

      通常來說應用屏幕在沒有用戶交互事件的時候都會保持視覺靜止狀態。游戲中則是相反的—— UI 會持續的渲染,而且游戲狀態會不斷變化。Flame 提供了一個 game widget,它內部管理了一個游戲循環,所以能恒定且高效地進行渲染。Game 類包含了游戲組件以及其邏輯的實現,然后被交給 widget 樹中的 GameWidget。在 I/O 彈球游戲中,游戲循環反映了彈球在游戲場的位置以及狀態,然后如果球與物體碰撞或跌出比賽則需要給出必要的反饋。

      @override
      void update(double dt) {
        super.update(dt);
        final direction = -parent.body.linearVelocity.normalized();
        angle = math.atan2(direction.x, -direction.y);
        size = (_textureSize / 45) * 
          parent.body.fixtures.first.shape.radius;
      }
      

      使用 2D 組件渲染 3D 空間

      在做 I/O 彈球游戲的時候,其中遇到的一個挑戰即是如何使用 2D 元素渲染一個 3D 的交互體驗。組件需要知道在屏幕上渲染的前后順序。例如,當小球發射到斜坡上時,它的順序會向前,這樣就會讓它看起來出現在斜坡的頂部。

      彈球、彈射活塞、擋板以及 Chrome 小恐龍等等這些元素都是可活動的,這意味著它應該遵循真實世界的物理規則。而且彈球也需要根據它在板子上的位置改變其大小。當彈球滾到頂部時,它應該越來越小,以讓它看著離用戶更遠。此外,重力還會讓彈球調整角度,讓它能在斜坡上更快地落下。

      /// Scales the ball's body and sprite according to its position on the board.
      class BallScalingBehavior extends Component with ParentIsA<Ball> {
        @override
        void update(double dt) {
          super.update(dt);
          final boardHeight = BoardDimensions.bounds.height;
          const maxShrinkValue = BoardDimensions.perspectiveShrinkFactor;
          final standardizedYPosition = parent.body.position.y +   (boardHeight / 2);
          final scaleFactor = maxShrinkValue +
              ((standardizedYPosition / boardHeight) * (1 - maxShrinkValue));
      parent.body.fixtures.first.shape.radius = (Ball.size.x / 2) * scaleFactor;
      final ballSprite = parent.descendants().whereType<SpriteComponent>();
          if (ballSprite.isNotEmpty) {
            ballSprite.single.scale.setValues(
              scaleFactor,
              scaleFactor,
            );
          }
        }
      }
      

      Forge 2D 的物理引擎

      I/O 彈球游戲很大程度依賴了 Flame 團隊維護的 forge2d package。這個 package 將開源的 Box2D 物理引擎 移植到 Dart 中,以便可以輕松集成到 Flutter。我們使用 forge2d 增強游戲中的物理特性,例如物體(夾板)在游戲場上的之間的碰撞檢測。使用 forge2D 能夠我們監聽夾板發生碰撞的時機。我們就可以在這里向夾板添加交互的回調,當兩個物體發生碰撞的時候我們就能收到通知。例如,彈球(它是圓形的)與彈簧(它是橢圓形的)接觸時,我們就會增加它的得分。在這些回調中,我們可以清楚地設置接觸開始和結束的位置,以便當兩個物體相互接觸時,會發生碰撞。

      @override
      Body createBody() {
        final shape = CircleShape()..radius = size.x / 2;
        final bodyDef = BodyDef(
          position: initialPosition,
          type: BodyType.dynamic,
          userData: this,
        );
        return world.createBody(bodyDef)
          ..createFixtureFromShape(shape, 1);
      }
      

      Sprite sheet 動畫

      在彈球游戲場中有一些小東西,例如 Android、Dash(Dart 吉祥物)、Sparky(Firebase 吉祥物)以及 Chrome 小恐龍,這些都是動畫。對于這些東西,我們使用了 sprite sheets,它已經包含在 Flame 引擎中了,叫做 SpriteAnimationComponent。對于每個元素,我們都有一個文件,其中包含不同方向的圖像、文件中的幀數以及幀之間的時間。使用這些數據,Flame 中的 SpriteAnimationComponent 能夠在一個循環中將所有圖像編在一起,使元素看起來在運動。

      △ Sprite sheet 示例

      △ Sprite sheet 示例

      final spriteSheet = gameRef.images.fromCache(
        Assets.images.android.spaceship.animatronic.keyName,
      );
      const amountPerRow = 18;
      const amountPerColumn = 4;
      final textureSize = Vector2(
        spriteSheet.width / amountPerRow,
        spriteSheet.height / amountPerColumn,
      );
      size = textureSize / 10;
      animation = SpriteAnimation.fromFrameData(
        spriteSheet,
        SpriteAnimationData.sequenced(
          amount: amountPerRow * amountPerColumn,
          amountPerRow: amountPerRow,
          stepTime: 1 / 24,
          textureSize: textureSize,
        ),
      );
      

      接下來詳細解析 I/O 彈球游戲代碼。

      來自 Firebase 的實時積分排行榜

      I/O 彈球排行榜實時地顯示世界各地玩家的最高分數,玩家還可以在 Twitter 和 Facebook 上分享他們的分數。我們使用 Firebase Cloud Firestore 記錄排名前十的分數,將其顯示在排行榜上。當一個新的分數計入排行榜時,一個 Cloud Function 會將分數按降序排列并刪除目前不在前十的分數。

      /// Acquires top 10 [LeaderboardEntryData]s.
      Future<List<LeaderboardEntryData>> fetchTop10Leaderboard() async {
        try {
          final querySnapshot = await _firebaseFirestore
            .collection(_leaderboardCollectionName)
            .orderBy(_scoreFieldName, descending: true)
            .limit(_leaderboardLimit)
            .get();
          final documents = querySnapshot.docs;
          return documents.toLeaderboard();
        } on LeaderboardDeserializationException {
          rethrow;
        } on Exception catch (error, stackTrace) {
          throw FetchTop10LeaderboardException(error, stackTrace);
        }
      }
      

      構建 Web 應用

      與傳統應用相比,制作響應式的游戲更容易。彈球游戲只需要根據設備的大小進行縮放即可。對于 I/O 彈球游戲,我們基于固定比例的設備大小進行縮放。確保了無論在何種顯示大小,坐標系統總是相同的。保證組件在不同設備之間的一致顯示和交互非常重要。

      I/O 彈球游戲也適配了移動和桌面瀏覽器。在移動瀏覽器上,用戶可以點擊啟動按鈕開始播放,也可以點擊屏幕左右兩側來控制相應的擋板。在桌面瀏覽器上,用戶可以使用鍵盤來發射彈球和控制擋板。

      代碼架構

      彈球代碼遵循分層架構,每個功能都在自己的文件夾中。在這個項目中,游戲邏輯也與視覺組件分離。讓我們能獨立于游戲邏輯輕松地更新視覺元素。彈球游戲的主題取決于玩家在游戲開始前選擇的角色。主題是由 CharacterThemeCubit 類控制的。根據角色的選擇,球的顏色、背景和其他元素都會更新。

      /// {@template character_theme}
      /// Base class for creating character themes.
      ///
      /// Character specific game components should have a getter specified here to
      /// load their corresponding assets for the game.
      /// {@endtemplate}
      abstract class CharacterTheme extends Equatable {
        /// {@macro character_theme}
        const CharacterTheme();
      /// Name of character.
        String get name;
      /// Asset for the ball.
        AssetGenImage get ball;
      /// Asset for the background.
        AssetGenImage get background;
      /// Icon asset.
        AssetGenImage get icon;
      /// Icon asset for the leaderboard.
        AssetGenImage get leaderboardIcon;
      /// Asset for the the idle character animation.
        AssetGenImage get animation;
      @override
        List<Object> get props => [
              name,
              ball,
              background,
              icon,
              leaderboardIcon,
              animation,
            ];
      }
      

      I/O 彈球的游戲狀態是用 flam_bloc 這個 package 處理的,這是一個組合了 bloc 和 Flame 組件的 package。例如,我們使用 flame_bloc 來記錄剩余的游戲回合數、游戲中獲得的獎勵以及當前的游戲分數。另外,在 wdget 樹頂層有一個 widget,它包含加載頁面的邏輯以及玩游戲的說明。我們還遵循 行為型模式 來封裝和隔離基于組件的游戲功能元素。例如,保險杠在被球擊中時會發出聲音,所以我們實現了 BumperNoiseBehavior 類來處理這個問題。

      class BumperNoiseBehavior extends ContactBehavior {
        @override
        void beginContact(Object other, Contact contact) {
          super.beginContact(other, contact);
          readProvider<PinballPlayer>().play(PinballAudio.bumper);
        }
      }
      

      代碼庫還包含全面的單元測試、組件測試和黃金測試。測試游戲會帶來一些挑戰,因為一個組件可能具有多個職責,使得它們很難單獨地進行測試。最終我們定義了更好的隔離和測試組件的模式,并將其改進整合到 flame_test 這個 package 中。

      組件沙盒

      這個項目高度依賴于 Flame 組件帶來的仿真彈球體驗。代碼附帶了一個組件沙盒,它類似于 Flutter Gallery 中展示的 UI 組件庫。在開發游戲時,這是一個很有用的工具,因為它提供了獨立的每個游戲組件以確保它們的外觀和行為符合預期,然后再將它們整合到游戲中。

      接下來

      邀請你來 I/O Pinball 試玩并獲取高分!關注積分排行榜并且在社交媒體上分享你的分數,也可以在 GitHub repo 訪問并學習項目的開源代碼。


      原文鏈接:

      https://medium.com/flutter/i-o-pinball-powered-by-flutter-and-firebase-d22423f3f5d

      本地化: CFUG 團隊

      中文鏈接: https://flutter.cn/posts/i-o-pinball

      posted on 2022-05-23 17:11  Flutter社區  閱讀(675)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: av老司机亚洲精品天堂| 会理县| 毛片av在线尤物一区二区| 欧美精品一产区二产区| 国产午夜A理论毛片| 2021精品亚洲中文字幕| 人人爽天天碰天天躁夜夜躁| 国产一区二区不卡视频在线| 亚洲高清有码在线观看| 久久久久高潮毛片免费全部播放 | 熟妇无码熟妇毛片| 免费人成年激情视频在线观看 | 亚洲av产在线精品亚洲第一站| 亚洲va久久久噜噜噜久久狠狠| 中文字幕一区二区久久综合| 亚洲欧美综合人成在线| 加勒比无码人妻东京热| 国产一级小视频| 中文激情一区二区三区四区| 国产亚洲av嫩草久久| 亚洲天堂精品一区二区| 伊在人间香蕉最新视频| 亚洲AV永久无码精品秋霞电影影院| 久久成人国产精品免费软件| 久久一区二区三区黄色片| 色婷婷日日躁夜夜躁| 亚洲18禁私人影院| 日韩精品三区二区三区| 天堂mv在线mv免费mv香蕉| 久久综合综合久久综合| 老子午夜精品888无码不卡| 亚洲精品天堂一区二区| 亚洲精品色在线网站| 水蜜桃av无码| 精品国偷自产在线视频99| 天堂√最新版中文在线地址| 午夜福利国产区在线观看| 亚洲春色在线视频| 老女老肥熟国产在线视频| 国产精品亚洲二区在线播放| 国产亚洲999精品AA片在线爽|