lunes, 10 de octubre de 2016

Crear un clon del Ahorcado en C


Español


Primero quiero aclarar que la 3era parte del proyecto de Generación Procedural de Circuitos de Carrera esta por salir. Todavía no funciona del todo pero empieza a dar resultados de a poco como el siguiente:


Pero ahora les traigo un trabajo práctico que tuve que hacer para una materia de programación. 

Vamos a recrear el juego del Ahorcado escrito en ANSI C, totalmente portable para Windows o Linux. (Nota: el juego va a ser desarrollado para Linux).

Las herramientas a usar son:
  •  Sublime Text
  • Compilador GCC

Los encabezados de las librerías que vamos a usar en todo el proyecto son:
  • stdio.h
  • stlib.h
  • time.h
  • string.h
  • ctype.h
Todo pertenecen a la librería estándar.


 Primero vamos a dividir en pasos que es lo que le programa va a hacer:
  1. Dibujar la pantalla inicial, la que va a contener al dibujo del ahorcado.
  2. Elegir de una lista de palabras una, de forma aleatoria.
  3. Pedir al usuario que introduzca una letra.
  4. Verificar si la letra pertenece o no a la palabra secreta, en caso de que si, reemplazar los espacios en blanco de la palabra secreta con la letra. Si no, dibujar una nueva parte del ahorcado.
  5. Repetir 4 hasta que se adivine la palabra o se haya dibujado a todo el ahorcado.
Para el dibujo del ahorcado lo que quería hacer es utilizar símbolos ASCII para dibujar como sería el peor caso:

/*    MATRIZ DIBUJO
   
          |
          |    Bye
          []
        --|--
          |     r
         / \    |
     ----------
   /            \

*/

Primero debemos dibujar la "MATRIZ DIBUJO" pero sin la persona. En mejor caso (que el jugador acierte todas las letras), esta no cambiaría.

ALTO y ANCHO son 2 constantes simbólicas que las calculé de acuerdo a cuantos caracteres ocupaba la matriz dibujo que hice arriba.

void
Dibujar(int m[ALTO][ANCHO]){
    for(int i = 0; i < ALTO_DIBUJO; i++){
        for(int j = 0; j < ANCHO_DIBUJO; j++){
            if( (i==0 || i==1) && j==6){
                m[i][j] = '|';
            }      
            else if(i==7 && j!=0 && j!= ANCHO-1){
                m[i][j] = '-';
            }
            else if(i==8 && j==0){
                m[i][j] = '/';
            }
            else if(i==8 && j==ANCHO-1){
                m[i][j] = '\\';
            }
            else if( i==4 && j==10){
                m[i][j] = 'r';
            }
            else if( (i==5 || i==6) && j==10){
                m[i][j] = '|';
            }
            else{
                m[i][j] = ' ';
            }
        }
    }
}
Se podría haber simplificado y simplemente en vez de tener los else if poner los correspondientes m[i][j] para cada caracter especial.

Para todos los demás caracteres que no forman parte del dibujo, los rellené con espacios.

Ahora vamos a la función errar.

A esta función se la llama si el jugador no acertó la letra. Se encarga de aumentar un contador de error "cant_err" y dependiendo de cuanto valga esta variable, dibujar una parte del ahorcado.

void
errar(int * cant_err, int m[ALTO][ANCHO]){
    (*cant_err)++;
    switch(*cant_err){
        case 1:
                m[2][6] = '[';
                m[2][7] = ']';
                break;
        case 2:
                m[3][6] = '|';
                m[4][6] = '|';
                break;
        case 3:
                m[3][7] = '-';
                m[3][8] = '-';
                break;
        case 4:
                m[3][5] = '-';
                m[3][4] = '-';
                break;
        case 5:
                m[5][5] = '/';
                break;
        case 6:
                m[5][7] = '\\';
                m[1][9] = 'B';
                m[1][10] = 'y';
                m[1][11] = 'e';
                m[6][10] = '/';
                m[5][11] = '/';
                m[5][10] = ' ';
                m[4][12] = 'r';
                m[4][10] = ' ';
                break;
    }
}

Ahora vamos con la función que verifica si la letra que ingresamos pertenece o no a la palabra:

int
verificar_letra(char * palabra_secreta, char letra, char * vec_resp){
    int flag=0;
    for(int i = 0; palabra_secreta[i]!=0; i++){
        if(palabra_secreta[i] == letra){
            vec_resp[i] = letra;
            flag=1;
        }
    }
    return flag;
}

Como podrán ver, esta función nos retorna 1 si la letra estaba en la palabra secreta y 0 si no lo estaba. Además, le asigna la letra a un vector llamado "vec_resp".

El vector "vec_resp" es un vector que tiene la misma dimensión que la palabra secreta que se elija, su función es llenarse con "*" para mostrárselo al usuario y que, si este acierta, se reemplace con la letra correspondiente.

Para crear este vector utilizamos la función "Crear_vector_Respuesta":

char *
Crear_vec_respuesta(char * palabra_secreta){
    int i=0, j;
    char *p;
    while(palabra_secreta[i]){
        i++;
    }
    p = malloc(i);
    for( j =0 ; j< i;j++){
        p[j] = '*';
    }
    p[j] = 0;
    return p;
}

La mejor forma de hacerlo es creando un vector de forma dinámica, pues no sabemos la longitud de la palabra que se va a elegir aleatoriamente. Entonces la función calcula la longitud de la palabra que se eligió y crea un vector de esa dimensión lleno de "*".

Ahora lo que quiero hacer es dibujar en cada paso la "MATRIZ DIBUJO". Si el jugador falla, la función "errar" cambiará la matriz pero esta va a simplemente imprimirla. Esta función también va a imprimir al "vector respuesta".

void
Imprimir_pantalla(int m[ALTO][ANCHO] char *vec_resp, char *usadas){
    LIMPIAR_PANTALLA;
    printf("\n");
    for(int i = 0; i < ALTO; i++){
        printf("\t\t");
        for(int j = 0; j < ANCHO; j++){
            printf("%c", m[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
    printf("\t    \t");
    for(int i = 0; vec_resp[i] != 0 ; i++){
        printf("%c ", vec_resp[i]);
    }
    printf("\t    \t \n");
    printf("\t Usadas: ");
    for(int i = 0; usadas[i] != 0 ; i++){
        printf("%c ", usadas[i]);
    }

    printf("\n");
    LIMPIAR_PANTALLA;
}

 Donde  LIMPIAR_PANTALLA es una macro que simplemente contiene un printf con varios "\n" dentro.

Esta función lo que hace es recorrer todos los vectores e imprimir sus valores como caracteres. La tabulación es simplemente por presentación. 

Lo importante de usar tantos espacios en blanco es para que, al imprimir la pantalla luego de que el jugador introdujo una letra, no pueda ver los "restos"  de las impresiones previas.

Lo último de esta función también utiliza un vector llamado "usadas", este vector es simplemente un vector de longitud 6 (lo máximo que puedo fallar es 6 veces, cuando se dibujó todo) en donde se irán mostrando las letras incorrectas que ya usamos.

Finalmente, la función main se encarga de inicializar los vectores y de controlar el ciclo principal del juego.

int
main(void){
int Matriz_Dibujo[ALTO][ANCHO], cant_err=0, k, w_used=0, h=0;
char lett;
char *palabras[5]={"ARBOL", "CASA", "AUTO", "JUEGOS", "COMPUTADORA"};
char * palabra_secreta, *vec_resp, usadas[7];
    srand(time(NULL));
    while(usadas[h]!=0){
        usadas[h]=0;
        h++;
    }
    palabra_secreta = palabras[rand()%5];
    Dibujar(Matriz_Dibujo);
    vec_resp = Crear_vec_respuesta(palabra_secreta);
    Imprimir_pantalla(Matriz_Dibujo, vec_resp, usadas);
    do{
        lett = toupper(getchar());
        getchar(); //para quitar el \n //IMPORTANTISIMO
        k = verificar_letra(palabra_secreta, lett, vec_resp);
        if(k){
            Imprimir_pantalla(Matriz_Dibujo,vec_resp, usadas);
        }
        else{
            usadas[w_used++] = lett;
            errar(&cant_err, Matriz_Dibujo);
            Imprimir_pantalla(Matriz_Dibujo, vec_resp, usadas);
        }
    }while((lett='\n') && (cant_err != 6) && (strcmp(palabra_secreta,vec_resp)!=0) );
    if(cant_err==6){
        printf("You Lose! the answer was %s \n", palabra_secreta);
    }
    if((strcmp(palabra_secreta,vec_resp)==0)){
        printf("You Win!!! \n");
    }
    return 0;
}

Primero definimos las variables que vamos a utilizar, puse también uno algunos ejemplos de palabras secretas para probar como funciona.

Después, inicializamos al vector "usadas" con todos ceros. Se podría haber hecho en otra función para mantener mejor estilo.

Luego, elejimos la palabra secreta siendo esta un elemento random de nuestro vector "palabras" y llamamos a la función Dibujar para crear el "setting" inicial para nuestro juego.

Creamos nuestro vector respuesta utilizando la función "crear_vec_respuesta" e imprimimos por primera vez la pantalla.

A partir de acá comienza el ciclo.

Se le va a pedir al usuario un caracter. Se va a utilizar la función verificar y a partir de ahí se va a determinar si se reescribe nuestro vector "respuesta", indicando que acertamos o si se modifica el vector "usadas" y se modifica la "matriz dibujo", indicando que erramos.

El ciclo se va a repetir mientras el caracter ingresado no sea un "enter", mientras la cantidad de errores no sea 6 (nuestro máximo) y mientras la palabra secreta sea distinta a la palabra secreta (utilizando la función string compare (strcmp)).

Luego, los if están para indicar si salimos del ciclo por que perdimos o por que ganamos.

Lo más importante del ciclo es: luego de pedirle al jugador un caracter con getchar(), hacer OTRO getchar(), para consumir el "\n" (el enter) del buffer, ya que si no, el ciclo se va a volver a ejecutar haciendo de cuenta que el caracter que ingresó el usuario es un enter.


Y eso es todo. 

Si quieren, pueden agregarle más palabras al conjunto de "palabras" para que sea más entretenido (y después cambiar el rand()%"nueva_cant_de_palabras" de la 10° línea del main).



Cualquier duda o sugerencia para optimizar pueden dejarla en los comentarios.

-L




 

domingo, 21 de agosto de 2016

Generación procedural de circuitos de carreras - Parte 2 | Race Track Procedural Generation - Part 2

Español | English


Esta va a ser la 2da parte de una serie de Posts en donde explico como crear pistas de carreras generadas aleatoriamente. La primer parte la pueden encontrar en mi blog.

En la parte anterior, había definido la siguiente estructura lógica que iba a utilizar el algoritmo de geneación:
  1. Generar un elemento de forma aleatoria
  2. Si ese elemento es una recta, seguir de largo, si es una curva, girar
  3. Repetir 1-2 hasta tener una cierta cantidad de elementos
  4. Buscar la forma de el último elemento con la posición inicial
Esta manera fue descartada, ya que había muchas cuestiones a tener en cuenta, como las rotaciones de las distintas partes y como estas influyen a las siguientes.

Así también como el hecho de que no era capaz de indicar el tamaño del mapa, ya que cada vez que se generaba, se creaba un camino hacia un sentido aleatorio, de esta forma no se podía limitar a que el mapa ocupe "10 unidades del eje Y".

Por eso que decidí cambiar la idea, teniendo primero una "grilla" que si puedo dimensionar y luego eligiendo las partes que van a ser usadas para la pista. Entonces el algoritmo se modificó a que recorra la siguiente secuencia:

  1. Crear una grilla de dimensiones X  e Y indicadas.
  2. Seleccionar los nodos eligiendo lugares aleatorios de la grilla
  3. Unir los nodos.

Esta idea de nodos esta pensada a base de Grafos:



En donde para generar el circuito, elijo cuantos nodos quiero que existan y luego busco la manera en la cual pueda unirlos (generar las aristas) de formas aleatorias, para que de una misma posición de nodos, pueda tener distintas variantes.

Por ahora estoy en la etapa 2. Estoy creando la forma en la cual se puedan elegir los nodos de forma aleatoria sin repeticiones y en lo posible que no estén juntos.



En la imagen se pueden ver: Los parámetros para la creación de la grilla, la grilla con sus elementos en gris y los nodos seleccionados aleatoriamente en rojo.

Lo siguiente es indicarle a las posiciones que se eligieron que van a representar nodos. Luego de eso, empieza la etapa 3 de pathfinding, en la cual a partir de esos puntos, hay que crear las formas de unirlos para generar los circuitos.

-L 


-------------------------------------------------------------------------------------------------------------------------
English


This is going to be the second part of a series of Posts where I explain who to create procedural generated racing tracks. You can find the first part on my blog.

On the previous part, I've defined the next series of steps that were going to be part of the generator algorithm:
  1. Generate a random element
  2. If that element is a straight line, move forward, if it is a curve, turn
  3. Repeat 1-2 until there are a certain amount of elements
  4. Find the way to join the final position with the starting position
This way was thrown away, as there were too many things to take into consideration, like the rotations of the different parts and how they influence on the next parts.

As well as the fact that I wasn't able to set the size of he map, because every time the map was generated, a different path as created, so I couldn't limit the size map by saying that the map should be "10 units on the Y axis".

That's why I decided to change the idea, using a grid which in fact I can set the size and then selecting the parts that are going to be used for the track. So the algorithm changed to follow the next steps.
  1. Create a grid of X and Y dimensions.
  2. Select the nodes by selecting a random positions of the grid.
  3. Join the nodes
This node-idea was thought thinking of Graphs:



Where to generate the track, I choose how many nodes I want and then I find the way to join them together (generate the edges) in random ways, so the same set of positions of nodes can generate different variatons.

Right now I'm on stage 2. I'm creating the way in which I can select the nodes from the random positions of the grid without repeating and if possible, not side by side.




On the image it can be seen: The parameters for the creating of the grid, the grid with its grey elements and the nodes, randomly selected in red.

The next step is to indicate to those positions that were chosen that they will represent nodes. After that, the 3 stage begins, pathfinding. In which I'll have to create different ways to join the nodes to generate the racing tracks.

-L 

lunes, 15 de agosto de 2016

Generación procedural de circuitos de carreras - Parte 1 | Race Track Procedural Generation - Part 1

Español | English 


Hoy vengo a presentar un nuevo proyecto/desafío. Me propuse crear un algoritmo para crear circuitos de carreras de forma aleatoria en Unity. Esta va a ser la parte 1 de no se cuantas en las que voy a explicar como hago para lograr mi objetivo.

La idea básica sobre la cual va a funcionar el algoritmo es:

  1. Generar un elemento de forma aleatoria
  2. Si ese elemento es una recta, seguir de largo, si es una curva, girar
  3. Repetir 1-2 hasta tener una cierta cantidad de elementos
  4. Buscar la forma de el último elemento con la posición inicial
Hasta ahora estoy en el paso 3. En la cual puedo generar varios elementos y colocarlos como hijos de un elemento llamado "Track". Lo que puedo generar por ahora es esto:


Los elementos rojos son Curvas rectas, los marrones son curvas hacia la izquierda y los violeta curvas hacia la derecha. Por ahora solo quería probar como resultaba el paso 1 y el paso 2.

La lógica (mal hecha) fue: si se crea una recta, mover hacia adelante y generar otro elemento, si es una curva, mover hacia el costado y generar otro elemento y así sucesivamente. 

¿Por qué esta mal? Porque no tomé en cuenta las rotaciones que generan las curvas, para poder apreciarlas voy a necesitar más que una imagen de un cuadrado.

Pero como primera etapa, lo considero adecuado. Lo que tengo que hacer para tener esta etapa bien definida es no solo desplazar la posición antes de generar un nuevo elemento, sino que también rotarlo si el anterior era un curva, para crear un nuevo sentido.

Lo más difícil va a ser la etapa 4, en la cual tengo que hacer que desde la posición final, se creen los elementos necesarios para volver al inicio, algo que se me viene a la mente para hacer esto es utilizar un simple algoritmo de A* path-finding. 

Eso es todo por ahora, espero que les guste el nuevo desafío, cualquier duda o sugerencia pueden dejarla en los comentarios.


-L


-----------------------------------------------------------------------------------------------------------

English


Today I'm here to present a new project/challenge. I made up my mind to create an algorithm that creates race tracks randomly in Unity. This is going to be part 1 of I don't know how many, in which I'll be explaining what I'm thinking in order to achieve my goal.

The basic idea on which the algorithm works is:
  1. Generate a random element
  2. If that element is a straight line, move forward, if it is a curve, turn
  3. Repeat 1-2 until there are a certain amount of elements
  4. Find the way to join the final position with the starting position
For now I'm on step 3. In which I can create several elements and put them as child of a GameObject named "Track". What I can generate by now is this:


The logic (poorly made) was: If a straight line is created, move forward and generate another element, if it is a curve, move to the side and generate another element and so on...

Why it is poorly made? Because I didn't take into consideration the rotations that the curves generate, to be able to see them more clearly I'll have to use something else than a red square.

But for the first stage, I found it right. What I have to do in order to make this stage properly is to not only move the position of the next element that is going to be generated, but also rotate it if the previous element was a curve, in order to create a new direction.

The most difficult stage is going to be stage 4, where I have to figure out a way in which, from the final position, create the necessary elements that are needed to come back to the starting point. Something that comes to my mind for this task might be a simple A* path-finding algorithm.

That's all for now, I hope you like this new challenge, for any doubt or suggestion you can write me a comment.


-L

domingo, 14 de agosto de 2016

¿Y ahora qué? | And now what?

Español | English

Ahora que terminé el proyecto Nerdy Run, debo elegir si quiero algún nuevo proyecto para enfocarme, aunque también no hay que dejar de lado la tarea de seguir haciendo promoción para mis juegos.

Entre todos los proyectos que tengo para hacer, debería elegir por cual inclinarme más, también como decidir si volver a desarrollar para Android o pasar a la PC... Aunque por otro lado también tengo que practicar más mis habilidades artísticas.

Por eso es que tenía pensado más que nada realizar arte variado, ilustraciones, temas musicales, crear "Assets" que tal vez me sirvan para un futuro juego. Así también como practicar conceptos de programación, ver como crear un FPS o un Tower Defense por más simple que sea.

Así que mi objetivo por ahora es variado, practicar un poco de todo antes de meterme de lleno en un solo proyecto, de esta forma voy a poder practicar varias áreas dentro de el desarrollo de video-juegos, así también como subir nuevos tutoriales.

Así que estén atentos al blog!


-L

------------------------------------------------------------------------------------------------------------
English

Now that I've finished the project Nerdy Run, I must choose if I want a new project to focus all my time to, although I shouldn't leave aside the task of promoting my games. 

Between all the projects I have to do, I should choose which one to focus my attention to and decide whether I should continue developing for Android or go to PC... Although on the other hand I also have to practice my art skills

That it why I was thinking of doing varied art, illustrations, music themes, create "Assets" that I might one day use for a game. As well as practice my programming skills, like how to create a basic FPS or a Tower Defense, as simple as it can be.

So my goal now is varied, practice a little bit of everything before stepping into a new project, in this way, I can practice several areas that merge together to make the development of games, as well as uploading new tutorials.


So stay tuned to the blog!

-L

viernes, 5 de agosto de 2016

Nerdy Run publicado!!! | Nerdy Run released!!!

Español |  English



Al fin! Nerdy Run ya está disponible para descargar en la tienda de Google Play. Hasta ahora tuve buenas respuestas de parte de amigos/conocidos. 

Hasta mañana no voy a tener ningún tipo de dato como cantidad de descargas o similares, también tengo que esperar hasta que Admob reconozca la aplicación en Google Play para poder vincular la cuenta.

A partir de ahora mi trabajo va a ser compartir el juego, promocionarlo y escuchar las devoluciones de los usuarios. También voy a trabajar en una actualización en donde esté integrado Tappx para utilizar el servicio de Closs-Promotion.

Eso es todo por ahora, espero que disfruten el juego.



-L




------------------------------------------------------------------------------------------------------

 English



Finally! Nerdy Run is available on the Google Play store. So far I had good responses from my friends and people I know.

Until tomorrow I won't be able to tell how many downloads the game has or that kind of information, I have to wait for Admob too to recognize the game on the Play Store so I can link the app.

From now on my job will be to share the game, promote it and listen to the users' feedback. I'll also be working on an update where I'll implement Tappx so I can use the Cross-Promotion service.

That's all for now, I hope you enjoy the game.


-L

jueves, 4 de agosto de 2016

Preparando todo para mañana | Setting up everything for tomorrow

Español | English



Nerdy Run ya esta completamente terminado. Fue probado varias veces y todo funciona. Solo queda esperar hasta  mañana para ya subirlo a la tienda de Google Play.

Al final decidí lanzarlo solo con Admob, sin Tappx ya que para implementar Tapps necesito que la App ya esté publicada, por eso, primero la publicaré y luego haré las cosas necesarias para que ambos servicios funcionen al mismo tiempo.

Un dato curioso es que salió una nueva versión del plug-in de Admob para Unity, lo que generó nuevos conflictos a la hora de implementarlo, pero afortunadamente encontré una solución. Espero que no haya nuevos conflictos entre Admob y Tappx.

Fue un lindo momento cuando me di cuenta que finalmente estaba terminado, ya todo corregido, ya no más cosas pendientes. Ahora solo queda publicar y esperar a ver la opinión de la gente.


-L


------------------------------------------------------------------------------------------------------

English



Nerdy Run is completely finished. I was tested several times and it works. I just need to wait until tomorrow to launch it on the Google Play Store.

I decided finally to launch it only with Admob, as Tappx needs the App to be already launched, so I'll launch it with Admob and then take the steps needed to implement Tappx and make sure they both work properly at the same time.

Something unexpected was that Admob released a new plug-in for Unity, which has generated many problems when people tried to use it but luckily I've found a solution. I hope there aren't new conflicts between Tappx and Admob.

It was a nice moment when I realized it was finally over, everything fixed, no more things to add. Now I have to publish it and see what people think about my game.

-L

miércoles, 3 de agosto de 2016

De idea a proyecto | From an idea to a project

Español | English



Como pueden ver en la foto de la izquierda, todo empezó con cuadrados rojos y sin fondo. De a poco se fuero agregando los detalles, corrigiendo las mecánicas y mejorando todo.

Si bien este proyecto me llevó más tiempo de lo que le tenía planeado, estoy contento con lo que se logró. Se pudo combinar de una forma divertida la base de Infinite Runner con los mini-juegos para resolver.


Esta bueno ver estas fotos y ver la diferencia entre lo que se pensó y lo que resultó ser.


La primera idea que tuve fue de hacer el juego en donde el personaje corría hacia abajo y nos desplazamos de izquierda a derecha.



También para algunos mini-juegos hubieron conceptos que después fueron descartados.


De cuadrados rojos a personajes y puntuación. El juego claramente evolucionó desde su etapa inicial, por mi lado voy a seguir trabajando para tener el juego listo para el viernes!



-L

--------------------------------------------------------------------------------------------

English


As you can see on the foto of the left, it all stated with red squares and without a background. Little by little the details were being added, the mechanics fixed and everything was improved.

Although this project took me more time than what I had planned, I'm happy with what I've achieved. The Infinite Runner base was successfully combined with the mini-games.



It is nice to look at this pictures and see the difference between what was first thought and what it become.


The first idea I had was to make the game so that the character run downwards and we move to the left or right.


There were some concepts of the mini-games that were also thrown away.


From red squares to characters and score. The game clearly evolved since its initial stage, by my side I'll continue working on the game so its ready for Friday!


-L

lunes, 1 de agosto de 2016

Fecha de lanzamiento de Nerdy Run! | Nerdy Run Release Date!


Español | English




Hola a todos, hoy les vengo a comentar una buena noticia: Nerdy Run tiene fecha de lanzamiento!

Estoy trabajando en los últimos detalles y haciendo las últimas pruebas. La fecha de lanzamiento es este viernes 5/8/16. Por lo que el juego estará disponible el día siguiente,sábado, en la tienda de Google Play.

El juego es completamente gratis. Durante la semana iré publicando más detalles sobre los programas que usé y voy a contar algunas historias y anécdotas. Así también como subir más tutoriales sobre las mecánicas que fui utilizando.

Así que sigan al tanto por más noticias!

-L

---------------------------------------------------------------------------------------------------------


English





Hello everyone, today I'm here to tell some good news: Nerdy Run has a release date!

I'm working on the last details of the game and doing the last tests. The release date is this Friday 5/8/16. So the game will be available on Google Play the next day, Saturday.

The game is completely free. During the week I'll be posting more details about the programs that I used and I'm going to tell some stories and anecdotes that happened to me. Also, I'll be uploading more tutorials about the mechanics I used for the game.

So stay tuned for more news!

-L






miércoles, 27 de julio de 2016

Como crear un fondo rotativo para Infinite Runners en Unity | How to create a scrolling background for Infinite Runners in Unity


Español | English



En este tutorial voy a enseñar como crear un fondo rotativo, esto es, un fondo que se mueva a medida que el jugador avanza. Este tutorial esta pensado para los juegos de estilo Infinite Runner, por lo tanto, se toma en cuenta que:
  1. El jugador siempre esta en movimiento
  2. El movimiento del jugador es constante

Aunque también se va a ver como crear este fondo para los casos en los que nuestro jugador este quieto o nuestro jugador haya variado la velocidad. Este tutorial sirve tanto para juegos 2D o 3D

Primero necesitamos un fondo, para ser más ilustrativo, voy a usar imágenes muy simples.


Este fondo de barras va a ser lo que vamos a utilizar, el hecho de que haya un rectángulo rojo es para poder distinguir mejor, nuestro fondo puede tener algún elemento que sea distintivo y sirva para marcar (un árbol, un edificio, etc).


Lo que vamos a hacer es importar esta imagen a Unity y asignarla como "Textura". Luego vamos a modificar el "Wrap mode" que por default esta en "Clamp" hacia "Repeat".

 Lo siguiente que vamos a hacer es crear un nuevo Material. Para eso vamos a dar clic derecho en el inspector/crear/material al que vamos a nombrar "fondo".Lo próximo va a ser modificar el Shader este nuevo material, lo queremos en Texture, para eso vamos a seleccionar de menú desplegable donde dice "Shader" y elegir "unlit/Texture"



Y arrastramos el fondo que importamos hacia el cuadrado al costado para indicarle al material su textura. Lo próximo es crear un Quad en el inspector, que va a ser donde vamos a colocar nuestro fondo, para eso vamos a GameObject/3D Object/Quad. Si queremos podemos remover el componente "Mesh Collider" de este, ya que no lo vamos a utilizar.

Luego, hay que asignarle a este Quad el nuevo material que creamos con nuestro fondo, para eso, seleccionamos al Quad y arrastramos el material que creamos hacia la pestaña Mesh Renderer/Materials/Element0 y luego podemos agrandar o achicar el Quad para que muestre lo que queremos del fondo.

La siguiente parte es de programación, lo que vamos a hacer es modificar el Offset del eje X del material dentro del Quad, eso va a rotar la imagen. A continuación muestro una imagen sin offset y una imagen con Offset:

Sin Offset (el fondo original):


Imagen con Offset;





Como podemos ver, la imagen se "corrió" hacia el costado y como a la derecha de la imagen no hay nada, se repite la imagen de nuevo, si este offset es continuo, se crea el efecto de que el fondo se esta moviendo.

Vamos a crear un Script llamado "Background_scroll" 

primero empezamos declarando las variables que vamos a utilizar:

public MeshRenderer mr;
public float scroll_vel = 0.4f; //el valor se pude cambiar a lo que más convenga.

Si se quiere simplemente que el fondo se mueva infinitamente sin importar que el jugador este quieto o no debemos escribir dentro de Update():

mr.material.mainTextureOffset = new Vector2( (Time.time * scroll_vel)% 1, 0);

lo que hace esto es indicarle al Mesh Renderer del Quad que su Material va a tener un offset de Time.time * scroll_vel  % 1

La parte más importante de todo está en el "%1", ya que Time.time va a ser cada vez más grande y lo que nosotros queremos es crear un offset entre el valor 0 (no offset) a 1 (una vuelta completa) por eso, se utiliza la congruencia con módulo 1 (los restos de dividir Time.time *scroll_vel con 1), ya que siempre van a estar entre 0 y 1.

Como dije antes, si solo se quiere que el fondo se mueva constantemente sin importar el jugador, ese es el código, faltaría únicamente desde el inspector arrastrar el Script hacia el Quar y arrastrar al Quad hacia "Mesh Renderer" para que se agarre a si mismo.

Si queremos que la velocidad varíe, necesitamos conocer la velocidad, para eso voy a asumir que la velocidad del jugador esta con acceso public static, en un Script "jugador". Entonces lo que haremos es modificar scroll_vel dependiendo de la velocidad del jugador.

declaramos la variable vel en Update(), ya que necesitamos que se actualice constantemente
vel = jugador.velocidad //referencia hacia una variable que indica la velocidad del jugador

Y simplemente, dentro de Update vamos a crear unos Ifs para variar dependiendo de la veloidad

If ( vel == 0 ){
    scroll_vel = 0; //para detener el scroll.
}

Por último, si la velocidad varía, por ejemplo que sea mayor a 0 y menor a 1, vamos a hacer decaer scroll_vel progresivamente. Para esto vamos a utilizar la función Mathf.Lerp(valor inicial, valor final, intervalo de tiempo).

If (vel > 0 && vel < 1)
{
    scroll_vel = Mathf.Lerp(0.4f, 0.2f, 0.5f); //hace decaer scroll_vel de 0.4 a 0.2 progresivamente
}

Debemos utilizar la función Lerp ya que no podemos utilizar cambios bruscos en la velocidad en la cual el fondo se rota.

Y eso es todo, con esto tenemos nuestro fondo rotativo para Infinite Runners.


-L


-----------------------------------------------------------------------------------

English



In this tutorial I'm going to teach how to create a scrolling backgound, this is, a background which scrolls as the player advances the level. This tutorial was thought for Infinite Runner games, so I take into consideration that:


  1. The player is always moving
  2. The movement speed is constant
Although it will also teach how to do for the case that our player isn't moving or his/her speed varies. This is both for 2D and 3D games

We first need a background, to keep things simple, I'm going to use very simple images:




This bar background will be the one we are going to use, the fact that it has a red rectangle is only to make very visible when we scroll it, your background may have a distinctive element that may be used for this (a tree, a building).

What we are going to do is to Import this image into Unity and assign it as a "Texture". Then, we are going to modify the "wrap mode" which by default is "Clamp" to "Repeat".

The next thing we are going to do is to create a new Material. For that we right click in the inspector/create/Material and we name it "Background". Next, we need to modify the Shader of this new material, we want it in Texture, for that we select from the drop down menu of Shader Unlit/Texture


And we drag the background that we imported to the square at the right to indicate the material its texture. Then we create a Quad in the Inspector, which will be use to place the background, for that we go to GameObject/3D Object/Quad. We can if we want, remove the "Mesh Collider" as we won't use it.

Next, we need to assign the Quad the Material which we created earlier, for that, we select the Quad and drag the Material to where it says "Mesh Renderer/Materials/Element0" and then we can adjust the size of the Quad to let it display the whole background.

The following part is about programming, what we are going to do is to modify the Offset of the X axis of the material inside the Quad, that will scroll the image. I'll now show you the background without offset and with offset:

Without Offset (the original background):


With Offset:




As we can see, the image "scrolled" to the side and as there is nothing at the right of the image, it began to repeat itself, if this offset effect is constant, we can create the effect that the image is scrolling.

Now we create a Script called "Background_scroll"

We first start declarating the variables we are going to use:

public MeshRenderer mr;
public float scroll_vel = 0.4f; //the value in here can vary to whatever you like

If you simply want to scroll the background infinitely without taking care if the player is still or not, we need to write this inside Update():

mr.material.mainTextureOffset = new Vector2( (Time.time * scroll_vel)% 1, 0);

What this does is to tell the Mesh Renderer of the Quad that his Material will have an offset of Time.time * scroll_vel  % 1

The most important part is in the "%1", as Time.time will always be increasing and what we want is to create an offset between 0 (no offset) to 1 (a full turn) that is why the congruence with module 1 is used ( the remainder of dividing Time.time * scroll_vel with 1) as they will always be between 0 and 1.

As I said before, if what you only want is the background to move constantly without taking care if the player is moving or not, that's the code, what it only needs to do left is to drag the Script from the inspector to the Quad and then drag the Quad to itselft where it says "Mesh Renderer" on the Script component.

If we want speed to vary, we need to know the player's current speed, for that I'm going to assume that the players velocity is in a public static float named velocity in a Script called "player". Then what we need to do is to modify scroll_vel depending the speed of the player.


We declare the variable vel in Update(), as we need it to be constantly updating

vel = player.velocity //reference to a value in the player script that indicates the player speed

We then simply make, inside the Update() function some Ifs statements to vary scroll_vel depending on the player's speed


If ( vel == 0 ){
    scroll_vel = 0; //to stop the background from scrolling
}

Lastly, if the player's speed varies, for example is bigger than 0 but less than 1, we need to reduce scroll_vel progresivelly. For this we are going to use the function Mathf.Lerp(initial value, final value, time interval).

If (vel > 0 && vel < 1)
{
    scroll_vel = Mathf.Lerp(0.4f, 0.2f, 0.5f); //reduces in a progressive way the value of scroll_vel
}

We need to use the Lerp function as we can't make abrupt changes to the speed in which the background is scrolling.

And that's all, with this we have our scrolling background for our Infinite Runners




-L

lunes, 25 de julio de 2016

Arreglando Bugs de Nerdy Run! | Fixing Bugs of Nerdy Run!

Español | English



Nerdy Run esta cerca de terminar! Ahora se encuentra en la etapa de probar y corregir. El último aspecto que le falta es crear la música, para la cual estoy viendo si crearla de cero o utilizar música de alguien (con licencia gratis).

Los personajes ya están hechos, los mini-juegos corregidos y funcionan. El juego esta diseñado también para que a medida que ganemos los mini-juegos, tengamos menos tiempo para correr y para resolver los próximos problemas. Por ahora no subo ninguna foto porque se están realizando los detalles para la imagen de fondo que va a tener el juego.

Decidí no incorporar Google Play Services, ya que lo utilizaba solamente para la tabla de puntuaciones y agregaba mucho peso al juego en sí, por lo que por ahora no habrá tabla de puntuaciones. Tal vez en el futuro haga una actualización y agregué esta característica.

Por lo que ahora, Nerdy les dice que esperen, ya que el juego será lanzado pronto.



-L

-------------------------------------------------------------------------------------
English




Nerdy Run is almost finished! It is now in the stage of testing-fixing. The last thing that needs to be created is the music, for which I'm asking myself if I should create it or use someone else's music (royalty-free)

The characters are made, the mini-games fixed and they work. The game is design so that when we win  the mini-games we then have less time to run and solve the next problems. I don't upload any picture now because the last details of the background image are being made.

I decided no to add Google Play Seriveces, as I would use it only for the Highscore table and it adds so much weight to the game size, so I've decided to don't add a Highscore table. In the future I may create an update for the game where I add this feature.

But for now, Nerdy tells you to wait, as the game is going to be released soon.




-L

miércoles, 6 de julio de 2016

Bienvenidos Profesores! | Welcome Professors!

Español | English


Sigo trabajando con el arte, así que hoy les traigo a los personajes secundarios que van a participar del juego. Son los personajes que aparecen cuando entramos un mini-juego. Como son 4 mini-juegos, son 4 profesores, cada uno de acorde a la "clase" (el mini-juego) que se esta jugando.


Profesor de Matemáticas


Este personaje lo había creado al principio de todo, quería que fuera cómico y que se note que es un profesor.


Profesor de Gimnasia


Para este personaje creé a un clásico estereotipo de profesor de gimnasia, vestido con ropa deportiva y con silbato.


Profesora de Química


Para crear a esta profesora necesitaba marcar el estereotipo, para eso se me ocurrió crear la bata de laboratorio y una vestimenta casual, agregué un detalle en el pelo para remarcar que es un personaje femenino.


Profesor de electrónica


Este fue el último que creé y en donde vi mi progreso con el Pixel Art, si bien es un modelo básico, es el que más fácil pude sombrear y en el cual se puede ver más detalle (como en la parte inferior izquierda del buzo). 

Todos los Sprites son de 200x200 pixels y fueron hechos en el programa Aseprite. La falta de los detalles es también debido a que, como las pantallas de celular son relativamente chicas, los detalles no se iban a apreciar demasiado. El color de los personajes es casi el mismo para todos ya que todavía no soy muy hábil utilizando la paleta indexada de 256 colores.

Falta crear un par de Assets más para tener ya listo todo el arte. Luego de eso entraría en la fase de corregir y mejorar, faltando poco para la publicación del juego!

-L


---------------------------------------------------------------

English



I'm still working on the art, so today I bring the secondary characters that will participate on the game. The characters show up when we enter a mini-game, As there are 4 mini-games, there are 4 professors, one for each class and everyone fits its class.

Math Professor


This character was created at the beginning of the game, I wanted it to be funny and make it notice that it is a professor


Gym Professor


For this character I created the classic stereotype of a gym professor, dressed with sport clothes and a whistle


Chemistry Professor


To create this professor I needed to clearly mark the stereotype, that is why I made the lab coat and casual clothe, I added the detail on the hair to stand out the fact that this is a female character


Electronic professor


This was the last one I created and where I could see my progress with Pixel Art, although it is a basic model, it was the character in which I could create shades more easily and where I could create more detail (as you can see in the button right corner of the clothes)

All the Sprites are of 200x200 pixels and where made with the program Aseprite. The lack of detail is also for the reason that the screen of mobile devices are too small, so the details wouldn't be much appreciated. The color of the characters are almost the same for everyone as I'm not very skilled using a 256 color index palette.

There are still some Assets that need to be created and I'm done with all the art. After that, the game will move to the stage of fixing and improving, not taking too long before the game is published!

-L