Desarrollo de videojuegos 2D con Flutter y Flame

Flame es una librería que permite simplificar el desarrollo de videojuegos para móviles usando el SDK de google. A continuación veremos los conceptos principales para el desarrollo de videojuegos y luego haremos un ejemplo práctico de cómo hacerlo realidad usando estas herramientas.

Introducción al desarrollo de videojuegos

El game loop

Es la esencia del juego. Un set de instrucciones que el computador ejecuta una y otra vez.

Los juegos normalmente tienen una métrica llamada FPS (Frames por segundo). Esto quiere decir que si un juego está corriendo a 60 fps, el computador está ejecutando un game loop 60 veces por segundo. 1 frame =  1 ejecución del game loop.

Un game loop básico está hecho de dos métodos: update y render.

El método update se encarga de los movimientos de los objetos (como enemigos, obstáculos) y otras cosas que necesitan actualizarse. Por ejemplo, calcular si el enemigo es golpeado por una bala o calcular si este enemigo toca el personaje principal.

El método render dibuja todos los objetos en la pantalla. Esto es un proceso separado y por tanto, todo debe estar sincronizado.

¿Porqué es necesario sincronizar?

Imagine que necesita actualizar la posición de su personaje principal, está sano y por tanto así lo renderiza.

Pero, una bala está a unos píxeles de tocarlo. La bala se actualiza y entonces afecta a su personaje, ahora él está muerto y por tanto no es necesario dibujar la bala. Para este momento usted debería está dibujando el primer frame de la animación de su personaje muriendo. En el siguiente ciclo, ya no es necesario actualizar el personaje debido a que está muerto. En lugar de eso se dibuja el primer frame de la animación del personaje muriendo (en vez del segundo frame).

Esto puede darle al juego la sensación de que está entrecortado. Imagine jugar un juego de ataque donde al disparar a un enemigo, no cae, le dispara otra vez  pero antes de que la bala lo impacte muere. Esta sensación no deseada puede no ser visible, especialmente cuando se está corriendo a 60 fps, pero si esto pasa muy seguido, el juego puede sentirse de baja calidad.

Necesitamos tener todo calculado, de tal forma que cuando los estados de los objetos están calculados y finalizados, la ventana será dibujada.

Flame y Flutter

Flame brinda el código que maneja el manejo de estos métodos, por tanto sólo tenemos que preocuparnos por escribir el proceso de actualización y renderización reales.

Para comenzar, transformaremos nuestra pantalla principal mostrando en modo horizontal y full screen:

import 'package:flame/util.dart';
import 'package:flutter/services.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  Util flameUtil = Util();
  flameUtil.fullScreen();
  flameUtil.setOrientation(DeviceOrientation.portraitUp);

}

Ahora, haremos uso de la clase Game de la librería mediante una subclase llamada MyAwesomeGame que la extienda:

import 'dart:ui';

import 'package:flame/game.dart';

class MyAwesomeGame extends Game {
  void render(Canvas canvas) {
    // TODO: implement render
  }

  void update(double t) {
    // TODO: implement update
  }
}
Traducido y adaptado de este post