# Parte 3 - Entidades

## Entidad Padre

Vamos a la carpeta entities y empezaremos a completar el archivo `entity.js`

Primero importamos phaser y creamos una clase llamada Entity que extiende un objeto del juego llamado Sprite.

```javascript
import Phaser from "phaser";

class Entity extends Phaser.GameObjects.Sprite {
}
```

Un sprite recibe los siguientes parametros

| Parametro | Descripcion                                                                                                                            |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| scene     | Una escena a la que queremos incluir este sprite                                                                                       |
| x         | <p>la posición donde aparecera nuestro objeto en el eje horizontal,</p><p>empezando desde el borde izquierdo siendo este igual a 0</p> |
| y         | <p>la posición donde aparecera nuestro objeto en el eje vertical,</p><p>empezando desde el borde superior siendo este igual a 0</p>    |
| texture   | Un string con la key de una imagen que importamos                                                                                      |
| frame     | <p>Si nuestra textura es un hoja de sprites con una animación,</p><p>podemos decirle el numero del frame con el que aparecerá.</p>     |

Vamos a crear el constructor para nuestra clase. Como no vamos a trabajar con animaciones el parámetro frame no lo vamos a utilizar pero agregaremos el parámetro `type` para identificar el tipo de entidad cuando heredemos en los siguientes objetos.

```javascript
constructor(scene, x, y, texture, type) {
    super(scene, x, y, texture);
    // We link both the scene and add this objecto to the scene
    // when our new object is created. And enable the physics.
    this.scene = scene;
    this.scene.add.existing(this);
    this.scene.physics.world.enableBody(this, 0);
    this.setData("type", type);
    this.setData("isDead", false);
  }
```

{% hint style="info" %}
Con `setData` podemos agregar claves y variables a nuestro objeto. Y con `getData` acceder a ellas.
{% endhint %}

Vamos a agregar el dato que pasamos por `type`, para identificar si es una nave o un disparo.\
Y un booleano para identificar si el objeto murió o esta vivo.

Para terminar, agregamos una función que tendrán en común todas las entidades, y es que, cuando queramos que un objeto se destruya cambiaremos el valor `isDead`

```javascript
onDestroy(){
    this.setData('isDead', true);
    this.visible = false;
 }
```

Por ultimo vamos a agregar una función que nos servirá para ir limpiando de la memoria los elementos que se van fuera del nivel, como los disparos o los enemigos.

```javascript
checkOutOfBonds() {
  if (
    this.x < -this.displayWidth ||
    this.x > this.scene.game.config.width + this.displayWidth ||
    this.y < -this.displayHeight * 4 ||
    this.y > this.scene.game.config.height + this.displayHeight
  ) {
    if (this) {
      this.destroy();
      console.log("bye");
    }
  }
}
```

## Jugador

Vamos a completar ahora el archivo `player.js` , esta clase heredara de la clase `Entity` que creamos antes, así que primero importamos `entity.js`

```javascript
import Entity from "./entity";

class Player extends Entity {
  constructor(scene, x, y) {
    super(scene, x, y, "sprPlayer", "Player");
    this.setData("speed", 300);
  }
}

export default Player;
```

Así debería verse nuestra clase Player. Recibirá en el constructor los parámetros `scene` ; `x` e `y`cuando la instanciemos, en `texture` le pasamos la key del sprite del jugador. Y el parámetro `type` le pondremos `"Player"`

Agregamos la key `speed` que nos va a servir para manipular luego la velocidad en que se movera nuestra nave.

### Métodos

| Método      | Descripción                                                                                                         |
| ----------- | ------------------------------------------------------------------------------------------------------------------- |
| `moveUp`    | moverá nuestra nave hacia arriba                                                                                    |
| `moveDown`  | moverá nuestra nave hacia abajo                                                                                     |
| `moveLeft`  | moverá nuestra nave hacia la izquierda                                                                              |
| `moveRight` | moverá nuestra nave hacia la derecha                                                                                |
| `shoot`     | creara un disparo en el frente de la nave que sera una entidad aparte                                               |
| `coolDown`  | mide el tiempo entre disparos para no generar infinitos disparos al presionar el botón                              |
| `update`    | todo lo que necesite estar en el loop del juego ira aquí, luego llamaremos este método en el `update` de la escena. |

### Movimiento

Primero vamos a hacer que nuestra nave se mueva. Para eso completamos las funciones de movimiento de la siguiente forma:

```javascript
moveUp() {
  this.body.velocity.y = -this.getData("speed");
}
moveDown() {
  this.body.velocity.y = this.getData("speed");
}
moveLeft() {
  this.body.velocity.x = -this.getData("speed");
}
moveRight() {
  this.body.velocity.x = this.getData("speed");
}
```

Como en la clase `Entity` ya aplicamos las físicas al objeto, a diferencia del `background`, aquí aplicamos una velocidad que hará que nuestra nave se mueva en una dirección basándonos en la velocidad que seteamos en el constructor. De esa forma podemos cambiar el atributo velocidad y se aplicara a todos los movimientos.

Ahora vamos a usar el `update` para captar cuando el jugador toque una tecla:

```javascript
update() {
    //We check if player is not dead
    if (!this.getData("isDead")) {
      
      //This set velocity to 0 every tick to stop our ship
      this.body.setVelocity(0, 0);

      //This prevent the player to go out of bounds of the screen
      this.x = Phaser.Math.Clamp(this.x, 0, this.scene.game.config.width);
      this.y = Phaser.Math.Clamp(this.y, 0, this.scene.game.config.height);

      if (this.scene.keyW.isDown) {
        this.moveUp();
      } else if (this.scene.keyS.isDown) {
        this.moveDown();
      }
      if (this.scene.keyA.isDown) {
        this.moveLeft();
      } else if (this.scene.keyD.isDown) {
        this.moveRight();
      }
      if (this.scene.keySpace.isDown) {
        this.shoot();
      }
    }
  }
```

Primero que nada, usamos la variable `isDead` para que nuestro jugador funcione solo cuando no haya muerto. Si aplicáramos una fuerza de movimiento a nuestra nave esta no se detendría hasta cambiar su velocidad, chocar con otro objeto o si indicamos la desaceleración.\
Para simplificar esto, cada vez que se actualice el juego, la velocidad sera 0 y solo se moverá si presionamos una tecla.

Existen varias maneras de calcular cuando el jugador se esta saliendo de la pantalla. Vamos a utilizar el código dado, pero pueden hacer una validación al momento de presionar las teclas por ejemplo.

### Teclas

Ahora nuestro nave sabe moverse y parar, y hasta donde moverse, pero hay que asociar las teclas.

Esto puede hacerse en la misma escena pero nosotros queremos que cuando un jugador se cree ya venga con sus teclas configuradas. Por eso vamos a escribir en el constructor el siguiente código.

```javascript
// This are the move keys for our player
this.scene.keyW = this.scene.input.keyboard.addKey(
  Phaser.Input.Keyboard.KeyCodes.W
);
this.scene.keyS = this.scene.input.keyboard.addKey(
  Phaser.Input.Keyboard.KeyCodes.S
);
this.scene.keyA = this.scene.input.keyboard.addKey(
  Phaser.Input.Keyboard.KeyCodes.A
);
this.scene.keyD = this.scene.input.keyboard.addKey(
  Phaser.Input.Keyboard.KeyCodes.D
);
this.scene.keySpace = this.scene.input.keyboard.addKey(
  Phaser.Input.Keyboard.KeyCodes.SPACE
);
```

Hasta acá ya tenemos nuestra nave, para poder verla vamos a ir a la escena principal `mainScene.js` y empezamos haciendo el `preload` importamos el sprite de nuestra nave:

```javascript
import player_sprite from "../assets/PNG/playerShip1_blue.png";
```

y lo agregamos a la escena

```javascript
preload() {
    // here we preload the graphics, this can be modulated later
    this.load.image("sprPlayer", player_sprite);
    this.load.image("sprBackground", background_sprite);
}
```

colocamos el siguiente código en la función `create()`

```javascript
this.player = new Player(
    this,
    this.game.config.width * 0.5,
    this.game.config.height * 0.5,
    "sprPlayer"
);
```

Ya creamos un jugador en el centro de la escena. En `update()` ahora llamamos a la función del jugador con el mismo nombre.

```javascript
update() {
    this.background.tilePositionY -= 3;
    this.player.update();
}
```

Ahora, si corremos nuestro juego, tenemos que ver nuestra nave viajando por el espacio, y podremos moverla, disparar no hará nada aun.

## Nave Enemiga

No hay mucho que explicar de la nave enemiga, debería verse así

```javascript
import Entity from "./entity";

class RedShip extends Entity {
  constructor(scene, x, y) {
    super(scene, x, y, "sprRedShip", "RedShip");
    this.setData("speed", 300);
  }

  move() {
    if (!this.getData("isDead")) {
      this.body.velocity.y = this.getData("speed");
    }
  }
}

export default RedShip;
```

En comparación, solo cambiamos el parámetro `type` por `RedShip` para saber de que entidad hablamos.\
En `move()` aplicamos un movimiento hacia abajo, cuando la nave aparezca simplemente ira hacia abajo, más adelante nos encargaremos de que destruirla cuando salga de pantalla.

Ahora vamos a la escena y repetimos el proceso de importar la imagen, nos debería quedar algo así. Considera ir importando el `shoot_sprite` que usaremos para el disparo.

```javascript
import Phaser from "phaser";
import Player from "../entities/player";
import RedShip from "../entities/redShip";
import player_sprite from "../assets/PNG/playerShip1_blue.png";
import background_sprite from "../assets/backgrounds/purple.png";
import shoot_sprite from "../assets/PNG/lasers/laserBlue01.png";
import red_ship_sprite from "../assets/PNG/Enemies/enemyRed1.png";

class MainScene extends Phaser.Scene {
  constructor() {
    super({ key: "mainScene" });
  }

  preload() {
    // here we preload the graphics, this can be modulated later
    this.load.image("sprPlayer", player_sprite);
    this.load.image("sprBackground", background_sprite);
    this.load.image("sprRedShip", red_ship_sprite);
  }

  create() {
    this.background = this.add.tileSprite(
      240,
      320,
      this.game.config.width,
      this.game.config.height,
      "sprBackground"
    );
    this.player = new Player(
      this,
      this.game.config.width * 0.5,
      this.game.config.height * 0.5,
      "sprPlayer"
    );
    
  }
  
  update() {
    this.background.tilePositionY -= 3;
    this.player.update();
  }
}
```

## Disparo

Ahora vamos a completar el archivo `playerShoot.js`, deberíamos tener el siguiente código.

```javascript
import Entity from "./entity";

class playerShoot extends Entity {
  constructor(scene, x, y) {
    super(scene, x, y, "sprShoot", "Shoot");
    this.setData("speed", 500);
  }

  move() {
    this.body.velocity.y = -this.getData("speed");
  }
}

export default playerShoot;
```

Es parecido a la nave enemiga, pero en `move()` en vez de bajar, sube.

Ahora el encargado de disparar sera nuestra nave. Así que **importemos** `playerShoot.js` en `player.js` y completamos `shoot()` y `coolDown()` con el siguiente código

```javascript
// Our ship creates a laser
  shoot() {
    // If our ship isn't charging then it shoots
    if (!this.getData("isCharging")) {
      let shoot = new Shoot(
        this.scene,
        this.body.position.x + 50,
        this.body.position.y
      );
      this.scene.playerLasers.add(shoot);
      // We call the move function so our laser moves
      shoot.move();
      //We set our shooting to charging
      this.coolDown();
    }
  }
  // This prevent creating an infinite amount of lasers
  coolDown() {
    this.setData("isCharging", true);
    setTimeout(() => {
      this.setData("isCharging", false);
    }, 500);
  }
```

Lo que hicimos fue simplemente verificar que nuestra nave no este recargando y luego crear un objeto disparo en la posición y del objeto (donde sea que este, en el punto de anclaje 0 vertical) y lo mismo en el eje horizontal pero agregamos un offset para que parezca que se dispara desde el centro de la nave. Luego agregamos este disparo a nuestro grupo de disparos en la escena y le decimos al disparo que empiece a moverse.

Nuestra nave ya debería poder disparar, pero que pasa? los objetos aun no interactuan entre si! Eso lo veremos en la siguiente parte.
