Flame : Part 6: Completing Gaming App using Flame and Flutter

What are prerequisite to make a simple 2d gaming app?

You should have basic knowledge of flutter, dart classes, flame basics like sprite animation, sprite animation component, settings position and size of sprite components, sprite sheet animation, adding backgrounds, collision detection and utilizing VS Code features to make your coding work easy.

Designing game:

So, designing a basic layout at start will give a clear idea that how your game should look like and which graphics and animations you should use to make your game more attractive and user interactive. So for this blog as in continuation to the previous blogs I am going to make a game in which girl will animate up and down, and we will handle collision like if she hits another sprite component then that component should vanish and also if she comes near the platform she should be able to stand on the platform so as the game looks meaningful.

Steps:

Adding required dependencies to pubspec.yaml:

We have worked on enough projects, so we can understand that if we have to use some packages we must register in pubscpec file, flame is basically collection of many useful packages for game development so register flame, and assets that you want to use for your game.

Making main.dart to add gaming features:

Execution of the program will always start from main.dart, so you should make main.dart file accordingly.

import 'package:flame/game.dart';
import 'package:flutter/material.dart';
void main() {
  var game = MainGame();
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Stack(
          fit: StackFit.expand,
        ),
      ),
    ),
  );
}

So here we import required packages which can we use to make game. So this main class body is having stack, so we can place some sprite component one over other, as I mentioned above that when girl is near the platform she should be able to stand on the platform and that can be possible only if it is arranged in the stack.

Adding all sprite component:

Add sprite components wherever it is necessary to add them on the screen, according to your layout.

So according to my layout I will be adding girl, background, energypowerup(if the girl collides with it, then it should vanish) and various platform(platform1 and platform2)  so girl can stand on it.

As in the previous blogs we already see that we always added our sprite components in the main game which extends to base game, so we can use features of base game which can further extends to collidable as per requirement.

class MainGame extends BaseGame {
  SpriteComponent background = SpriteComponent();
  SpriteComponent platform1 = SpriteComponent();
  SpriteComponent platform2 = SpriteComponent();
  SpriteComponent energyPowerUp = SpriteComponent();
  SpriteComponent girl = SpriteComponent();

  String direction = 'down';
  final spritePadding = 3;
  late final screenWidth;
  var fuel = 60;
  bool fuelConsumed = false;
}

In the above code we can see that we have initialized our sprite components in the main game, and we choose the initial direction of the girl in the downward direction and padding and screen width is initialized and also fuelconsumed is taken to be "false" so when the girl hits the energypowerUp sprite component then fuelconsumed should turns to "true" and also that sprite component should vanish as the girl already is in energized state.

Setting properties of sprite components and loading them:

So as we added our sprite components in our game now its time to load their pic and set size and position according to the layout.

Future<void> onLoad() async {
    screenWidth = size[0];
    background
      ..sprite = await loadSprite('background.png')
      ..size = size
      ..position = Vector2(0, 0);
    add(background);

    platform1
      ..sprite = await loadSprite('platform.png')
      ..size = Vector2(100, 50)
      ..position = Vector2(0, 600);
    add(platform1);

    platform2
      ..sprite = await loadSprite('platform.png')
      ..size = Vector2(100, 50)
      ..position = Vector2(screenWidth - 100, 300);
    add(platform2);

    energyPowerUp
      ..sprite = await loadSprite('energy.webp')
      ..size = Vector2(80, 80)
      ..position = Vector2(300, 500)
      ..anchor = Anchor.center;
    add(energyPowerUp);

    girl
      ..sprite = await loadSprite('girl.png')
      ..size = Vector2(80, 80)
      ..position = Vector2(25, 100);
    add(girl);
  }
  }

So here we first added background to our game, and then we set its position and size. Then we added two platforms as shown in the code above, one is set to the right of the screen and the other platform is set to the left of the screen and their size is set too. After that, we added energypowerUp  component and its position and size. Finally, we added our special character that is the girl and her position and size is also set. Refer to previous blogs if you are facing a problem that how ".."(cascade operator) is used to set properties of sprite components that is discussed there.

Making girl stand on platform:

We had saw before collision detection, well we can use collision handling to make the girl stand on the platform which can be done by making a function which will decide how the girl will stand on the platform.

For the Left platform

bool onLeftPlatform() {
    return (girl.y + girl.height - spritePadding > platform1.y) &&
        (girl.x < platform1.x + platform1.width && direction != 'stop');
  }

This is my way to decide that how and when the girl should stand on the platform, as shown above.

For the Right platform

 bool onRightPlatform() {
    return (girl.y + girl.height - spritePadding > platform2.y) &&
        (girl.y + girl.height < platform2.y + platform2.height) &&
        (girl.x + girl.width > platform2.x && direction != 'stop');
  }

Similarly, for the right platform, I have defined the function.

Well to implement these function we must use something as there should be some changes in UI as we have seen in dart we had to use setstate at many places if something changes.

Implementing the changes on UI:

For this we are going to use update method which is part of the base game. Update method is also part of the sprite component. We will use it here in the base game, so you may get an idea how top implement it.

@override
  void update(double dt) {
    super.update(dt);

    if (onLeftPlatform() || onRightPlatform()) {
      direction = 'stop';
    }
    if (direction == 'down') {
      girl.y += 30 * dt;
    }

    energyPowerUp.angle += .15 * dt;
    energyPowerUp.angle %= 2 * pi;

    if (girl.containsPoint(energyPowerUp.center)) {
      print('hit energy pill');
      energyPowerUp.remove();
      if (!fuelConsumed) {
        fuel += 30;
        fuelConsumed = true;
      }
    }
  }

Override the built-in update method which is void, then run super update "dt" is just the delta time that comes in. So according to the code above if the girl is on right or left platform her direction is set to stop. As we saw before, we have initialized girl's initial direction as down, so its going down with the rate in delta time as shown in the code above. Also, if the girl collides with energypowerUp component her fuelconsumed variable is set to true as she consumed it and on terminal hit energy pill is going to be printed. And value of fuel raise to 30.

Controlling movement of girl

So as we are discussing the girl will stand on right or left platform but we have3 initialized her position somewhere in the middle of the screen, so how will she be able to move right or left?

That is why we are going to decide her movement by pressing right arrow or left arrow to move her in right or left direction respectively.Those buttons would be arranged in a row.

For the right movement,

IconButton(
              iconSize: 64,
              icon: Icon(Icons.arrow_forward_rounded),
              onPressed: () {
                if (widget.game.fuel > 0) {
                  widget.game.girl.x = widget.game.girl.x + 10;
                  widget.game.girl.y = widget.game.girl.y - 10;
                  widget.game.direction = 'down';
                  setState(() {
                    widget.game.fuel -= 1;
                    widget.game.girl.renderFlipX = false;
                  });
                }
                print('right boost. fuel: ${widget.game.fuel}');
              },
            ),

we can clearly see in the above code that how we decide here rightward movement, however it is obvious we are still letting her going down but also going in the rightward direction. And we will print something on screen related to fuel that we will see in the output screen.

For the left movement,

 IconButton(
              iconSize: 64,
              icon: Icon(Icons.arrow_back_rounded),
              onPressed: () {
                if (widget.game.fuel > 0) {
                  widget.game.girl.x = widget.game.girl.x - 10;
                  widget.game.girl.y = widget.game.girl.y - 10;
                  widget.game.direction = 'down';
                  setState(() {
                    widget.game.fuel -= 1;
                  });
                }
                widget.game.girl.renderFlipX = true;

                print('left boost. fuel: ${widget.game.fuel}');
              },
            ),

similarly, like her  right movement, we have decided left movement as well.

So now the game is completely ready, look the videos down to see the game and also understand how it is implemented.


So,  we have now completed the making of gaming app and also we have seen how it is working we have used collision in two ways. First handling is when the girl comes on anyone of the platform then we handled in such a way that she stands on the platform and second way is that when she strikes sprite component (energy up component)  then her fule should raise up and that sprite component should vanish. 

Refer to the link below in case of any doubt related to the code

https://gitlab.com/mdnazisharman/final-game




Post a Comment

Previous Post Next Post

Subscribe Us


Get tutorials, Flutter news and other exclusive content delivered to your inbox. Join 1000+ growth-oriented Flutter developers subscribed to the newsletter

100% value, 0% spam. Unsubscribe anytime