Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming

Crear un juego simple de asteroides usando entidades basadas en componentes

by
Read Time:11 minsLanguages:

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

En el tutorial anterior, hemos creado un sistema basado en componentes basados en componentes. Ahora usaremos este sistema para crear un simple juego de asteroides.


Vista previa del resultado final


Este es el sencillo juego de asteroides que vamos a crear en este tutorial. Está escrito con Flash y AS3, pero los conceptos generales se aplican a la mayoría de los idiomas.

El código fuente completo está disponible en GitHub.


Descripción de la Clase

Hay seis clases:

  • AsteroidsGame, que extiende la clase de juego base y agrega la lógica específica a nuestro espacio dispararles.    
  • Ship, que es lo que controlas.
  • Asteroid, que es la cosa en la que disparas.
  • Bullet, que es lo que disparas.
  • Gun, que crea esas balas.
  • EnemyShip, que es un extranjero errante que está ahí para añadir un poco de variedad al juego.
  • Vamos a pasar por estos tipos de entidad, uno por uno.


    La clase Ship

    Comenzaremos con la nave del jugador:

Hay un poco de detalles de implementación aquí, pero lo más importante es notar que en el constructor instanciamos y configuramos los componentes Body, Physics, Health, View y Weapon. (El componente Weapon es de hecho una instancia de Gun en lugar de la clase base de armas.)

Estoy usando las API de dibujo de gráficos Flash para crear mi nave (líneas 29-32), pero podríamos utilizar con igual facilidad una imagen de mapa de bits. También estoy creando una instancia de mi clase Gamepad - esta es una biblioteca de código abierto que escribí hace un par de años para facilitar la entrada de teclado en Flash.

También he reemplazado la función update de la clase base para añadir un comportamiento personalizado: después de activar todo el comportamiento por defecto con super.update() rotaremos y empujaremos la nave en base a la entrada del teclado, y dispararemos el arma si la tecla de disparo es presionado.

Al escuchar la señal de muerte died del componente health, activamos la función onDied si el jugador se queda sin puntos de golpe. Cuando esto sucede, le decimos al barco que se destruya a sí mismo.


La clase Gun

A continuación vamos a usar la clase Gun:

¡Este es corto! Simplemente anulamos la función fire() para crear una nueva Bullet cada vez que el jugador se dispara. Después de hacer coincidir la posición y la rotación de la bala con el barco, y empujándolo en la dirección correcta, enviamos entityCreated para que pueda ser añadido al juego.

Una gran cosa acerca de esta clase Gun es que es utilizado por el jugador y las naves enemigas.


La clase Bullet

Un Gun crea una instancia de esta clase Bullet:

El constructor instancia y configura el cuerpo, la física y la vista. En la función de actualización, ahora puede ver la lista de objetivos targets se vuelve util, ya que el bucle a través de todas las cosas que queremos golpear y ver si alguno de ellos están intersectando la bala.

Este sistema de colisión no escalaría a miles de balas, pero está bien para la mayoría de los juegos casuales.

Si la bala tiene más de 20 marcos de edad, comenzamos a desaparecer, y si es más de 25 marcos lo destruimos. Al igual que con el arma Gun, la bala Bullet es utilizado por el jugador y el enemigo - las instancias sólo tienen una lista de objetivos diferentes.

Hablando de que...


La Clase EnemyShip

Ahora veamos esa nave enemiga:

Como puede ver, es bastante similar a la clase de la nave del jugador. La única diferencia real es que en la función update(), en lugar de tener el control del jugador a través del teclado, tenemos algo de "estupidez artificial" para hacer que el buque pase y dispare al azar.


La clase Asteroid

El otro tipo de entidad en el que el jugador puede disparar es el propio asteroide:

Esperemos que te acostumbras a cómo estas clases de entidad parecen ahora.

En el constructor inicializamos nuestros componentes y aleatorizamos la posición y la velocidad.

En la función update() verificamos las colisiones con nuestra lista de objetivos, que en este ejemplo solo tendrá un solo elemento, la nave del jugador. Si encontramos una colisión hacemos daño al objetivo y luego destruimos el asteroide. Por otro lado, si el asteroide está dañado (es decir, es golpeado por una bala de jugador), lo reducimos y creamos un segundo asteroide, creando la ilusión de que ha sido destruido en dos partes. Sabemos cuándo hacerlo escuchando la señal de "daño" del componente de Salud.


La clase AsteroidsGame

Por último, veamos la clase AsteroidsGame que controla todo el espectáculo:

Esta clase es bastante larga (bueno, más de 100 líneas!) Porque hace muchas cosas.

En startGame() crea y configura 10 asteroides, la nave y la nave enemiga, y también crea el mensaje "CLICK TO START".

La función start() reanuda el juego y elimina el mensaje, mientras que la función gameOver hace una pausa en el juego y restaura el mensaje. La función restart() escucha un clic del ratón en la pantalla Game Over - cuando esto sucede, detiene el juego y lo vuelve a iniciar.

La función update() recorre a través de todos los enemigos y distorsiona cualquiera que haya quedado fuera de la pantalla, así como la comprobación de la condición de victoria, que es que no hay enemigos en la lista de enemigos.


Tomándolo más lejos

Este es un motor de huesos muy simple y un juego simple, así que ahora vamos a pensar en maneras de expandirlo.

  • Podríamos agregar un valor de prioridad para cada entidad y ordenar la lista antes de cada actualización, de modo que podamos asegurarnos de que algunos tipos de Entidad siempre se actualicen después de otros tipos.
  • Podríamos usar el agrupamiento de objetos para reutilizar objetos muertos (por ejemplo, viñetas) en lugar de crear cientos de nuevos.
  • Podríamos añadir un sistema de cámara para que podamos desplazar y ampliar la escena. Podríamos ampliar los componentes de Cuerpo y Física para añadir soporte para Box2D u otro motor de física.
  • Podríamos crear un componente de inventario, para que las entidades puedan transportar elementos.

Además de ampliar los componentes individuales, es posible que a veces necesitamos ampliar la interfaz IEntity para crear tipos especiales de Entity con componentes especializados.

Por ejemplo, si estamos haciendo un juego de plataforma, y ​​tenemos un nuevo componente que maneja todas las cosas muy específicas que un personaje de juego de plataforma necesita - están en el suelo, están tocando una pared, cuánto tiempo han sido En el aire, pueden saltar de doble salto, etc. - otras entidades también podrían tener acceso a esta información. Pero no es parte de la API Entity principal, que se mantiene intencionalmente muy general. Así que tenemos que definir una nueva interfaz, que proporciona acceso a todos los componentes de entidad estándar, pero añade acceso al componente PlatformController.

Para esto, haríamos algo como:

Cualquier entidad que necesite funcionalidad de "plataforma" implementa esta interfaz, permitiendo que otras entidades interactúen con el componente PlatformController.


Conclusiones

Incluso atreviéndome a escribir sobre la arquitectura del juego, temo que estoy moviendo un nido de opinión de avispones - pero eso es (en su mayoría) siempre una buena cosa, y espero que por lo menos te he hecho pensar en cómo organizar tu código.

En última instancia, no creo que usted debe ponerse demasiado colgado sobre cómo estructurar las cosas; Lo que funciona para que usted haga su juego es la mejor estrategia. Sé que hay sistemas mucho más avanzados que el que aquí delineo, que resuelven una gama de problemas más allá de los que he discutido, pero pueden tender a comenzar a parecer muy desconocido si estás acostumbrado a una arquitectura basada en herencia tradicional.

Me gusta el acercamiento que he sugerido aquí porque permite que el código sea organizado por el propósito, en pequeñas clases enfocadas, mientras que proporciona una interfaz extensible y sin el confiar en características dinámicas del lenguaje o las búsquedas de String. Si desea modificar el comportamiento de un componente en particular, puede ampliar ese componente y anular los métodos que desee cambiar. Las clases tienden a permanecer muy cortas, así que nunca me encuentro desplazándome por miles de líneas para encontrar el código que busco.

Lo mejor de todo, soy capaz de tener un solo motor que es lo suficientemente flexible como para usar en todos los juegos que hago, ahorrándome una enorme cantidad de tiempo.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.