3.6 Spacewar! Estados y comportamientos

3.6.1 Los estados del juego

Después de definir las clases involucradas en el diseño del juego, ahora definimos varios estados de estas clases:

Necesitamos explicar la naturaleza matemática de estos estados y, a continuación, analizar su representación objetiva en las variables de instancia de nuestras clases.

 note En las siguientes secciones, para facilitar la lectura, escribiremos «la variable myVar es una String» en lugar de la correcta pero más engorrosa «la variable de instancia myVar es una referencia a una instancia de String».

SpaceWar

Este objeto es la entrada al juego. Queremos un nombre de clase significativo. Sus variables de instancia son los protagonistas involucrados en el juego:

CentralStar

Es una variable de instancia única, mass es un número, lo más probable un entero (Integer).

SpaceShip

La nave es el objeto más complejo, algunas aclaraciones al echar un vistazo a sus variables.

Unas pocas palabras sobre las coordenadas euclidianas: el origen de nuestro marco ortonormal es la estrella central, su primer vector está orientado hacia la derecha de la pantalla y el segundo hacia la parte superior de la pantalla. Esta elección facilita el cálculo de la aceleración, la velocidad y la posición de la nave. Más adelante daremos información al respecto.

Torpedo

Un torpedo se lanza o «dispara» desde una nave con la velocidad iniciar relacionada a la velocidad de la nave. Una vez que el tiempo de vida del torpedo llega a cero, se autodestruye.

3.6.2 Variables de instancia

En el capítulo anterior, explicamos cómo definir las cuatro clases SpaceWar, CentralStar, SpaceShip y Torpedo. En esta sección añadiremos a esas definiciones las variables de instancia –estados– que describimos arriba.

Para añadir las variables de la clase Torpedo, desde el Browser, selecciona esa clase. A continuación, añade los nombres de variables a la clave instanceVariableNames:, separadas por espacio. Por último, guarda la definición de la clase actualizada con el atajo Ctrl-s:

Object subclass: #Torpedo
   instanceVariableNames: 'position heading velocity lifeSpan'
   classVariableNames: ''
   poolDictionaries: ''
   category: 'Spacewar!'

Ejemplo 3.14: La clase Torpedo con sus variables de instancia

 CuisLogo Añade las variables de instancias descritas arriba a las clases SpaceWar, CentralStar y SpaceShip.

Ejercicio 3.9: Variables de instancia de los protagonistas de Spacewar!

3.6.3 Comportamientos

Necesitamos acceder a algunos de estos estados desde otras entidades:

Para escribir estos comportamientos en el Browser primero selecciona la clase, luego la categoría de método que quieres, o si no quieres ninguna -- all --.

En el panel de código aparece la plantilla de método:

messageSelectorAndArgumentNames
   "comment stating purpose of message"
   | temporary variable names |
   statements

Ejemplo 3.15: Plantilla de método

Se describe a sí misma:

  1. Línea 1. Es un nombre de método obligatorio, el mismo del mensaje.
  2. Línea 2. Un comentario opcional entre comillas dobles.
  3. Línea 3. Una lista opcional de variables locales del método entre barras verticales.
  4. Línea 4. La subsiguiente lista de mensajes enviados y asignaciones.

El getter mass de SpaceShip está escrito como:

SpaceShip>>mass
   ^ mass

La parte SpaceShip>> no es código válido y no se debe escribir en el Browser. Es una convención de texto para indicarle al lector que es un método de la clase SpaceShip.

 CuisLogo Escribe unos mensajes getter de SpaceShip para sus atributos de posición, velocidad y masa.

Ejercicio 3.10: Mensajes getter de SpaceShip

Algunas variables de instancia se deben inicializar desde otra entidad, para esto es necesario un mensaje setter. Para establecer el nombre de una nave espacial podemos añadir el siguiente método:

SpaceShip>>name: aString
   name := aString

El caracter := es una asignación, significa que la variable de instancia name contiene un objeto aString. Para teclear este símbolo, teclea _ y luego espacio, Cuis-Smalltalk lo convertirá en un símbolo de flecha izquierda. Alternativamente puedes escribir name := aString. Se podría pronunciar := como «gets».

Dado que name es una variable de instancia, cada método de instancia sabe que debe utilizar el espacio para el nombre. Lo que significa que estamos colocando el valor del argumento aString en el espacio de la instancia llamado name.

Dado que cada elemento de la variable de instancia puede contener un objeto de cualquier clase, nos gusta nombrar el argumento para indicar que pretendemos que la variable name contenga una cadena, una instancia de la clase String.

 CuisLogo La posición (position) y velocidad (velocity) de la nave, tanto como el rumbo (heading) del torpedo se deben establecer al inicio del juego o cuando la nave salta en el hiperespacio. Escribe los apropiados setters.

Ejercicio 3.11: Mensajes setter de SpaceShip

Fíjate que no tenemos un mensaje setter para el atributo mass (masa) de la nave espacial. De hecho, no tiene sentido cambiar la masa de una nave desde otro objeto. De hecho, si consideramos que ambas naves de los jugadores tienen la misma masa, deberíamos eliminar la variable mass y editar el método #mass para que devuelva un número literal:

SpaceShip>>mass
   ^ 1

Ejemplo 3.16: Un método devolviendo una constante

Por otro lado, también podríamos considerar que la masa depende del combustible y los torpedos consumidos. Después de todo, el 93 % de la masa del cohete Saturno V estaba compuesta por su combustible. Hablaremos más sobre esto más adelante, en el capítulo sobre refactorización.

Controles

Una nave espacial controlada por el jugador comprende mensajes para ajustar su dirección y aceleración17:

Dirección. El rumbo de la nave se controla con los mensajes #left y #right. El primero reduce el rumbo en 0.1 y el segundo lo incrementa en 0.1.

 CuisLogo Escribe dos métodos llamados left y rightpara modificar el rumbo de la nave en 0.1 de acuerdo con las indicaciones anteriores.

Ejercicio 3.12: Métodos para controlar el rumbo de la nave

Aceleración. Cuando se envía el mensaje #push a la nave, se encienden los motores y una aceleración interna de 10 unidades de aceleración se aplican a la nave. Cuando se envía el mensaje #unpush, la aceleración se detiene.

 CuisLogo Escribe dos métodos llamados push y unpush para ajustar la aceleración interna de acuerdo con las indicaciones anteriores.

Ejercicio 3.13: Métodos para controlar la aceleración de la nave

3.6.4 Inicializado

Cuando se crea una instancia, por ejemplo, SpaceShip new, se inicializa automáticamente: se envía el mensaje #initialize al objeto recién creado y se llama al método de instancia initialize correspondiente.

El proceso de inicialización es útil para establecer los valores predeterminados de las variables de instancia. Cuando creamos un nuevo objeto nave espacial, queremos establecer su posición, velocidad y aceleración predeterminadas:

SpaceShip>>initialize
   super initialize.
   velocity := 0 @ 0.
   position := 100 @ 100.
   acceleration := 0

Ejemplo 3.17: Inicializar la nave espacial

En el método Ejemplo 3.17, observa la primera línea super initialize. Cuando se envía un mensaje a super, se refiere a la superclase de la clase del método. Hasta ahora, la clase padre de SpaceShip es Object, por lo que, para la inicialización, primero se llama al método Object>>initialize.

Cuando se crea una nave espacial se coloca en la parte superior y derecha de la estrella central. No tiene velocidad ni aceleración interna, solo la fuerza gravitatoria de la estrella central. Su proa apunta hacia la parte superior de la pantalla del juego.

Probablemente hayas notado que no hay código para inicializar el atributo heading, algo como heading := Float halfPi negated para orientar la nave en la dirección de la parte superior de la pantalla. La verdad es que no necesitamos el heading, ya que esta información la proporcionará la clase Morph, que se utilizará más adelante como clase padre de SpaceShip y Torpedo. En este momento, se eliminará la variable heading y definiremos el comportamiento de la dirección con los métodos heading y heading: adecuados.

 CuisLogo Escribe el método para inicializar la estrella central con 8000 unidades de masa.

Ejercicio 3.14: Inicializar la estrella central


Notas al pie

(17)

La velocidad es una consecuencia de las aceleraciones aplicadas a la nave espacial.