background

I received a demand for game development, which needs to support both iOS and Android due to the launch of dual terminals.

3 Android RD, with no experience in game development, quickly learn how to use Flutter to support dual end.

Plan your game using the Flame framework to familiarize yourself with the environment and then learn and solve problems as you develop.

knowledge

What is the GameLoop

A game loop is the scaffolding of a game. Most games only need two methods:

  1. The Render method is used to draw
  2. Update the difference between the current frame and the previous frame.

The render method is responsible for rendering the circle with the y value, and the update method is responsible for updating the y changes. Cooperate with each other to complete a round falling animation

How to display a Flutter component on a Frame engine

Use the HasWidgetsOverlay interface.

  1. withremoveWidgetOverlayMethod to remove the Flutter component
  2. withaddWidgetOverlayMethod to add a Flutter component
class MyGame extends BaseGame with HasWidgetsOverlay.TapDetector {
  Size size;
  SpriteC spriteC;
  bool isPaused = false;

  MyGame(this.size) {
    spriteC = SpriteC.create();
  }

  @override
  void onTap() {
    super.onTap();
    if (isPaused) {
      removeWidgetOverlay('pausemenu');
      isPaused = false;
    } else {
      addWidgetOverlay(
          'pausemenu',
          Center(
            child: Container(
              width: 100,
              height: 100,
              color: Colors.blue[300],
              child: const Center(child: const Text('Pause'))))); isPaused =true; }}}Copy the code

How to present a game on a component of Flutter

Game provides a Widget object that can be directly retrieved and used as a Widget of Flutter.

  final game = MyGame(size);
  runApp(game.widget);
Copy the code

What is the Debug function

  @override
  bool debugMode() => true;

  @override
  bool recordFps() => true;
Copy the code

Open the Debug.

Debug allows debugging and automatically prints the location of the component.

RecordFps is the output of the FPS of the currently running game.

Components (Components)

Necessity: Just like pasting pages on Android/iOS. All of the pages, animation, special effects can use Canvas to paint, develop normally use is actually ImageView, TextView, ListView such components to complete. No one likes slash-and-burn

Component important methods:

Except for generic methods like render and update.

  / / initialization
  @override
  void onMount() {
    super.onMount();
  }

  / / before recycling
  @override
  void onDestroy() {
    super.onDestroy();
  }
  
  // I don't know... ? I'm talking about the relationship between the drawing position and the device
  @override
  bool isHud() {
    return true;
  }

  // The tag is recyclable
  @override
  bool destroy() {
    return false;
  }
Copy the code

How to draw frame animation

Namely the

The people in the game are moving, so this is an important point.

Display AnimationComponent in the game

    const textureWidth = 96.0;
    const textureHeight = 96.0;
    add(AnimationComponent.sequenced(
      textureWidth * 2,
      textureHeight * 2.'minotaur.png'.19,
      textureWidth: textureWidth,
      textureHeight: textureHeight,
      loop: true,
      stepTime: 0.15));Copy the code

The function AnimationComponent. Sequenced parameters stated below:

AnimationComponent. Sequenced (double width, / / display the width of the double height, the height of the / / display the String imagePath, int the amount, Int amountPerRow, // double textureX = 0.0, // display offset double textureY = 0.0, Double textureWidth, // Double textureHeight, // Double textureHeight, // Double stepTime, // Play interval bool loop =true// Whether to loop this.DestroyonFinish =false})Copy the code

Provides a display of the AnimationWidget to the Flutter component

  await Flame.images.load('minotaur.png');
  final _animationSpriteSheet = SpriteSheet(
    imageName: 'minotaur.png', columns: 19, rows: 1, textureWidth: 96, textureHeight: 96, ); _animation = _animationSpriteSheet. CreateAnimation (0, stepTime: 0.2,, 5,); // Use Container(width: 200, height: 200, child: AnimationWidget(animation: _animation),)Copy the code

How to draw an SVG animation SvgComponent

    Svg svg = Svg('android.svg');
    SvgComponent android = SvgComponent.fromSvg(100.100, svg);
    android.x = 100;
    android.y = 100;
Copy the code

How to draw the composite control ComposedComponent

Similar to native composite controls.

class GameOverPanel extends PositionComponent
    with Resizable, HasGameRef, Tapable, ComposedComponent {

  GameOverPanel(Image spriteImage) : super() { gameOverText = GameOverText(spriteImage); gameOverRestart = GameOverRestart(spriteImage); components.. add(gameOverText).. add(gameOverRestart); } bool visible =false;

  GameOverText gameOverText;
  GameOverRestart gameOverRestart;

  @override
  void render(Canvas canvas) {
    if(visible) { super.render(canvas); } } } class GameOverText extends SpriteComponent with Resizable { GameOverText(Image spriteImage) : Super. FromSprite (GameOverConfig. TextWidth, GameOverConfig textHeight, Sprite. FromImage (spriteImage, x: 955.0, y: 26.0, width: GameOverConfig textWidth, height: GameOverConfig. TextHeight,),); @override void resize(Size size) {if(width > size.width * 0.8) {width = size.width * 0.8; } y = size.height * .25; x = (size.width / 2) - width / 2; } } class GameOverRestart extends SpriteComponent with Resizable { GameOverRestart(Image spriteImage) : Super. FromSprite (GameOverConfig. RestartWidth, GameOverConfig restartHeight, Sprite. FromImage (spriteImage, x: 2.0, y: 2.0, width: GameOverConfig restartWidth, height: GameOverConfig. RestartHeight,),); @override void resize(Size size) { y = size.height * .75; x = (size.width / 2) - GameOverConfig.restartWidth / 2; ! [](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/6/19/172c89c8d5d4aff0~tplv-t2oaga2asx-image.image )}}Copy the code

How do WE create a ParallaxComponent

That’s how to do it in a nutshell

Combine to produce

  final images = [
      ParallaxImage("bg.png"),
      ParallaxImage("mountain-far.png"),
      ParallaxImage("mountains.png"),
      ParallaxImage("trees.png"),
      ParallaxImage("foreground-trees.png")];final parallaxComponent = ParallaxComponent(images,
        baseSpeed: const Offset(20.0), layerDelta: const Offset(100.0));
Copy the code

The moon & sky is farther away from us so it moves more slowly

The trees moved faster because they were close to us

The combination is amazing and I love the effect. TOT

How to draw stretchable images NineTileBox

The following cases:

/ / define
  final sprite = Sprite('nine-box.png');
    nineTileBox = NineTileBox(sprite, tileSize: 8, destTileSize: 24);
    
/ / use
 nineTileBox.draw(canvas, x, y, 200.500);
Copy the code

The two corners are 4 pixels each, making 8 pixels for a total of 24 pixels. That’s what these parameters mean.

The UE cut image needs to keep the image size multiple of 3. Another disadvantage compared to.9. PNG is that it must ensure the 4 corners are symmetrical. For asymmetries, such as images that need only 4 pixels below 8 pixels above are not supported.

Physics engine Box2DComponent

Flame supports Box2D. That is, Box2DComponent. My understanding is that you can achieve physical volume and the ability to collide.

This is a very Powerful component, and it should have some depth, so I need to spend some time to study it carefully. Just familiarize yourself with his scope here.

Website: box2d.org/

Box2D is a free open source 2d physics engine written by Erin Catto in C++ and released under the zlib license. It’s been used in crayon physics, Angry Birds, Limbo, Rolando, Fantastic…