5.6 Métodos de Spacewar!

Ya estás familiarizado con la escritura de métodos simples para el juego Spacewar! Escribiremos algunos más y aprenderemos a clasificarlos.

5.6.1 Inicializar el juego

Queremos añadir el método initialize a nuestra clase SpaceWar. Por supuesto, necesitamos utilizar el System Browser: ...menú World → Open...Browser...

Como recordatorio, haz lo siguiente (si es necesario mira la Figura 2.1):

  1. En el panel de Categoría de clases a la izquierda, desplázate hacia abajo hasta la categoría Spacewar! y selecciónala.
  2. En el panel de Clases, selecciona la clase SpaceWar.
  3. Debajo, haz click en el botón de instance para exponer los métodos del lado de la instancia de la clase SpaceWar. Es el comportamiento por defecto del browser de todos modos, por lo que puedes saltarte este paso siempre que no hayas pulsado el botón class.
  4. En el panel Categoría de Métodos, selecciona la categoría -- all --. Se mostrará en el panel inferior una plantilla de código para el método:
    messageSelectorAndArgumentNames
      "comment stating purpose of message"
      | temporary variable names |
      statements
    

    La plantilla contiene cuatro líneas: el nombre del métdo, un comentario, una declaración de variable local y statements. Puedes seleccionar todo y borrarlo o editar línea a línea de la plantilla según necesites.

    En nuestro caso, seleccionaremos todo y lo reemplazaremos con el código fuente de SpaceWar>>initialize:

    SpaceWar>>initialize
      "We want to capture keyboard and mouse events, 
      start the game loop(step) and initialize the actors."
      super initialize.
      color := self defaultColor.
      self setProperty: #'handlesKeyboard' toValue: true.
      self setProperty: #'handlesMouseOver:' toValue: true.
      self startSteppingStepTime: self stepTime.
      self initializeActors
    

    Ejemplo 5.7: Inicializar SpaceWar

  5. Una vez cambiado, guárdalo con Ctrl-s o ...click derecho → Accept (s)...

El método recién creado se mostrará en el panel Métodos. También puedes clasificarlo automáticamente: con el ratón, ve al panel Categorías de métodos...haz clic con el botón derecho → categorize all uncategorized (c)... (clasificar todo lo no clasificado).

 CuisLogo En la clase SpaceWar, añade el método teleport: tal y como se define en Ejemplo 5.3 y, a continuación, clasifícalo en la categoría de métodos events.

Ejercicio 5.3: Clasificar un método

5.6.2 Controles de la nave espacial

En un capítulo anterior, escribiste como ejercicio una implementación sencilla de los métodos de control de la nave. Los métodos de control definitivos de la clase SpaceShip se reescriben como:

SpaceShip>>push
  "Init an acceleration boost"
  fuel isZero ifTrue: [^ self].
  fuel := fuel - 1.
  acceleration := 50

SpaceShip>>unpush
  "Stop the acceleration boost"
  acceleration := 0

SpaceShip>>right
  "Rotate the ship to its right"
  self heading: self heading + 0.1
  
SpaceShip>>left
  "Rotate the ship to its left"
  self heading: self heading - 0.1

Ejemplo 5.8: Controles de la nave

Observa los métodos #right y #left, son prácticamente idénticos a los que se piden en el Ejercicio 3.12. No modificamos directamente el atributo heading, sino que utilizamos los métodos heading: y heading para leer y escribir esta información.

 CuisLogo Clasifica los métodos de control en una nueva categoría creada con el nombre de control.

Ejercicio 5.4: Clasificar los métodos de control

El control no estará completo sin el método para disparar un torpedo. Inicializar correctamente un torpedo es más complejo. Esto se debe a que una nave espacial suele estar en movimiento y, además, su rumbo y velocidad cambian con frecuencia. Por lo tanto, el torpedo debe configurarse de acuerdo con la posición, el rumbo y la velocidad actuales de la nave espacial antes de ser disparado.

SpaceShip>>fireTorpedo
  "Fire a torpedo in the direction of
  the ship heading with its velocity"
  | torpedo | 
  torpedoes isZero ifTrue: [ ^ self].
  torpedoes := torpedoes - 1.
  torpedo := Torpedo new.
  torpedo 
    position: position + self nose;
    heading: self heading;
    velocity: velocity;
    color: self color muchLighter.
  owner addTorpedo: torpedo

Ejemplo 5.9: Disparar un torpedo desde una nave espacial en movimiento

ch05-SpacewarGamePlay

Figura 5.1: Spacewar! torpedos alrededor

5.6.3 Colisiones

En un capítulo anterior, ofrecimos una pequeña muestra del código de detección de colisiones entre las naves espaciales y la estrella central. Se basa en un iterador, un bloque de código y un flujo de control.

Sin embargo, existen otros escenarios, como colisiones entre naves, entre torpedos y el Sol, y entre torpedos y naves.

 CuisLogo ¿Cómo escribirás el método para detectar la colisión entre las dos naves y tomar las acciones correspondiente? (Adáptalo de Ejemplo 4.23).

Ejercicio 5.5: Colisión de naves

La detección entre las dos naves y la gran cantidad posible de torpedos necesitó dos enumeradores con bloques de código anidados:

SpaceWar>>collisionsShipsTorpedoes
ships do: [:aShip | 
  torpedoes do: [:aTorpedo |
    (aShip morphPosition dist: aTorpedo morphPosition) < 15 ifTrue: [
      aShip flashWith: Color red.
      aTorpedo flashWith: Color orange.
      self destroyTorpedo: aTorpedo.
      self teleport: aShip]
  ]
]

Ejemplo 5.10: Colisión entre las naves y los torpedos

El último escenario de colisión entre torpedo y sol lo dejamos como un ejercicio para ti.

 CuisLogo Escribe el método para detectar las colisiones entre los torpedos y la estrella central y realizar la acción correspondiente. (Adáptalo desde Ejemplo 4.23 y Ejemplo 5.10.)

Ejercicio 5.6: Colisiones entre los torpedos y el Sol