lunes, 29 de enero de 2018

Pirates Tycoon - Introduction

Introducción al concepto del juego


Como mencioné antes, hace mucho que tenía las ganas de hacer un juego del estilo "Tycoon".

Si bien muchas variantes me vinieron a la cabeza, decidí por mezclar una de mis temáticas preferidas, piratas. Después pensé... ¿Cómo hubiera sido administrar todo el "imperio" pirata en su época de oro?

Pero a diferencia de mi manera usual de hacer juegos, esta vez no voy a hacer el juego completo sino una "demo". El jugador va a tener completa libertad de lo que puede hacer pero el tiempo de juego va a estar limitado a varios días (o meses) en el tiempo del juego. Esto es para que el jugador pueda sentir el "medio juego" y el concepto general se pueda expresar de mejor manera.

Las posibilidades hasta ahora van a ser desde construir edificios y poder mejorarlos hasta organizar saqueos a flotas extranjeras para ganar recursos. También tengo en mente poder desarrollar relaciones con piratas famosos al estilo de Civilization pero esto último esta por verse.

Esto es lo que pude hacer hasta ahora:


Como siempre, prefiero dedicarme primero a las mecánicas generales y después ir a los detalles artísticos como los modelos del terreno y de los objetos en escena, además de las interfaces.

El mapa fue cargado directamente de una imagen de 10x10 px, fue una idea que vi de un tutorial del Youtuber "Quill18" (https://www.youtube.com/watch?v=5RzziXSwSsg&t=1s) que después también implementó el otro Youtuber "Brackeys" (https://www.youtube.com/watch?v=B_Xp9pt8nRY).

Lo siguiente en lo que voy a trabajar es en las ventanas que deben mostrar cada edificio si se hace click en él, mostrando la información que corresponda.


//Detalles técnicos

En el caso de la implementación de Brackeys, hice un cambio en la forma de verificar qué color corresponde con cada tipo de suelo. Utilicé un diccionario, ya que su orden de Búsqueda es O(1) en vez de verificar en toda la lista de colores cual color corresponde con el tipo de suelo, que tiene un orden O(n).

Hasta la próxima.

-L

jueves, 11 de enero de 2018

C++ Snake Dev Guide Part 3

Tercera parte: movimiento en el mapa y Game Over



Última parte! Como mencioné antes, voy a dedicar esta parte para explicar en más detalle la lógica de cómo saber si el jugador perdió y además, cómo hacer para que la serpiente pueda salir por un borde del mapa y aparecer por otro.

Primero voy a explicar lo último que es más simple.

Si tenemos un tablero de 10 lugares, sabemos que podemos ir desde la posición 0 hasta la 9. Pero sabemos que en el juego Snake si pasamos la casilla 9, volvemos a estar en la casilla 0, como si hubiera un portal para la serpiente.

Esto se hace simplemente forzando la posición de la serpiente. Si la posición de la parte de la serpiente es mayor o igual a 9, que ahora sea 0. Esto va a obligar a el juego a mandar a la serpiente a un extremo si la serpiente se pasó por otro.

Para los bordes izquierdo y el inferior es el mismo truco, si la posición de la serpiente es menor o igual a cero, que se modifique a la posición (TAMAÑO_DE_MAPA - 1) para ir al extremo derecho o superior de la pantalla.

Hay que tener en cuenta que estas verificaciones debemos hacerlas después de que cada parte de la serpiente avanza. Es decir, primero una parte de la serpiente se mueve y luego se verifica si esta tiene que ir hacia otro extremo o no.

Ahora, el Game Over.

Podemos ignorar lo de más arriba y tener como otra condición que la serpiente no pueda tocar las paredes del mapa. 

En ambos casos, deberíamos tener un flag (una variable de tipo boolean) que nos indique si el jugador perdió o no. 

Para no tocar los bordes, tendríamos que verificar que si el jugador tocó alguno de los bordes, se active el flag (flag = true) y que se muestre la pantalla de Game Over.

El hecho de verificar si la serpiente se mordió a si misma son 3 líneas de código. Pero estas líneas puede que requieran un poquito de explicación.

Así es como se mueve la serpiente en todo momento:



Donde "H" es para la cabeza y "B" para el cuerpo. Podemos ver en la segunda imagen como se va armando el camino de la serpiente.

Ahora, lo más importante a notar es que las casillas que no están ocupadas por el cuerpo de la serpiente no tienen ninguna dirección. Osea que si una casilla tiene una dirección, es porque esta ocupada por una parte del cuerpo de la serpiente.

Entonces, si la cabeza de la serpiente entra en una casilla que ya tiene una dirección, esta se esta mordiendo a si misma. Esto nos va a servir como condición para activar nuestro flag y mandar al jugador a la pantalla de Game Over.

Desde acá hay todavía cosas que se pueden agregar. Como por ejemplo, un menú para jugar, un contador del puntaje, tiempo si es que queremos agregar esa funcionalidad, etc.

Yo no quise agregar más cosas para no complicar de más el proyecto. Pero si quieren, les recomiendo probar por su cuenta.

Acá termina esta guía para crear un clon del Snake. Espero que le haya servido a alguien para darse una idea de cómo arrancar a desarrollarlo o haber podido resolver alguna pregunta que alguien se haya hecho durante el desarrollo del juego.

Un saludo y hasta la próxima.

-L

miércoles, 10 de enero de 2018

C++ Snake Dev Guide Part 2


Segunda parte: Movimiento y Comida



Ya teniendo una idea de como armar la serpiente y el tablero, nos falta pensar como va a ser el movimiento de la serpiente y como esta va a crecer cada vez que come.

Lo que primero hice fue dibujar el tablero en pantalla, dibujando cuadrados y luego llenar la pantalla con los cuadrados, cambiando los colores de los cuadrados del borde para que se distingan y sean el borde del mapa.

Para la serpiente, lo que hice fue simplemente recorrer la estructura que la contenía (una lista, un array, etc) y por cada eslabón de la serpiente, dibujar en la pantalla un cuadrado (de color verde) en la posición x e y en donde estaba esa parte de la serpiente.

El movimiento de la serpiente es simplemente recorrer de nuevo el array que contiene la serpiente y por cada eslabón avanzar hacia una casilla correspondiente dependiendo la dirección indica la casilla actual. Esto se puede hacer fácilmente con un switch y aprovechando el enum que mencioné en la parte 1.

Entonces por ejemplo, si la casilla [1][1] tiene dirección arriba, indicamos que este eslabón de la serpiente ahora está en la casilla [2][1] (contando de arriba para abajo en filas) haciendo algo del estilo "eslabón->posiciónY++". No debemos olvidarnos de dos cosas importantes: 
  • La cabeza tiene que marcar de nuevo la dirección nueva.
  • Hay que borrar la dirección de la casilla de la última parte de la serpiente.

Lo primero es porque, una vez que toda la serpiente se mueve, la cabeza tiene que seguir indicando la dirección que tiene que seguir el cuerpo. Si no, sería el equivalente a que en un tren en marcha, la locomotora se desenganche y frene, sabemos que si esto pasa, los vagones van a chocar y apilarse con la locomotora.

Para la comida podemos hacer algo muy simple. Declarar 2 variables de tipo int indicando la posición x e y de la comida. Darle un valor aleatorio a estas posiciones y luego, mostrarlo en el mapa con un color distinto.

Para saber si la serpiente comió o no la comida lo que podemos hacer es que en cada movimiento que pase, la cabeza de la serpiente pregunte "¿mi casilla siguiente es la posición x y la posición y de la comida?" si la respuesta es si, agregamos un eslabón a la serpiente (agregar un elemento al array o a la lista) y ahora le decimos que la cabeza esta en donde estaba la comida. De esta forma, la serpiente se "agrandó".

De esta forma ya tenemos una serpiente que se puede mover y crecer al comer.

En la tercer parte voy a explicar los detalles finales como cómo hacer para que se pueda mover de un borde de la pantalla a otra o saber si se mordió a si misma.

Hasta la próxima.

-L

lunes, 8 de enero de 2018

C++ Snake Dev Guide Part 1


Primera parte: Estructura de la serpiente




Lo primero que vamos a hacer es pensar cómo va a ser la estructura que va a representar a la serpiente y que funcionalidad va a tener, eso nos va a dar una idea de como deberían funcionar las demás cosas:

El juego de Snake tiene una mecánica simple que se puede reducir en 3 reglas:
  • Para agrandar la serpiente hay que comer la comida del mapa.
  • El cuerpo debe seguir la trayectoria de la cabeza
  • Hay que evitar que la serpiente muerda su propio cuerpo
Esto ya nos da una idea general de como armar la serpiente. Por un lado, tenemos que el cuerpo tiene que "seguir" a la cabeza siguiendo la trayectoria que el jugador le indique. Esto nos da un indicio de que podemos subdividir el cuerpo de la serpiente en Cabeza y Cuerpo.

La pregunta ahora sería: ¿Cómo hacer para que el cuerpo pueda seguir la trayectoria?

Podemos pensarlo de la siguiente manera:

Podríamos dejar en el tablero "direcciones" que tiene que seguir el cuerpo, por ejemplo que en la casilla [2][3] del tablero haya algo que diga "ARRIBA" así el cuerpo sabe hacia donde tiene que ir.

Si queremos hacerlo de esta manera, nuestro tablero tiene que poder guardar las direcciones que el jugador le va asignando.

Por lo tanto, podemos crear una estructura auxiliar para las casillas del tablero. Una estructura que guarde la posición x e y de la casilla y la dirección que puede tener. Luego, el tablero va a estar compuesto de casillas. Para las distintas direcciones es recomendable utilizar un enum, ya que facilita el uso general.

Lo último que falta es borrar las direcciones cuando la última parte del cuerpo (la cola de la serpiente) ya pasó por ella. Para esto podríamos distinguir la serpiente entre Cabeza-Cuerpo-Cola o dejarlo como Cabeza-Cuerpo.

La gran ventaja que tiene esta forma es que podemos también saber cuando la serpiente se muerde a sí misma! Como la cabeza es la que marca las direcciones, siempre debería entrar a casillas que no tengan dirección (o tengan dirección "NONE"). Por lo tanto, si la cabeza entra en una casilla que ya tenía asignada una dirección, significa que la cola todavía no pasó por ahí y no borró esa dirección. Entonces, significa que la serpiente se mordió a si misma.

Así que de esta manera podemos hacer que el cuerpo siga una trayectoria y tenemos también una forma de saber si el jugador perdió o no.

En la próxima parte vamos a ver cómo hacer el movimiento y cómo crear la comida y hacer que la serpiente crezca.

Hasta la próxima.

-L






domingo, 7 de enero de 2018

C++ Snake


De nuevo al proyecto de Snake!

Debido a que el artista que trabaja conmigo en Rock Climber esta de vacaciones, no pude avanzar más en ese proyecto, por lo que decidí volver a esta idea que tenía de hacer un Snake en C++ para enseñarme a mi mismo como usar el lenguaje.

Así que borré todo lo que había hecho (muy poco) y decidí comenzar de nuevo. Primero definí como estructurar a la serpiente, sabiendo que lo más importante es que el cuerpo tiene que seguir la trayectoria que el jugador hace y luego, dedicarme en el tablero.

A mi sorpresa, si bien hubieron algunas partes en las que me atasqué, el juego esta terminado! Pueden ver el código en Github así también como una rápida guía de como ejecutarlo (Para S.O. Linux, no fue probado en Windows).

Es un juego simple y cumplió su propósito, aprendí a como utilizar una librería gráfica (OpenGL) para crear una ventana y para dibujar en ella, aunque esto lo hice mediante a un framework llamado "Glut" que facilita mucho el trabajo.

En lo que más me atasqué fueron errores de sintaxis del lenguaje o de relación entre los archivos, como por ejemplo cómo hacer para que el archivo que tiene la mecánica de la serpiente pueda acceder al tablero que esta en otro archivo. Por suerte muchos foros en internet sobre Glut o directamente sobre C++ tenían las respuestas, así que no fueron graves problemas.

Próximamente voy a estar subiendo unos posts explicando una par de decisiones que tomé para el diseño del juego. Que también le pueden servir de guía para quien quiera armar el juego también!



Hasta la próxima.

-L