domingo, 2 de febrero de 2014
En1mes
http://www.en1mes.com
miércoles, 5 de agosto de 2009
Juegos para navegadores II
A pasado ya mas de un año de la ultima vez que escribi en este tema, pero he estado trabajando principalmente en diseño web y aprendido algún par de cosas interesantes de mencionar.
En primer lugar debo mencionar que asi como existen frameworks para python y ruby que son lenguajes sencillos de aprender, tambien existen frameworks para php que simplifican mucho el trabajo, yo se que antes dije que php era lenguaje un tanto criptico, pero la verdad es que es cosa de costumbres y la mayoria de los frameworks te hacen la mayor parte del trabajo.
actualmente existen muchos y cada dia salen nuevos frameworks, la mayoria de ellos inclusive son gratis y de licencias libres, en particular debo mencionar los dos que mas me gustan, estos son codeigniter, y cakephp .
Las diferencias de estos dos son enormes, el primero es muy liviano, pero no cuenta con demasiadas herramientas, sin embargo la curva de aprendizaje es casi indolora, sabiendo php aprender codeigniter es cosa de una o dos horas, el segundo cakephp es completamente lo contrario, cuenta con muchas herramientas, pero tambien tiene muchas convenciones que lo hacen dificil de seguir, sin embargo la mayor gracia de cake es un script que se llama bake, que te construye paginas crud (Create, Update & Delete) para cada una de las tablas de tu base de datos.
Existen muchos mas, pero no tengo experiencia con ellos, por ejemplo esta zend y symfony, que tambien estan muy valorados dentro del mercado.
Algunos se preguntaran que tiene que ver todo esto con juegos de video, la respuesta es que la mayoria de estos juegos de navegador consisten en insertar y recuperar valores de una base de datos, mas un par de imagenes que se muestran en el navegador, y para hacer este tipo de paginas un framework ayuda mucho, y si se espera que corra para mucha gente jugando al mismo tiempo un framework liviano es la solucion.
Pygame 1.9 esta listo
Han sacado una nueva version de pygame, la version 1.9, esta incluye varios cambios, pero los mas relevantes de mencionar son lejos soporte para webcams y soporte para midi, con esto se pueden hacer varias cosas interesantes. Otro cambios incluyen mejor soporte para OSX y soporte para el celular nokia s60
sábado, 22 de noviembre de 2008
Backtracking ( Busqueda En Profundidad )
generación de numeros y encontrar salidas de laberintos.
La tecnica consiste en recorrer todas las soluciones posibles ordenadamente,
asi si estuviesemos hablando de generar todos los numeros posibles de 4 digitos
tendriamos:
1 1 1 1
2 1 1 1
3 1 1 1
...
9 1 1 1
1 2 1 1
Ahora si estuviesemos hablando de encontrar la salida en un laberinto, lo que tendriamos que hacer es recorrer todas las habitaciones del laberinto pero en profundidad esto quiere decir, que una vez que se entra en una pieza, se busca una nueva salida que no sea por donde tu entraste y no te devuelves hasta que llegues a una habitacion sin salida
imaginemosnos el siguiente mapa
......
....xf
sxx...
donde:
s es el punto de partida
f el punto de llegada
x un muro
. un camino accesible
* un camino ya transitado
ademas dijimos que backtracking funciona generando soluciones ordenadas, de ahora
en adelante le llamaremos a esto generar nuevos candidatos, los nuevos candidatos son aquellas
posiciones que no han sido transitadas previamente.
Para este ejemplo usaremos el siguiente criterio:
primero se recorre para arriba si es posible
sino a la derecha
sino abajo
sino la izquierda.
con este criterio la salida encontrada seria:
******
*...x*
*xx...
Es importante destacar que backtracking no se preocupa de encontrar la mejor solucion, le
basta con la primera.
Recapitulando, se necesita
1) un mapa
2) un orden de movimiento ( para la generación de nuevos candidatos )
3) un criterio de llegada, normalmente que la posicion de un personaje este en cierta posicion
el pseudocodigo es el siguiente
listo = falso
backtrack(mapa, camino_recorrido, posicion_nueva)
si llegaste al final:
agregas la posicion a recorrido
listo = verdadero
retornas el camino_recorrido
si no:
agregas el nuevo punto a camino_recorrido
por cada posicion adyacentes
si es un movimiento legal y no esta en camino_recorrido
backtrack(mapa, camino_recorrido, posicion adyacente)
si esta listo retornas el camino_recorrido
Para empezar simplemte le pasas la posicion de origen.
Sabes que llegasta al final cuando tu posicion es la posicion de destino
el camino de recorrido puede ser una lista, pero cuidado tienes que copiar la lista
y no pasarlo por referencia.
martes, 8 de julio de 2008
actualizacion
miércoles, 21 de mayo de 2008
La direccion por ahora es:
http://www.alumnos.utfsm.cl/~gonzalo.sanchez/
miércoles, 14 de mayo de 2008
Aqui viene lo interesante, el codigo
import pygame
from pygame import *
from OpenGL.GL import *
class Character:
def __init__(self):
#--Position
self.posX = 0.0
self.posY = 0.0
self.posZ = 0.0
#--Movement
self.rot = 0.0
self.speed_left = 0.0
self.speed_right = 0.0
self.speed_top = 0.0
self.speed_down = 0.0
#--General
self.color = (1.0, 0.0, 0.0)
self.size = 0.2
def Update(self):
self.posX -= self.speed_left
self.posX += self.speed_right
self.posY += self.speed_top
self.posY -= self.speed_down
def Draw(self):
glBegin(GL_QUADS)
glColor3f(self.color[0], self.color[1], self.color[2])
glVertex3f(self.posX - self.size , self.posY - self.size , self.posZ)
glVertex3f(self.posX - self.size , self.posY + self.size , self.posZ)
glVertex3f(self.posX + self.size , self.posY + self.size , self.posZ)
glVertex3f(self.posX + self.size , self.posY - self.size , self.posZ)
glEnd()
def UpdateScreen ():
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
# Select GL_MODELVIEW matrix
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
character.Draw();
# Save current GL_MODELVIEW matrix state
glPushMatrix()
# Restore last GL_MODELVIEW matrix state
glPopMatrix()
# Flush everything to screen
glFlush()
# Flip the double-buffer
pygame.display.flip()
def SetUp():
pygame.init()
# we want a fullscreen, 1280x1024, SDL surface that supports doublebuffered OpenGL
pygame.display.set_mode((500,500),OPENGL|DOUBLEBUF)
# Select GL_PROJECTION matrix
glMatrixMode(GL_PROJECTION)
# Reset GL_PROJECTION matrix
glLoadIdentity()
def Main():
SetUp()
global character
character = Character()
while True:
character.Update()
UpdateScreen()
for event in pygame.event.get():
if event.type == QUIT:
return
if event.type == KEYDOWN:
if event.key == K_LEFT:
character.speed_left += 0.01
if event.key == K_RIGHT:
character.speed_right += 0.01
if event.key == K_DOWN:
character.speed_down += 0.01
if event.key == K_UP:
character.speed_top += 0.01
if event.type == KEYUP:
if event.key == K_LEFT:
character.speed_left = 0
if event.key == K_RIGHT:
character.speed_right = 0
if event.key == K_DOWN:
character.speed_down = 0
if event.key == K_UP:
character.speed_top = 0
Main()
Voy a seguir trabajando en este mismo tema, asi que cualquier comentario es bienvenido.
martes, 13 de mayo de 2008
Pygame y openGL juntos: lo mejor de 2 mundos
La clave esta en usar la siguiente linea:
pygame.display.set_mode((width,height),OPENGL|DOUBLEBUF)
de esa manera le permitimos a la ventana principal de pygame, mostrar lo que podria mostrar una ventana de OpenGL.
A continuacion el ejemplo.
#---Codigo de pygame junto con pyopengl---
#Working with pygame instead of GLUT
#Using pygame events
import pygame
from pygame import *
from OpenGL.GL import *
from OpenGL.GLU import *
def triangle():
glBegin(GL_TRIANGLES)
glColor3f(1.0,0.0,0.0)
glVertex3f(0.0,0.8,0.0)
glColor3f(0.0,1.0,0.0)
glVertex3f(-0.6,-0.2,0.0)
glColor3f(0.0,0.0,1.0)
glVertex3f(0.6,-0.2,0.0)
glEnd()
def display():
glClearColor(0.0,0.0,0.0,0.0)
glClear(GL_COLOR_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0)
triangle()
glMatrixMode(GL_MODELVIEW)
glFlush()
def windowInit(width,height):
pygame.init()
pygame.display.set_mode((width,height),OPENGL|DOUBLEBUF)
glViewport(0,0,width,height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45,1.0*width/height,0.1,100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def main():
windowInit(640,480)
while True:
display()
pygame.display.flip()
for event in pygame.event.get():
if event.type==QUIT:
return
main()
El unico problema de combinarlos es que el framerate que se obtiene, es menor que el que se obtendria ocupando directamente la ventana de Glut, o ventanas de windows/linux/otros. De todas maneras el framerate obtenido es suficiente para desarrollar un juego comercial.
domingo, 20 de abril de 2008
Como Compilar en python
from distutils.core import setup
import py2exe
setup(console=['mi_archivo.py'])
el codigo anterior lo guardas en un archivo, digamos makeExe.py, y luego lo llamas desde la consola makeExe.py py2exe, y voila se compila el codigo.
Nota: Si tu codigo depende de librerias como pygame, py2exe las compilara solo, asi que no te preocupes, con el codigo anterior basta para compilar tu codigo.
domingo, 23 de marzo de 2008
Dirty Rects
global dirty
dirty = True
def draw() :
#Aqui va el codigo de ploteo y de dibujo
global dirty
dirty = False # Como recien fue dibujado ya no esta sucio
def main():
while True
if dirty:
draw()
Es tan facil como esto, ahora como ejemplo final voy a reescribir el codigo del ploteo isometrico ocupando dirty rects
#-------Empieza Codigo-----------
#Isometric Plot
import pygame
from pygame import *
global dirty
dirty = True
TILESIZE = 64
SCREEN = pygame.display.set_mode((800, 600))
BLUE = (0, 0, 200)
GROUND_IMAGE = pygame.image.load('grass.png')
def plot():
SCREEN.fill((0, 200 , 0))
"""Aqui en el range es donde vamos a poner cuantos tiles queremos dibujar
En este caso son 15 tiles en la direccion y, y 10 tiles en la direccion x
y por lo tanto vamos a dibujar 150 tiles"""
for y in range(0, 15):
for x in range(0, 10):
"""tenemos 2 tipos de posiciones en este ploteo,
posiciones de pixeles y posiciones de tiles,
la posiciones de pixeles se incrementan de 1 en 1,
las de tile depende del ploteo que queramos,
en este caso nuestra imagen mide 64*32 pixeles,
por lo tanto cada posicion horizontal esta a 64 pixeles
de la siguiente, pero en el caso vertical,
las imagenes estan distanciadas por 32 pixeles
y dijimos que habia que moverse desde
la mitad de la imagen para abajo
o sea: imagen/4 para abajo
"""
tile_x = x * TILESIZE
tile_y = y * TILESIZE/4
if y % 2 == 0: # si estamos en una fila par(partiendo desde 0 seria la fila 0,2,4,6,8)
SCREEN.blit(GROUND_IMAGE, (tile_x, tile_y))
else:
tile_x += 32 # corregimos la posicion para las filas impares
SCREEN.blit(GROUND_IMAGE, (tile_x, tile_y))
global dirty
dirty = False
def main():
clock = pygame.time.Clock()
fps = 40
ready = False
while not(ready):
clock.tick(fps)
print clock.get_fps()
if dirty:
plot()
pygame.display.update()
events = pygame.event.get()
for event in events:
if event.type == QUIT:
return
if event.type == KEYDOWN:
ready = True
main()
#-------Termina Codigo-----------
viernes, 21 de marzo de 2008
Ploteo Isometrico
Esta imagen tiene una carecteristica muy especial, y es que es el doble de ancha que de alta, en este caso tiene 64 pixeles de ancho y 32 de alto, aunque el canvas de la imagen es de 32*32, el resto que no es visible es transparente, tambien pudimos haber ocupado un fondo blanco y usar colorkey pero no este caso preferi ocupar el canal alpha que traen los png's
Volviendo al tema interesante, el ploteo isometrico consiste en poner esta imagen u otras de las mismas caracteristicas a lo largo de la pantalla, para lograr esto debes poner sucesivamente las imagenes a lo largo del eje x, pero cuando lleguemos al final del eje y nos toque empezar a rellenar la segunda fila, la imagen la pones solo la mitad de un imagen mas abajo que la anterior, y una imagen mas a la derecha que la anterior y solo la mitad de la imagen mas abajo, despues cuando terminemos esa fila empezamos llenando el eje x desde el principio y el eje y de nuevo la mitad de la imagen en pixeles mas abajo, esta estructura se repite cuantas veces quieras.
Aqui les dejo un codigo para que puedan ver como funciona
#-------Empieza Codigo-----------
#Isometric Plot
import pygame
from pygame import *
TILESIZE = 64
SCREEN = pygame.display.set_mode((800, 600))
BLUE = (0, 0, 200)
GROUND_IMAGE = pygame.image.load('grass.png')
def plot():
SCREEN.fill((0, 200 , 0))
"""Aqui en el range es donde vamos a poner cuantos tiles queremos dibujar
En este caso son 15 tiles en la direccion y, y 10 tiles en la direccion x
y por lo tanto vamos a dibujar 150 tiles"""
for y in range(0, 15):
for x in range(0, 10):
"""tenemos 2 tipos de posiciones en este ploteo,
posiciones de pixeles y posiciones de tiles,
la posiciones de pixeles se incrementan de 1 en 1,
las de tile depende del ploteo que queramos,
en este caso nuestra imagen mide 64*32 pixeles,
por lo tanto cada posicion horizontal esta a 64 pixeles
de la siguiente, pero en el caso vertical,
las imagenes estan distanciadas por 32 pixeles
y dijimos que habia que moverse desde
la mitad de la imagen para abajo
o sea: imagen/4 para abajo
"""
tile_x = x * TILESIZE
tile_y = y * TILESIZE/4
if y % 2 == 0: # si estamos en una fila par(partiendo desde 0 seria la fila 0,2,4,6,8)
SCREEN.blit(GROUND_IMAGE, (tile_x, tile_y))
else:
tile_x += 32 # corregimos la posicion para las filas impares
SCREEN.blit(GROUND_IMAGE, (tile_x, tile_y))
def main():
clock = pygame.time.Clock()
fps = 40
ready = False
while not(ready):
clock.tick(fps)
print clock.get_fps()
plot()
pygame.display.update()
events = pygame.event.get()
for event in events:
if event.type == QUIT:
return
if event.type == KEYDOWN:
ready = True
main()
#-------Termina Codigo-----------
Hay otros tipos de ploteo y todavia nos queda mucho por hablar acerca de este.
Nos vemos.
martes, 18 de marzo de 2008
Juegos para navegadores
Para poder jugar estos juegos solo necesitas un navegador como por ejemplo IExplorer o Firefox.
Estos tipos de juegos no estan hechos en html plano, puesto que el html es un lenguaje estatico y por lo mismo no sirve para hacer juegos, puesto que no se puede actualizar la pagina mientras el usuario no presione actualizar, y tenga que cargar la pagina completamente desde cero.
Existen algunas herramientas para poder generar codigo ligeramente dinamico como por ejemplo javascript y DOM, pero para poder crear un juego donde se deba interaccionar con otras personas que estan jugando se necesita un fuente de datos (variables como por ejemplo niveles o cantidades de recursos) fija y que no dependa del cliente (la persona que esta usando el navegador). Para tener una fuente de datos fijas necesitamos una base de datos, esta puede ser un simple archivo al que el cliente envie informacion, el servidor modifique el archivo con la informacion nueva y envie el archivo a cada uno de los clientes conectados, o bien puede ser una herramienta mas sofisticada como una base de datos con un lenguaje propio de consultas como por ejemplo MySQL y Oracle, estas ultimas tienen la ventajas de poder recuperar la informacion rapidamente y con mucho menos trabajo que programarlo manualmente
Como solucion a la enorme cantidad de problemas mencionados anteriormente nacen los frameworks, estos son un conjunto de herramientas como por ejemplo una libreria para el manejo de las bases de datos, un router el cual permite redirrecionar la pagina web (y asi poder actualizar la pagina), y un template el cual permite poner codigo dinamico en nuestra pagina web
Muchos de los juegos en linea actualmente no estan hechos en frameworks sino que usan php, el cual es un lenguaje dinamico pero no muy bueno, de por si es un poco criptico y con criptico quiero decir que alguien que no sabe php no puede leer el codigo, a diferencia que casi cualquier persona que sepa programar puede leer un codigo diseñado en python, bueno volviendo al analisis de los juegos, ogame el cual a mi gusto es el mejor de los juegos de este tipo, esta hecho en php, y si mal no recuerdo travian tambien.
Si te interesa programar este tipo de juegos existe una alternativa bastante buena al php y son los frameworks, existen principalmente tres frameworks para python y son django, pylons y turbogears.
Yo hasta el momento solo he trabajdo con los dos primeros, con django y con pylons, y comparandolos diria que django es mas facil de aprender, pero es mejor pylons, si quieren diseñar un juego sencillo o una pagina estilo fotolog o myspace o youtube con django podrian hacerlo perfectamente, aunque yo personalmente me inclino por pylons que permite mucha mayor configuracion.
Lamentablemente toda la buena documentacion de estos frameworks esta en ingles.
Bueno si todavia estan interesados, les recomendaria The Django Book como punto de partida.
Buena Suerte.
lunes, 3 de marzo de 2008
Cargar imagenes con pygame
superficie1 = image.load("nombre_imagen")
#---cargando imagenesDe esta manera el programa avisara que hubo un fallo a la hora de intentar abrir el archivo
import pygame
from sys import exit
def loadImage(filename):
try:
image = pygame.image.load(filename)
except:
print "error al cargar la imagen desde ", filename
sys.exit()
return image
#-----
Transparencia en pygame
Transparencia alfa (alpha) :
Se aplica a toda la imagen, es un valor que va desde 0 a 255 donde 0 es opaco y 255 es transparente, se puede hacer una imagen borrosa dandole valores intermedios
Tranparencia colorkey :
Se aplica solo a un color de la imagen y hace ese color invisible.
Advertencia: la transparencia alpha suele ser bastante lenta.
viernes, 29 de febrero de 2008
Deteccion de colisiones 3d
Asi que no queda otra que empezar a leer.
Suerte con sus juegos 3D.
jueves, 28 de febrero de 2008
Variables locales y variables globales
Supongamos la siguiente situacion:
#---Caso 1
a = 5
print a
def funcion():
print a
function()
#fin codigo
En este primer caso como la variable a esta definida fuera de la funcion es visible dentro de la funcion, pero en el caso contrario no sucede lo mismo, para eso veamos el siguiente ejemplo
#---Caso 2
def otra_funcion():
b = 5
otra_funcion()
print b
#fin codigo
Solucion al caso 2:
#---Solucion al caso 2
def solucion():
global b
b = 6
solucion()
print b
#fin codigo
A modo de advertencia dejo claro que las variables globales quedan tapadas por las locales, pero este comentario probablemente no sea muy clara asi que pongamoslo un ejemplo de esto
#---codigo
a = 5
def funcion():
a = 7
funcion()
print a
La pregunta que deberias estar haciendote es: ¿que imprime?.
La respuesta es 5, y la razon es porque cuando definimos la variable a en la funcion tapamos la definida anteriormente, hay que tener cuidado con esto, este tipo de errores son muy dificiles de rastrear.
La explicacion de porque esto sucede es dificil explicarla sin dibujitos pera la idea es la siguiente, el programa principal imaginalo como un bloque que en la parte superior tiene escrita informacion, ahora cuando en el programa llama a una funcion
se pone otro bloque pero de menor tamaño, que tapa la mayor parte de lo que estaba en el bloque anterior excepto aquellas cosas que fueron escritas en la periferia, de esta manera se va construyendo una especie de piramide que realmente es mas parecida a una columna que recibe como nombre tecnico pila (stock). Espero que entienda que esto es una metafora y no es del todo correcto.
Para completar me gustaria comentarles que en python se puede conocer cuales son las variables locales que actualmente estan en uso, para acceder a ellas se usa la funcion locals(), esta devuelve un diccionario con todas las variables locales, de la misma forma es posible conocer que variables globales estan en uso a traves de la funcion globals().
domingo, 24 de febrero de 2008
Recursividad
ej:
def funcion_hola():
funcion_hola()
Bueno, y esto para que sirve?.
El limite de la recursividad:
Factorial:
-El factorial de un numero N, natural (o sea un entero > 0) se anota como N!
y esta definido asi:
N! = (N - 1)!
En base a estas 2 definiciones podemos programar una funcion recursiva que calcule el factorial de un numero
#---codigo
def recursive_factorial( n ):
if n == 0:
return 1
else:
return n * recursive_factorial( n - 1 )
#---fin codigo
jueves, 21 de febrero de 2008
Crear un triangulo con pyopengl
#Codigo ---------
from OpenGL.GL import *
from OpenGL.GLUT import *
def draw_triangle():
glBegin(GL_TRIANGLES)
glVertex3f(0.0, 0.6, 0.0)
glVertex3f(0.6, -0.6, 0.0)
glVertex3f(-0.6, -0.6, 0.0)
glEnd()
def display():
glClear(GL_COLOR_BUFFER_BIT) # Pinta la pantalla de color negro
draw_triangle()
glFlush()
glutInitWindowSize(800, 600)
glutCreateWindow("HELLO WORLD")
glutDisplayFunc(display)
glutMainLoop()
#------------
Crear una ventana con pyopengl
from OpenGL.GL import *
from OpenGL.GLUT import *
def display():
glClear(GL_COLOR_BUFFER_BIT) # Pinta la pantalla de color negro
glutInitWindowSize(800, 600)
glutCreateWindow("HELLO WORLD")
glutDisplayFunc(display)
glutMainLoop()
las primeras 2 lineas importan las funciones de la libreria.
glutInitWindowSize(800, 600): crea una ventana de ancho 800 pixeles y alto 600 pixeles
glutCreateWindow("HELLO WORLD"): crea la ventana con titulo HELLO WORLD
glutDisplayFunc(display): llama a la funcion display mientras corre el bucle principal de glut
glutMainLoop(): llama a correr el bucle principal de openGL.
Para correr el codigo en windows necesitas el dll de glut, el cual se llama glut32.dll
martes, 19 de febrero de 2008
Usando el mouse en pygame
Primero: Para poder hacerlo visible o invisible el cursor del mouse:
pygame.mouse.set_visible(bool)
bool puede ser True o False segun se desee hacer visible o invisible el cursor
Segundo: para poder saber en que posicion de la pantalla esta el cursor utilizamos:
pygame.mouse.get_pos()
esta funcion devuelve un par de datos con las coordenadas x,y del cursor, por lo tanto la deberiamos llamar asi:
mouse_pos = pygame.mouse.get_pos()
o tambien:
mouse_pos_x, mouse_pos_y = pygame.mouse.get_pos()
Estos nombres son arbitrarios, los puedes cambiar, lo que debes saber es que: pygame.mouse.get_pos() te devuelve una tupla con las posiciones del mouse.
Tercero: Para saber si se esta presionando algun boton del mouse:
pygame.mouse.get_pressed()
devuelve un tupla de tres valores, que son los tres botones del mouse, los valores se encuentran en el mismo orden que los botones del mouse, o sea el valor de mas a la izquierda es el boton izquierdo del mouse y asi sucesivamente, si el boton se encuentra presionado, el valor es 1, en caso contrario es 0.
Resumiendo con codigo:
botones_mouse = pygame.mouse.get_pressed()
if botones_mouse[0] == 1: # o sea
print "hola"
Cuarto: tambien queremos poder saber si con el mouse estamos o no haciendo click sobre algo, para esto hay varias formas, una de ellas es aprovechar el rect de lo que estamos clickeando, eso seria mas o menos asi:
mouse_x, mouse_y = pygame.mouse.get_pos()
for objeto in objetos_del_juego:
if objeto.collidepoint(mouse_x, mouse_y):
print "algo"
una segunda opcion es construir un rect con la posicion del mouse, dandole un ancho y alto
y utilizando ese rect para detectar colisiones como explique en un post anterior
Para los que se entusiasmaron, buena suerte programando su primer RTS.