martes, 14 de junio de 2016

Como crear trayectoria Senoidal para un objecto por Código | How to create a Sinusoidal trajectory to an object by Script

Español | English

Muchas escuchamos o hicimos la pregunta a nuestro/a profesor/a de matemáticas: "¿Voy a usar esto en el futuro?" y tal vez el o ella no sabía que responder, seguro les contestaba que dependía de la carrera que el alumno o la alumna fuera a seguir.

Para el desarrollo de Videojuegos se utiliza toda herramienta posible de las matemáticas, ya que nos pueden servir para resolver los casos que se nos planteen. Por eso es importante tener un amplio conocimiento de las ciencias exactas para tener más herramientas disponibles.

La situación de la cual partimos se genera a partir de un objeto que se mueve en línea recta a velocidad constante. Este objeto es uno de los encargados de instanciar (Spawnear) otros objetos, que el jugador va a recolectar.

Ya había hablado antes de que el Spawner instancia objetos en intervalos aleatorios de tiempo, pero siempre en linea recta. Por lo que nos podemos quedar quietos en una misma posición y siempre agarrar objetos.

Una solución a este problema es cambiar la posición vertical ("altura") del Spawner constantemente, para que genere objetos a distintas "alturas" y así, cubrir más superficie del mapa. Al moverse verticalmente de arriba hacia abajo y con velocidad constante, podemos ver que la trayectoria del Spawner va a crear una forma senoidal.

Para eso primero creamos las variables que van a actuar:

float distancia = 0.13f;
public float h = 0;
public float hmax = 0;
public float hmin = 0;
public bool up = true;

Donde h representa la altura del objeto, se actualiza constantemente, hmax y hmin representan la altura máxima y mínima que puede tomar ese objeto, y por último, "up" determina si tiene que subir o no.

Las variables hmax y hmin tienen que estar asignadas en la función Start() del Script, ya que no deberían cambiar.

void Start(){
hmax = 30f;
hmin = 1f;

}

Ahora vamos a focalizarnos en la función Update(). Primero, vamos a asignarle a la variable h el valor de la posición vertical del Spawner, luego vamos a indicarle si debe subir o bajar.

h = this.GetComponent<Transform>().position.y;

Nota: Se asume que el Script esta añadido al objeto, de no ser así, se debería crear una variable pública de tipo Transform a la cual le pondremos los valores del objeto.

if (up == true)
        {
          this.gameObject.GetComponent<Transform>().position += new Vector3(0, distancia, 0);
        if (h >= hmax)
        {
            up = false;
        }
        }
        if (up == false)
        {
           this.gameObject.GetComponent<Transform>().position -= new Vector3(0, distancia, 0);
        }
        if(h <= hmin)
        {
            up = true;
        }

Aquí esta la lógica del movimiento. Se basa en analizar si el objeto tiene que subir o bajar, en caso de que tenga que subir, se actualiza constantemente su posición vertical hasta que alcanzó el límite, luego, se le indica que debe bajar y de nuevo se modifica la posición vertical. Esto se lleva a cabo infinitas veces.

Se puede, como complemento, ajustar la velocidad a la que se desplaza o agrandar el intervalo.Y así queda creada la mecánica para hacer que un objeto recorra una trayectoria senoidal.


-L

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

English

Many times we have heard someone ask (or did it ourselves) to the teacher: "Am I going to use this in the future?" and maybe the teacher didn't know what to answer, they surely said that it depended on what the student was going to do when he or she grow up.

For Game development, we use every available tool from math, as they can be useful to solve cases that may appear. That is why we need to have a wide range of knowdledge from the exact sciences to have as many tools as possible.

Our starting situation is generated by and object that moves in straight line with constant speed. This object is one of many who instantiates (Spawns) the objects that the player will collect.

I've spoken before about the Spawner, saying that it instantiates in random periods of time, but always in straight line. So we can stand still in a fixed position and alwats grab objects.

A solution to this problem is to change the vertical position ("height") of the Spawner constantly, so that it generates the objects in different "heights", which will cover more surface of the map. As the object moves up and down and it is also moving at a constant speed horizontally, we can see that this creates a sinewave trajectory.

To do this we first need to create the variables that will act:

float distancia = 0.13f;
public float h = 0;
public float hmax = 0;
public float hmin = 0;
public bool up = true;

Where h represents the height of the object, which is constantly being updated, hmax and hmin represent the maximum and minimum height that the object can have, finally, "up" determines whether  the object has to go up or not.

The variables hmax and hmin have to be assign in the Start() function of the Script, as they are not meant to be modified.


void Start(){
hmax = 30f;
hmin = 1f;
}

Now we are going to focus on the Update() function. First of all, we need to assign the vertical position of the object to the variable h, then we are going to indicate if it needs to go up or down.

h = this.GetComponent<Transform>().position.y;

Note: I assume that the Script is attached to the gameObject, if this is not the case, a public variable of the type Transform needs to be created and later on, it has to be assign to an object.

if (up == true)
        {
          this.gameObject.GetComponent<Transform>().position += new Vector3(0, distancia, 0);
        if (h >= hmax)
        {
            up = false;
        }
        }
        if (up == false)
        {
           this.gameObject.GetComponent<Transform>().position -= new Vector3(0, distancia, 0);
        }
        if(h <= hmin)
        {
            up = true;
        }

Here it is the logic of the movement. It is based on analyzing whether the object has to go up or down, in case it has to go up, its vertical position is being constantly updated until the limit is reached, then, it indicates the object that it has to go down and it modifies the vertical position again. This is performed infinite times.

As a complement, one can also adjust the speed on which it moves or make the periods longer. And so it is created the mechanic that make an object travel a sinusoidal trajectory.

-L

lunes, 13 de junio de 2016

Como crear un botón de pausa | How to create a pause button

Español | English

Los botones de pausa son fundamentales para los videojuegos, son una herramienta que no puede faltar en cualquier juego sin importar en que medio se este jugando. Por eso hoy voy a crear un simple tutorial para crear un botón de pausa en Unity.

Si bien yo creo que cada juego debería ser analizado individualmente dependiendo de sus características, lo que principalmente buscamos es crear un estado en donde toda actividad se detiene. Lo que más en detalle vamos a hacer sería detener el tiempo, ya que muchas funciones dependen de el para funcionar.

Como no todas las mecánicas del juego dependen del tiempo (como el desplazamiento de un objeto que recibe un Input como el teclado), estas van a seguir activas mientras el tiempo este detenido, de ahí que digo que cada juego puede utilizar mecánicas especiales y por eso debe ser pensado distinto.

Primero en principal debemos crear un botón de GUI: 


Ahora creamos el Script (o usamos uno ya existente) en donde vamos a poner una función publica para que el botón pueda acceder

public void Pause (){
If(Time.timeScale == 1)
        {
            Time.timeScale = 0;
            velocidad = 0;
            is_pause = true;
        }
        else
        {
            Time.timeScale = 1;
            velocidad = 0.13f;
            is_pause = false;
        }
}

Acá podemos ver que la propiedad importante a usar es Time.timeScale, que lo que hace es modificar la escala del tiempo del juego, si la escala está en 0, el juego esta detenido, si esta en 0.25, el juego va a estar "en cámara lenta", una propiedad de la que se puede aprovechar.

Di un ejemplo de como sería si por ejemplo en mi juego hay un objeto a velocidad constante. Al poner pausa, como lo que hace mover al objeto no es la velocidad sino un cambio en el espacio, no es afectado por el tiempo, por eso tengo que "frenarlo" manualmente. Así también podemos poner unos flags que indiquen si el juego esta pausado o no.

Finalmente, queda asignarle la función al botón, para eso vamos a ir a la sección de "OnClick()" que esta en el inspector cuando seleccionamos un botón


Haciendo click en el más, le asigamos una función al botón, falta decirle que función, para eso vamos a:
  1. Agregar el Script al objeto
  2. Arrastrar el botón desde el inspector hasta esta propiedad "OnClick()" del botón
De ahí que podemos, desde una lista de elementos desplegables, elegir nuestro Script y luego, nuestra función. Aviso: El hecho de primero agregar el Script al botón puede ser innecesario en algunos casos. Yo lo hago por si quiero que varios botones tengan la misma función pero que, al accionarla, funcione solo para un botón y no para todos.

Para los que querrían que su personaje no se pueda desplazar, les recomiendo usar las Constraints del Rigidbody

Primero declaramos una variable publica (por si no lo hicimos antes) del RigidBody (en mi caso, 2D):

public Rigidbody2D rb;

y luego les asignamos el bloqueo de posición en el eje Y y Z.


rb.constraints = RigidbodyConstraints2D.FreezePositionX;
rb.constraints = RigidbodyConstraints2D.FreezePositionY;

para luego desbloquear esto, simplemente ponemos:

 rb.constraints = RigidbodyConstraints2D.none;

Y así queda creado un simple botón de pausa.

-L



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

English
 
Buttons are fundamental for video-games, they are a tool that can't be absent in any game regardless the media on which the game is played. That is why today I'm creating a simple tutorial to teach how to create a pause button in Unity.

Although I think each game needs to be analyzed separately depending on its features, what we are mainly looking for is to create a state where every activity is stopped. Going into the details, we are going to stop time, as many functions depend on the time to work.

As there are some mechanics that don't depend on time (such as the displacement of an object which recieves an Input like a keyboard), this are going to be active whether the time is "on" or "off", that is why I mentioned earlier that there could be games that use special mechanics and that is why they need to be thought different.

First of all we need to create a GUI Button:



Now we create the Script (or we use one that we had before) on where are going to write a public function that the button can access.

public void Pause (){
If(Time.timeScale == 1)
        {
            Time.timeScale = 0;
            velocidad = 0;
            is_pause = true;
        }
        else
        {
            Time.timeScale = 1;
            velocidad = 0.13f;
            is_pause = false;
        }
}

Here we can see that the important property to use is Time.timeScale, that modifies the time scale of the game, if the scale is on 0, the game is stopped, if it is on 0.25, the game will be in "slow motion", a property which can be given different uses.

I also did an example of how it would be the case where I have an object that moves at constant speed. When I pause the game, the object will keep moving as the movement doesn't uses the time but the space, that is why I need to "stop" it manually. In the same way, we can create flags to indicate whether the game is paused or not.

Finally, we need to assign the function to the button. To do that we are going to go to the "OnClick()" section which is in the inspector when we select a botton.


Clicking on the plus we assign a function to the button, now we have to say which function, for that we:

  1. Add the Script to the object
  2. Grab and drag the button from the inspector to the "OnClick()" property of the button
From there we can, from a drop down list, select our Script and then, our function. Note: The step of adding the Script first to the object is not necessary in some cases. I use it in case I have several buttons using the same function and I want each one of them to work separately when I activate the function.

For those who would like their character not to move when it is on pause, I recommend to use Rigidbody's Constraints

First we declare a public variable (in case we didn't do it before) of the Rigidbody (in my case, 2D):

public Rigidbody2D rb;

Then we add the block to the X and Y axis:


rb.constraints = RigidbodyConstraints2D.FreezePositionX;
rb.constraints = RigidbodyConstraints2D.FreezePositionY;


Later, to unblock the axis we need to use:

 rb.constraints = RigidbodyConstraints2D.none;

And that is how we create a simple pause button

-L

domingo, 12 de junio de 2016

Falta poco! | Almost there!

Español | English


De a poco seguimos avanzando. Ya casi termino con la programación, las lógicas están hechas, los mini-juegos creados y las dificultades creadas.

Mi mayor complicación ahora, como mencioné antes, es crear el arte del juego. Lo que dejé para el final son los personajes que van a aparecer (tanto el principal como los secundarios), como el mapa mismo del juego. Lo bueno es que no necesito modificar mucho, ya que simplemente les agrego las imágenes correspondientes a los objetos que tenía antes.

Las últimas modificaciones que se hicieron fueron:
  • Solucionar problemas de colisión entre los objetos que agarramos.
  • Creé el botón de pausa.
  • Se modificó el juego para que se complique a medida que avanzamos
  • Se agregaron textos al agarrar cosas.
De el último elemento de la lista voy a dedicarme más en detalle a futuro, ya que no se podía hacer de forma directa sino que había que modificar algunas cosas. Más adelante también voy a hacer tutoriales sobre como hacer las cosas que hice.

Esto les dejo por ahora sigan al tanto que no falta mucho para que el juego este en la Play Store.

-L

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

English


Little by little we keep moving forward. I'm almost done with all the programming, the logics are made, the mini-games are created and the difficulties made.

My biggest problem right now, as I mentioned before, is the art of the game. What I left for the end was the characters (both the main characters and the secondary characters), as the main map of the game. The good thing is that I don't need to modify much, as I simply add the images I create to the corresponding objects that I had before.

The last modifications I did were:

  • Solve  problems with the collision between the objects we collect.
  • I created the pause botton.
  • I modified the game so that it is harder as we move forward.
  • I added texts that show up when we grab objects.
I'll dedicate more detail in the future to the last item of the list, as it can't be done directly because some configurations need to be made. In the future I'll also make tutorials telling how I did those things.

I leave you with this by now, keep up with the blog as it won't be long before the game is on Play Store.

-L

sábado, 14 de mayo de 2016

Progresando con el arte! | Making progress with the art!

Español | English


Para hoy les traigo todo lo que pude avanzar con respecto al arte para el videojuego, hice una calculadora, un cubo Rubik y un compás, que van a ser todos objetos que podemos agarrar. Cada Sprite es de tamaño 128x128 indexado y fueron hechos con Aseprite. Las imágenes tienen una marca de agua, en el caso de que alguien quiera utilizarlas, puede contactarse conmigo para que le envíe las versiones originales.


La calculadora en mi opinión es la imagen que mejor me salió de las 4 en total
Para el compás tarde un poco más de lo esperado ya que no me decidía entre hacer las sombras más notables o no marcarlas tanto.


El cubo fue el más fácil de todos ya que en lo que tuve que tener cuidado únicamente era en crear las líneas rectas y paralelas para que todos los cuadrados sean iguales.

No merece dedicarle demasiado detalle a cada objeto porque se va a perder, ya que como es un juego para móviles, los detalles van a ser tan pequeños que no se van a notar. Además de tener en cuenta que el juego en sí es de movimiento continuo, lo que lleva a que el jugador no pueda quedarse a admirar el detalle de los objetos. Por lo que lo importante más que nada son los grandes rasgos.

Me quedan por hacer 3 objetos que el personaje puede agarrar y lo demás son personajes, el mapa, los menúes y los mini-juegos. 

-L

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


Today I bring you all the art I did for the video-game, I made a calculator, a Rubik's cube and a mathematical compass, which are all going to be objects which we can grab. Each Sprite is 128x128 indexed and where made using Aseprite. The images have a watermark, in case someone want to use any image, he/she can contact me so I can send him/her the original version.

This calculator in my opinion is the best one I made of the 4 I draw.

For the compass I spend a little bit more of time than I expected because I couldn't decide whether I want with the shadows more notable or more smooth.


The cube was the easiest one, the only thing I needed to take care of where to make the lines straight and parallel so the cubes have the same size.

It isn't worth to take care too much worry with the details as they are going to be lost, as it is a mobile game, the details will be so small they are going to be hard to see. Also, keeping in mind the game keeps the player in continuous movement, this takes away the chance for the player to be still looking the details of the objects. So that really matters are the main features of each object.

I only have left 3 objects which the player can grab, the characters, the map, the menus and the mini-games.

-L

miércoles, 11 de mayo de 2016

Volviendo después de un largo tiempo | Coming back after a long while

Español | English

He vuelto! Primero que nada perdón por dejar olvidado a este blog, por tema de exámenes de la facultad tuve que dejar el proyecto a un lado pero ahora que ya pasaron puedo volver al trabajo!

Retomando donde había dejado antes, faltaba terminar algunos aspectos de programación, en particular con los mini-juegos. Ya he arreglado eso y muchos problemas más que había, por lo que la transición entre los mini-juegos y el juego principal esta completa.

Por otro lado, creé el sistema de puntuación. Simplemente se incrementa si ganamos un mini-juego o si agarramos ciertos objetos especiales "buenos" y  en caso de agarrar objetos "malos", perdemos puntos. Al ganar un mini-juego, tenemos un bonus de 250 puntos.

Un cambio técnico importante: Cambié la forma en la que trabaja el cronómetro, la cuestión era simple de ver, el reloj funcionaba en función del tiempo. Por otra parte, al entrar a un mini-juego, este reloj se detenía y si lo ganábamos, el reloj debía empezar de nuevo, por lo que debía pedirle que empiece de nuevo, esto traía conflicto porque el reloj lo restaba la propiedad Time.time, que incrementa a medida que el juego avanza, de esta manera, tuve que buscar otra manera que me permite "resetear" el reloj cuando quiera.

Quitando otros aspectos técnicos de los cuales hablaré más adelante, puedo afirmar que faltan solo unos pocos aspectos para poder terminar con toda la programación del juego, por lo que ya empecé a realizar el arte (del cual voy a publicar mis avances). Hasta ahora pude trabajar solamente en uno de los objetos que podremos agarrar mientras corremos:

La resolución es pequeña ya que intento de ahorrar la mayor cantidad de espacio posible para que el peso final del apk no sea tan elevado. Si bien debo retocar detalles de cada dibujo que vaya haciendo, sirven para más que nada tener ya casi armado el juego en general, al cual luego se le van a pulir todos los detalles.

-L


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

English


I'm back! First of all I have to say that I'm sorry for keeping this blog outdated, due to exams of the university I had to put aside the project for a while, but now I'm back on business!

Taking up from where I've left, I needed to finish a few aspects of programming, the mini-games on particular. I've fix that and many problems, so the transition between the mini-games and the main game is complete.

On the other hand, I created score system. It simply increments if we won a mini-game or if we grab certain "good" objects and in if we grab "bad" obects we lose points. When the player wins a mini-game, he/she has a bonus of 250 points.

A big technical upgrade: I've changed the way the chronometer works, the thing was easy to see, the clock worked based on time. On the other hand, when the player enters a mini-game, this clocks stops and if we win it, the clock needs to start again, for which I had to ask the clock to restart, but this caused conflict because the clock worked by the property "Time.time", which increments as the game goes forward, so I had to look for another way that could make me able to restart the clock whenever I want.

Keeping apart other technical aspects which I'll talk about them in the future, I can confirm that there are only few aspects left to finally finish with all the programming of the game, so I've started with the art (which I'll post my progress). For now I could only work on one of the objects that can be grabbed while we run:


The resolution is low because I'm trying to save as many space as I can so the final size of the apk isn't too big. Although I need to work on the details on each drawing I'll be making, they also work so I can put every piece together and then work on every detail in general.

-L