El Patrón de Estado

La enumeración de estado «EnemyState» se puso complicada. Es necesario implementar un patrón de estado.

Un switch con múltiples casos se volvió extremadamente complicado e imposible de mantener. También obligaba a la repetición de código entre casos, lo que hace que todo el método sea ineficiente.

Con el nuevo patrón de estado, delego cada estado a su propia clase aislada de los demás y si necesito repetir algún código, lo añado a la clase abstracta.

EnemyState.java

public abstract class EnemyState {

  public abstract EnemyStateName name();

  public abstract void act(Enemy enemy, float delta);

  public boolean gotHit(Enemy enemy) {
    RM.get().playSingleHurtSound();
    if (--enemy.HP == 0) {
      RM.get().playSingleDeathSound();
      enemy.setAnimation(RM.get().animations.get(AnimationKey.ENEMY_EXPLOSION));
      enemy.setStateTime(0);
      if (enemy.state.name() != BERTH) enemy.destinyPolar = enemy.polar;
      enemy.state = ExplodingState.getInstance();
    } else enemy.radiusFlux = MAX_RADIUS_FLUX;
    return true;
  }
}
  • La enumeración anterior ahora se llama EnemyStateName (Linea 3) y solo sirve para identificar la clase y evitar una comparación con instanceof.
  • Linea 7: Método compartido para evitar repetición que la mayoría de los estados comparten.
  • Linea 14: La nueva forma de cambiar de estado. Cada estado es un Singleton.

La llegada del muelle espacial fue un reto visual, ya que cada explosión se mezclaba con todo lo que había alrededor, desordenando totalmente la vista del muelle.

Con el nuevo patron de estado, puedo mantener y mover la explosion en el mismo lugar del objeto manteniendo el muelle organizado pero al mismo tiempo puedo recrear la forma anterior de poner la explosion tiesa en el ultimo lugar del objeto.

Esa decisión de mantener la explosión dentro del muelle o tiesa afuera, se decide en el código anterior en la línea 13.

AttackingState.java

Ejemplo de cómo se ve un estado aislado. En este caso, no es necesario especificar el método gotHit(Enemy enemy).

public class AttackingState extends EnemyState {

  private final static AttackingState instance = new AttackingState();

  private AttackingState() {
  }

  public static AttackingState getInstance() {
    return instance;
  }

  @Override
  public EnemyStateName name() {
    return EnemyStateName.ATTACKING;
  }

  @Override
  public void act(Enemy enemy, float delta) {
    float deltaAngle = shortestAngularRoute(enemy.polar.angle, enemy.destinyPolar.angle);
    float maxAngularStep = enemy.orbitSpeed * delta;
    enemy.polar.angle += MathUtils.clamp(deltaAngle, -maxAngularStep, maxAngularStep);
    enemy.polar.angle = normalizeAngle(enemy.polar.angle);
    if (MathUtils.isEqual(enemy.polar.angle, enemy.destinyPolar.angle, 0.01f))
      enemy.currentPolar.angle = MathUtils.random(MathUtils.PI2);
  }
}

La función de este estado es navegar a un punto polar predefinido y cuando llega, escoge un nuevo punto polar al azar.

Proximo es la codificación de «option» o naves ayudantes.

Únete a otros 35 suscriptores

Deja una respuesta

Anuncios


Anuncios