Saturday, August 6, 2022

Flame: Bodies and sprites

This article will teach us how to draw sprites on top of our Box2D bodies.

Let’s start by creating a Box2D scene in which a box or a ball will appear at the top of the screen each time we click the screen.

We start by creating the class Box:

class Box extends BodyComponent {

  
  Body createBody() {
    final bodyDef = BodyDef(
      position: Vector2(worldSize.x / 2, 0),
      type: BodyType.dynamic,
    );

    final shape = PolygonShape()..setAsBoxXY(.25, .25);
    final fixtureDef = FixtureDef(shape)
      ..density = 5
      ..friction = .5
      ..restitution = .5;
    return world.createBody(bodyDef)
      ..createFixture(fixtureDef)
      ..angularVelocity = radians(180);
  }
}

Notice that we added an angularVelocity so the box will rotate on its axis. Everything else is what we have been doing in previous tutorials.

Now let’s create a class Ball:

class Ball extends BodyComponent {

  
  Body createBody() {
    final bodyDef = BodyDef(
      position: Vector2(worldSize.x / 2, 0),
      type: BodyType.dynamic,
    );

    final shape = CircleShape()..radius = .25;
    final fixtureDef = FixtureDef(shape)
      ..density = 5
      ..friction = .5
      ..restitution = .5;
    return world.createBody(bodyDef)
      ..createFixture(fixtureDef)
      ..angularVelocity = radians(180);
  }
}

Again, there is nothing special in this class. This ball will be rotating on its axis too.

Every time we click the screen, we want to add a ball or box randomly. Let’s add this code:

class GameLesson05 extends MyGame with TapDetector {
  
  Future<void> onLoad() async {
    super.onLoad();
    add(Floor());
  }

  
  void onTapDown(TapDownInfo info) {
    super.onTapDown(info);
    if (Random().nextBool()) {
      add(Ball());
    } else {
      add(Box());
    }
  }
}

If we run the previous code, the result is this:

Adding sprites

Let’s make the scene of white boxes and balls more fun. First, we will add these two images to the assets folder:

Then, we update the pubspec.yaml file to add the assets path.

  assets:
    - assets/images/

We will load the sprites and store them in the cache. On the class GameLesson05, we add this code to the onLoad() function:

  Future<void> onLoad() async {
    super.onLoad();
    await loadSprite('ball.png');
    await loadSprite('box.png');

    add(Floor());
  }

Now we must retrieve the loaded sprites from the cache and add them to the box and the ball.

Let’s start by overriding the onLoad() function from the Ball class:

  
  Future<void> onLoad() async {
    await super.onLoad();
    final sprite = Sprite(gameRef.images.fromCache('ball.png'));
    add(
      SpriteComponent(
        sprite: sprite,
        size: Vector2(.5, .5),
        anchor: Anchor.center,
      ),
    );
  }

The previous code retrieves the image from the cache and creates a new Sprite, then creates a new SpriteComponent that will be in charge of drawing the image on top of the ball.

Updating the box code is very similar to the ball code. Let’s take a look:

  
  Future<void> onLoad() async {
    await super.onLoad();
    final sprite = Sprite(gameRef.images.fromCache('box.png'));
    add(
      SpriteComponent(
        sprite: sprite,
        size: Vector2(.5, .5),
        anchor: Anchor.center,
      ),
    );
  }

Running the updated code will give us the following result:

Looks better right? Notice how Flame takes care of drawing the sprites on top of the bodies, including updating the position, rotation, etc.

Source code of all tutorials is available on Github, and you can try all the examples in your browser:

0 comments:

Post a Comment

Entradas populares