Como hacer un SNAKE

Pues eso .. un SNAKE básico de toda la vida, el de la serpiente que come manzanas :)



Podéis bajaros el ejecutable aquí <download>

ARCHIVOS

Pues al bajaros el ZIP y volcarlo a una carpeta veréis

nlkEngine.exe -> el ejecutable windows del NLKEngine
command.ini -> un archivito que le permite saber como queremos arrancar el motor
config.pi -> el archivo que configura el motor, resolución, etc.
main.pi -> el script de arranque y el que tendrá la base lógica de nuestro "juego"
snake.pi -> cada pieza de la serpiente, incluyendo la cabezota.

COMMAND.INI

En este archivo le decimos al motor que queremos arrancar en modo debug y que arranque el "main.pi" desde un comienzo. Realmente, si no se pone esto, es lo que asume por defecto, pero bueno, para que la gente vea como se pueden arrancar desde el inicio otros scripts que no sean el "main".

-debug -run main.pi

CONFIG.PI

Archivo de configuración. Puede existir o no, pero si no existe se asumen parámetros de configuración por defecto. Siempre es bueno tener un "config" y al menos configurar las resoluciones y poco más. Un titulillo para la ventanita y poco más.

class SERVICE 
{
   defines:
RESX = 512;
RESY = 512;

function Init() 
{
System_SetParam(SP_TITLE, "SUPER SNAKE");

System_SetParam(SP_RESX, RESX);
System_SetParam(SP_RESY, RESY);

System_SetParam(SP_INRESX, RESX);
System_SetParam(SP_INRESY, RESY);

System_SetParam(SP_BPP, 32);

System_SetParam(SP_CURSOR, false);
}
}

MAIN.PI

Aquí lo que hacemos es simplemente iniciar la cabeza de la serpiente (nuestro player particular) y gestionar la aparición de la manzana (cuadradote amarillo). El "main" es un SERVICE. Y los servicios tienen su propia forma de funcionar. Cuando se crean se ejecuta su función INIT. Cuando arrancan se ejecuta su función START. En cada frame se ejecuta su función MOVE y su DRAW a la hora de dibujar. Cuando paran ejecutan su función STOP y cuando se destruyen su función FINAL. Las funciones no es obligatorio tener que definirlas si no se van a usar.

class Service
{
constants:
APPLE_SIZE = 15;

properties:
head = null;
tail = null;
apple_x = 0;
apple_y = 0;

function Init ()
{
head = Service_Run ("head", "snake", ["x", 20, "y", 20]);
tail = head;
}

function Start ()
{
GenerateApple ();
}

function GenerateApple ()
{
apple_x = Rand(0, RESX-APPLE_SIZE);
apple_y = Rand(0, RESY-APPLE_SIZE);
}

function Move ()
{
_ret = IntersectRectWithRect (head.x-head.SIZE/2, head.y-head.SIZE/2, head.SIZE, head.SIZE, apple_x, apple_y, APPLE_SIZE, APPLE_SIZE);
if (_ret[0])
{
tail = Service_Run ("tail", "snake", ["head", tail]);
GenerateApple ();
}


function Draw ()
{
Render_DrawBox (apple_x, apple_y, APPLE_SIZE, APPLE_SIZE, ARGB(255,255,255,0));
}
}

SNAKE.PI

Nuestra serpiente. Que diferencia claramente el funcionamiento de la CABEZA (head) del resto de piezas (tails). La cabeza es la que mirará si pulsamos los cursores para ir tomando las distintas direcciones. Las colas lo que harán será seguir a su cabeza. Es una cuestión de transmisión de movimiento.
El "GetFTime" es una función que nos da el factor de tiempo a tener en cuenta para que los incrementos vayan siempre a la misma velocidad (dependiendo del framerate) en todas las máquinas.
El "IncreaseValue" lo que hace es una interpolación lineal entre un valor A hasta un valor B según una velocidad.

class Service
{
    constants:
SIZE = 10;
SPEED = 5.0f;

properties:
x = 0;
y = 0;
tail = null;
head = null;
dirX = 0;
dirY = 0;

function Init ()
{
if (head)
{
head.tail = this;
x = (head.x - head.dirX * SIZE);
y = (head.y - head.dirY * SIZE);
}
else
{
dirX = 1;
dirY = 0;
}
}

function Move ()
{
if (head == null)
{
if (Input_IsKeyPressed (KEY_RIGHT))
{
dirX = 1;
dirY = 0;
}
else if (Input_IsKeyPressed (KEY_LEFT))
{
dirX = -1;
dirY = 0;
}
else if (Input_IsKeyPressed (KEY_UP))
{
dirY = -1;
dirX = 0;
}
else if (Input_IsKeyPressed (KEY_DOWN))
{
dirY = 1;
dirX = 0;
}

x += dirX * GetFTime() * SPEED;
y += dirY * GetFTime() * SPEED;
}
else
{
_toX = (head.x - head.dirX * SIZE);
_toY = (head.y - head.dirY * SIZE);

if (x < _toX) dirX = 1;
else if (x > _toX) dirX = -1;
else dirX = 0;
if (y < _toY) dirY = 1;
else if (y > _toY) dirY = -1;
else dirY = 0;

x = IncreaseValue (x, _toX, GetFTime() * SPEED);
y = IncreaseValue (y, _toY, GetFTime() * SPEED);
}
}

function Draw ()
{
Render_DrawBox (x-SIZE/2, y-SIZE/2, SIZE, SIZE, ARGB(255,255,255,255));
}
}


No hay comentarios:

Publicar un comentario