Anda di halaman 1dari 44

Capítulo 1 - El componente Timage

El presente curso está bajado de www.gdsweb.com.ar el portal de


programación de VideoJuegos.

Capítulo 1 - El componente Timage

En este primer capítulo vamos a aprender a trabajar con el componente


Timage. Cubriremos las diversas características de Timage y cómo
pueden ser usadas. Debajo puede verse un diagrama que muestra las
propiedades que definen el alto y ancho de la Imagen, así como la
posición que ocupa dentro del formulario.

Como pueden ver, Imagen.Left e Imagen.Top son las coordenadas x e y


respectivamente, mientras que width y height son el ancho y alto,
Imagen.Left e Imagen.Top indican a cuantos pixels se encuentra del
borde superior izquierdo del Área del Cliente (form1).

Propiedades de Timage
AutoSize

Las propiedades Imagen.Height e Imagen.Width son necesarias


solamente si AutoSize está en false. AutoSize puede ser muy útil si
planea cambiar el tamaño de una Imagen durante el juego, ya que no
necesita indicar de nuevo el alto y ancho de la Imagen. Existiendo
AutoSize por qué querría yo utilizar la forma manual?. Bueno, a veces

http://programacion-de-juegos.gdsweb.com.ar/ (1 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

poniendo AutoSize en true, se reduce la velocidad de ejecución del


programa, por ello puede ser más útil colocar AutoSize en true y luego
nuevamente en false cuando ya las propiedades queden fijas.

Transparent

Esta propiedad debe ponerse a true casi siempre, para que los
gráficos de fondo no queden ocultos detrás del borde de la Imagen
(Componente Timage).

Debe asegurarse que tiene un color transparente configurado en


su imagen. En general si está creando imágenes en programas como
Paint, el color transparente es blanco, pero puede cambiarse fácilmente.

Visible

Cuando se coloca en falso el objeto es invisible. Se utilizará en


capítulos subsiguientes para ocultar imágenes hasta que sea necesario
utilizarlas. El siguiente código vuelve visible al personaje cuando se lo
utiliza.

ImgPersonaje.Visible := true;

Stretch

Básicamente lo que hace es ajustar la imagen al ancho y alto


indicado por imagen.width e imagen.height. Tengan cuidado porque la
imagen puede verse muy mal si es deformada. Ahora, si desean que sus
personajes se puedan agrandar durante el juego, este es el comando a
usar; para esto es necesario que la propiedad AutoSize esté en false.

http://programacion-de-juegos.gdsweb.com.ar/ (2 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Como verán más adelante nos será util conocer el alto y ancho de
una imagen a medida que nos acercamos al borde de la pantalla para no
salirnos de la misma. Esto se verá más desarrollado en el capítulo 3, por
lo que no profundizaremos por el momento.

Todas estas propiedades se pueden modificar en tiempo de ejecución,


convendría que las practiquen antes de continuar.

Capítulo 2 - Moviendo una imagen por la pantalla

Para realizar un juego lo primero que necesitamos es poder mover un


personaje por la pantalla. Utilizaremos botones para dirigir el movimiento
de nuestro sprite (personaje).

Práctica 1:

Comenzar una nueva aplicación. Agregar 4 botones (están en la paleta


standard) y un componente Timage (de la paleta Additional). Modifiquen
los Captions de cada botón para indicar las cuatro direcciones, Si
queremos ser más prolijos sería ideal darles nombres como
BtnIzquierda, BtnDerecha, etc. a cada botón, de aquí en adelante
asumimos que utilizan los nombres sugeridos.

También podemos cambiar el nombre de la imagen a ImgPersonaje. Para


realizar los personajes pueden utilizar el editor de imágen que viene con
Delphi. Seleccionen una imagen para nuestro Timage, ahora pongan la
propiedad AutoSize de la imagen en true para que el borde se ajuste a la
imagen, al terminar deben tener algo similar a lo siguiente.

Ya estamos listos para realizar algo de programación. El componente


Timage tiene 2 propiedades, Top y Left, que indican las coordenadas
donde se colocará la imagen. En tiempo de ejecución modificaremos
http://programacion-de-juegos.gdsweb.com.ar/ (3 of 44) [05/04/2004 19:47:24]
Capítulo 1 - El componente Timage

estas propiedades para que nuestro personaje se mueva por la pantalla.

Ir hacia la Izquierda

Lo primero es darle doble click al botón izquierdo para crear el proceso


BtnIzquierdaClick, entre begin y end escribir lo siguiente.

ImgPersonaje.Left := ImgPersonaje.Left – 10;

Este renglón le dice al programa que se mueva 10 pixels a la izquierda,


restándole 10 a la propiedad left de la imagen.

Ir hacia Arriba

Haremos lo mismo para el botón subir, dele doble click al botón subir para
crear el procedimiento BtnSubirClick. Escriba lo siguiente.

ImgPersonaje.Top := ImgPersonaje.Top –10;

En los otros dos casos es muy similar.

Ir hacia la Derecha
ImgPersonaje.Left := ImgPersonaje.Left +10;

Ir hacia Abajo
ImgPersonaje.Top := ImgPersonaje.Top +10;

Con esto finalizamos esta práctica y el presente capítulo, prueben el


código y practiquen moviendo su personaje por la pantalla. Notarán que
existe un problema : nuestro personaje se nos pierde de vista al cruzar
los bordes del formulario.

Capítulo 3

http://programacion-de-juegos.gdsweb.com.ar/ (4 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Impidiendo que la Imagen se salga de los márgenes del formulario.

Para controlar el movimiento de nuestro personaje evitando que se salga


del formulario será necesario agregar algunas líneas a cada botón.

BtnIzquierdaClick

Las líneas que deberemos agregar aparecen en cursiva.

procedure Tform1.BtnIzquierdaClick (Sender: Tobject);


begin
if ImgPersonaje.Left > 0 then
imgPersonaje.Left := imgPersonaje.Left –10
else
end;

Este cambio verifica que la coordenada izquierda de la imagen


sea siempre mayor que cero, ya que si es menor, la imagen al moverlo
quedará fuera del formulario.

BtnArribaibaClick

El movimiento hacia arriba del personaje necesita un código similar al


anterior. Agreguen el código siguiente:
if ImgPersonaje.Top > 0 then
BtnDerechaClick
if ImgPersonaje.Left < Form1.ClientWidth - ImgPersonaje.Width - 4
then

Este código verifica que el personaje no supere el ancho del contenedor


(nuestro formulario), tomando como ancho total del mismo el ancho del
formulario menos el ancho del personaje. Nótese que también le

http://programacion-de-juegos.gdsweb.com.ar/ (5 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

restamos 4 , ésto es para que no genere una barra de desplazamiento


horizontal al querer dibujar en el límite derecho del formulario.

BtnAbajoClick

if ImgPersonaje.Top < Form1.ClientHeight - ImgPersonaje.Height - 1


then
Es muy similar al código anterior con la sola diferencia que se le resta 1
en lugar de 4 para evitar que cree la barra vertical.

Capítulo 5 - Agregando jugadores

Agregaremos más jugadores a nuestro código actual . Estamos


utilizanod los botones para mover a nuestro personaje , por lo que
modificaremos el código para utilizar estos mismos botones para mover
diferentes imágenes según el jugador de turno.

Por ejemplo , si tenemos cuatro jugadores y cada uno debe


mover dos veces cada turno, deberemos realizar lo siguiente: Primero
debe crear un set de cuatro imágenes principales (cada una con la
propiedad visible puesta en false, y el autosize en true), estas imágenes
representan diferentes jugadores y si desea que mismas cambien de
dirección, deberá agregar otras cuatro (con la propiedad visible en falso)
para cada una de las distintas direcciones de cada jugador (frente, detrás
y perfiles). Más adelante ya los introduciremos en el uso de bibliotecas de
imágenes que volverá esto menos complicado. Por el momento, nos
servirá para introducir los conceptos de cómo manejar varios jugadores.

Como agregar y borrar imágenes

Tenemos cuatro imágenes para cada uno de nuestros cuatro jugadores,


llamados, Jugador1, Jugador2, Jugador3 y Jugador4 con las imágenes
Jugador1Izq, Jugador1Arr, Jugador1Aba, Jugador1Der, etc. Para utilizar
estas imágenes debemos volver a modificar el código de nuestro
http://programacion-de-juegos.gdsweb.com.ar/ (6 of 44) [05/04/2004 19:47:24]
Capítulo 1 - El componente Timage

programa.

Dentro del código agregamos dos nuevas variables:

iMovida: integer;
iJugador: integer;
ImgPersonaje: Timage;

También debemos agregar nuestro propio procedimiento,


colocando el siguiente código debajo de la línea private.

procedure VerificarMovida;

Agregaremos una llamada a este procedimiento desde cada click


de los botones de dirección, quedando el código como sigue:

procedure Tform1.BtnIzqClick(Sender: Tobject);


begin
if ImgPersonaje.Left > 0 then
begin
ImgPersonaje.Left := ImgPersonaje.Left -10;
iMovida:= iMovida+1;
VerificarMovida;
end;
end;

procedure Tform1.BtnArribaClick(Sender: Tobject);


begin
if ImgPersonaje.Top > 0 then
begin
ImgPersonaje.Top := ImgPersonaje.Top -10;
iMovida:= iMovida+1;
VerificarMovida;

http://programacion-de-juegos.gdsweb.com.ar/ (7 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

end;
end;

procedure Tform1.BtnDerClick(Sender: Tobject);


Var
iLimiteDerecho: integer;
begin
iLimiteDerecho:= Form1.ClientWidth – ImgPersonaje.Width -4;

if ImgPersonaje.Left < iLimiteDerecho then


begin
ImgPersonaje.Left := ImgPersonaje.Left + 10;
iMovida:= iMovida+1;
VerificarMovida;
end;
end;

procedure Tform1.BtnAbajoClick(Sender: Tobject);


Var
iLimiteInferior: integer;
begin
iLimiteInferior:= Form1.ClientHeight – ImgPersonaje.Height -1;

if ImgPersonaje.Top < iLimiteInferior then


begin
ImgPersonaje.Top := ImgPersonaje.Top + 10;
iMovida:= iMovida+1;
VerificarMovida;
end;
end;

Primero se controla que nuestro personaje no se salga de la pantalla,


http://programacion-de-juegos.gdsweb.com.ar/ (8 of 44) [05/04/2004 19:47:24]
Capítulo 1 - El componente Timage

para sumarle los 10 pixels del desplazamiento, luego se incrementa


iMovida, y se verifica en VerificarMovida la cantidad de pasos dados por
cada jugador.

También se deben inicializar nuestras variables, en el procedimiento


FormCreate; para esto dele doble click al formulario, y escriba el código
siguiente:

ImgPersonaje := ImgJugador1;
iMovida := 0;
iJugador := 1;

La imgPersonaje comenzará con la imagen del jugador 1 (ImgJugador1)


.El programa asume que el número de jugador que comienza a mover es
el número 1 (iJugador).

Procedimiento VerificarMovida

Este procedimiento es llamado cada vez que se pulsa un botón de


movimiento, en cualquiera de las direcciones, y lo utilizaremos para
verificar que un jugador ya haya utilizado sus dos turnos, si esto ocurre
pasamos al jugador siguiente, hasta completar los cuatro jugadores y
volver a comenzar con el jugador 1.
Comenzamos entonces con ImgJugador1, hasta que la variable iMovida
es igual a dos (2), momento en el que le asignamos el turno a
ImgJugador2.

procedure TForm1.VerificarMovida;
begin
if iMovida = 2 then
begin
ImgPersonaje :=ImgJugador2;
iJugador := 2;
end;

http://programacion-de-juegos.gdsweb.com.ar/ (9 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

if iMovida = 4 then
begin
ImgPersonaje :=ImgJugador3;
iJugador := 3;
end;
if iMovida = 6 then
begin
ImgPersonaje :=ImgJugador4;
iJugador := 4;
end;
if iMovida = 8 then
begin
ImgPersonaje :=ImgJugador1;
iMovida := 0;
iJugador := 1;
end;
end;
Si queremos hacer que el personaje voltee en la dirección en la que lo
movemos: necesitamos tres imágenes extras para cada jugador, en total
estamos utilizando unas 16 imágenes.

Debería tener en su formulario 16 imágenes cada una con una imagen


diferente con la propiedad visible en false.
Para este código necesitamos nuevas variables que nos indiquen cual de
las cuatro direcciones estamos viendo . Debemos también agregar 4
procedimientos, los cuales deben ser definidos en la seccion public:
procedure DibujarIzq;
procedure DibujarDer;
procedure DibujarArriba;
procedure DibujarAbajo;
Los procedimientos son los siguientes:

http://programacion-de-juegos.gdsweb.com.ar/ (10 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

procedure TForm1.DibujarIzq;
begin
if ImgPersonaje = ImgJugador1 then
ImgJugador1.Picture := ImgIzq1.Picture;
if ImgPersonaje = ImgJugador2 then
ImgJugador2.Picture := ImgIzq2.Picture;
if ImgPersonaje = ImgJugador3 then
ImgJugador3.Picture := ImgIzq3.Picture;
if ImgPersonaje = ImgJugador4 then
ImgJugador4.Picture := ImgIzq4.Picture;
end;

procedure TForm1.DibujarDer;
begin
if ImgPersonaje = ImgJugador1 then
ImgJugador1.Picture := ImgDer1.Picture;
if ImgPersonaje = ImgJugador2 then
ImgJugador2.Picture := ImgDer2.Picture;
if ImgPersonaje = ImgJugador3 then
ImgJugador3.Picture := ImgDer3.Picture;
if ImgPersonaje = ImgJugador4 then
ImgJugador4.Picture := ImgDer4.Picture;
end;

procedure TForm1.DibujarArriba;
begin
if ImgPersonaje = ImgJugador1 then
ImgJugador1.Picture := ImgArriba1.Picture;
if ImgPersonaje = ImgJugador2 then
ImgJugador2.Picture := ImgArriba2.Picture;
if ImgPersonaje = ImgJugador3 then
ImgJugador3.Picture := ImgArriba3.Picture;
if ImgPersonaje = ImgJugador4 then
ImgJugador4.Picture := ImgArriba4.Picture;

http://programacion-de-juegos.gdsweb.com.ar/ (11 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

end;

procedure TForm1.DibujarAbajo;
begin
if ImgPersonaje = ImgJugador1 then
ImgJugador1.Picture := ImgAbajo1.Picture;
if ImgPersonaje = ImgJugador2 then
ImgJugador2.Picture := ImgAbajo2.Picture;
if ImgPersonaje = ImgJugador3 then
ImgJugador3.Picture := ImgAbajo3.Picture;
if ImgPersonaje = ImgJugador4 then
ImgJugador4.Picture := ImgAbajo4.Picture;
end;

Si corre este código podrá ver a nuestros cuatro personajes moviéndose


a través de la pantalla.

Capítulo 6 – El componente TTimer

Esta es una introducción al componente Ttimer, el cual será utilizado en


las guías subsiguientes. Está pensada para que no tenga problemas al
querer utilizarlo, pero si usted ya conoce el componente puede saltearse
este capítulo y pasar a los ejercicios prácticos.

A menudo puede ser útil generar un evento a intervalos regulares de


tiempo durante el juego, en lugar de verificar permanentemente si ocurrio
cierta acción. Nosotros queremos conseguir que el programa verifique si
el usuario está usando la palanca de mandos (Joystick) o las teclas de
cursor. Hay que tener en cuenta que si el programa estuviera verificando
continuamente, se pondría demasiado sensible a cada movimiento del
Joystick o teclas del cursor.
Otro uso del Ttimer se verá en el capítulo 7, donde analizaremos un
juego con inteligencia artificial . A menudo tenemos que verificar donde

http://programacion-de-juegos.gdsweb.com.ar/ (12 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

se encuentra el otro jugador, por ejemplo para que los fantasmas


persigan a un PacMan de forma inteligente. Recuerde que usted puede
tener muchos TTimers en un programa, para verificar o realizar distinto
tipo de acciones en diferentes períodos de tiempo, por ejemplo mover los
asteroides, disparar misiles, mover las naves contrarias, etc. Al igual que
como con la mayoría de los componentes, usted puede alterar sus
propiedades durante el funcionamiento del programa. En el caso del
componente TTimer la línea siguiente puede alterar el tiempo de espera,
para que usted pueda acelerar un personaje, por ejemplo cuando ellos
empujan una palanca, o botón particular. El ejemplo coloca el intervalo en
100 independientemente del valor anterior.
Timer1.Interval := 100;
El Ttimer no nos sirve en caso que queramos generar una pausa.
El Comando Sleep o Delay

En las versiones más nuevas de Delphi existe el comando Sleep (tiempo


en milisegundos), pero en versiones anteriores, no existia esta
instrucción. Pascal tiene la instrucción Delay, para aquellos de ustedes
que programan en alguna versión de Delphi y no tienen el comando
Sleep, o para aquellos a los que les interese saber como generar un
procedimiento que haga esto, aquí va el código:
procedure Delay(Num: longint);
var
tc: longint;
begin
tc :=GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount-tc) >= Num);
end;
Asegúrese de poner este procedimiento antes de cualquiera de sus otros
procedimientos, para que sea reconocido por alquellos que lo usan. Para
usarlo , todo lo que necesita hacer es:

http://programacion-de-juegos.gdsweb.com.ar/ (13 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Delay(1000);
Lo que hace esto es crear un retraso de un segundo ya que el tiempo es
calculado en milisegundos.
Con ésto termina nuestra mini introducción al manejo del Ttimer. El
Ttimer no es perfecto ya que puede tener diferencias de una
computadora a otra, si no se usa correctamente.

Capítulo 7 – Introducción a la Inteligencia Artificial

En este capítulo introduciremos los conceptos básicos de IA, pero no


obstante esperamos que encuentre de utilidad todo lo que acá se
exponga.

La Inteligencia Atacante

En este capítulo, crearemos dos personajes, uno controlado por usted, el


otro por la computadora. Básicamente, el objetivo del personaje
controlado por la computadora es buscar las coordenadas del oponente ,
pero a usted le parecerá que lo persigue, o lo ataca. Cada vez que usted
se aleja del otro personaje, éste lo perseguirá y sólo se va a detener
cuando esté en su misma posición.

Para empezar necesita crear un personaje y las cuatro direcciones en las


que se va a mover. Una vez hecho esto, también necesita crear otro
TImage para representar al personaje de la computadora. Luego agregue
el componente TTimer de la solapa del Sistema y ponga el intervalo de
tiempo a 100, siempre puede corregir esta velocidad (retraso) después.
Cuánto más chico sea el valor utilizado, más rápido se moverá el
personaje de la Pc, y lo alcanzará a Usted antes ,aumentando el nivel de
dificultad. Para los propósitos de esta guía, asumiremos que usted llamó
al TImage del jugador, Jugador y al TImage del enemigo, Enemigo.

http://programacion-de-juegos.gdsweb.com.ar/ (14 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Para que nuestro perseguidor parezca tener vida, debemos utilizar el


componente TTimer. Haga doble clic en él ,en su formulario, y aparecerá
en el editor de código en el evento pertinente, allí escriba las líneas
siguientes entre el begin y end;.

if ImgJugador.Left > ImgEnemigo.Left then


ImgEnemigo.Left := ImgEnemigo.Left + 2;

if ImgJugador.Left < ImgEnemigo.Left then


ImgEnemigo.Left := ImgEnemigo.Left - 2;

if ImgJugador.Top > ImgEnemigo.Top then


ImgEnemigo.Top := ImgEnemigo.Top + 2;

if ImgJugador.Top < ImgEnemigo.Top then


ImgEnemigo.Top := ImgEnemigo.Top - 2;

El código anterior, verifica cada vez que es llamado, en un intervalo de


tiempo dado por TTimer , si la posición izquierda y superior del jugador es
mayor a la del perseguidor. Recuerde que la posición Izquierda y
Superior son nuestras coordenadas X e Y. En este programa si las
coordenadas del jugador son mayoresa las del enemigo, se suma dos a
sus coordenadas hasta que las coordenadas del enemigo sean iguales a
las del jugador. Un juego simple pero sirve para que usted capte la idea.
Podrían intentar , por ejemplo ,que ,cada vez que el enemigo alcance al
jugador se produzca una explosión, (mostrando un gráfico de explosión
en la posición del jugador) y el jugador pierda una vida, decrementando la
variable de nVidas. Cuando el número de vidas se pone a cero, el Juego
termina y debería mostrar un gráfico de Final de Juego, y presentar los
puntajes. No sería mala idea que realicen esto como ejercicio práctico.

El Jugador como Atacante

Para invertir los roles y hacer que la computadora escape de su

http://programacion-de-juegos.gdsweb.com.ar/ (15 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

personaje, sólo es necesario cambiarle cada uno de los - por un + y cada


uno de los signos+ por un -. Sin embargo, usted necesitará asegurarse de
que su personaje no se salga de los bordes de la pantalla, ver capítulo 2.
Obviamente, por las reglas de movimiento, es probable que cuando el
enemigo se escape por la pantalla, se quede atrapado en la esquina,
para mejorar esto debe hacer algunas nuevas reglas de escape,
mejorando el algoritmo.
Por ejemplo usted podría hacer que el enemigo, solo comience a alejarse
cuando usted se encuentre dentro de los 50 pixeles de él. Para ellos
agregue unas cuatro líneas extras como se muestra debajo. También
debe verificar que la distancia sea menor a 50 pixeles para moverlo.
if ImgJugador.Left > ImgEnemigo.Left then
if ImgJugador.Left - ImgEnemigo.Left < 50 then
ImgEnemigo.Left := ImgEnemigo.Left - 2;

if ImgJugador.Left < ImgEnemigo.Left then


if ImgEnemigo.Left - ImgJugador.Left < 50 then
ImgEnemigo.Left := ImgEnemigo.Left + 2;

if ImgJugador.Top > ImgEnemigo.Top then


if ImgJugador.Top - ImgEnemigo.Top < 50 then
ImgEnemigo.Top := ImgEnemigo.Top - 2;

if ImgJugador.Top < ImgEnemigo.Top then


if ImgEnemigo.Top - ImgJugador.Top < 50 then
ImgEnemigo.Top := ImgEnemigo.Top + 2;

Como ejercicio sobre IA, vamos a crear un programa que imite una
imgMosca zumbando alrededor de una flor. Cómo vamos a hacer eso?
Bien, generaremos un número aleatorio para decidir si la imgMosca se
moverá hacia la flor, fuera de la flor o en una dirección aleatoria.

De esta manera, vamos a permitir que la imgMosca 'decida' ir hacia la


flor, alejarse de ella o tomar cualquier otra dirección . ¿Por qué pongo

http://programacion-de-juegos.gdsweb.com.ar/ (16 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

decide entre comillas? Bien, porque técnicamente todo que hace es crear
un número aleatorio y realizar una acción determinada, no está tomando
realmente ninguna decisión. Como el programa no puede tomar
decisiones , conviene dejarlas libradas al azar.

La función Random

Antes de continuar permítame presentarle al número aleatorio.


function Azar(const n: integer): integer;
begin
Azar := Trunc(Random*n) + 1;
end;

Corto pero elegante. Esto prepara el procedimiento que se usará


después. Si usted escribe la línea Azar(6) esto generará un número al
azar entre el cero y seis, veremos esto más tarde. También necesita
llamar a la siguiente línea en su procedimiento FormCreate para que el
número aleatorio se inicialice y no repita siempre los mismos valores.

Randomize;

Existe más de una forma de realizar lo mismo

Las dos tienen sus propias ventajas, depende de usted decidir cual usará
en su propio juego, pero yo recomendaría probarlas ambas.

La primer forma

Para hacer este programa usted necesitará tres componentes, el


componente TTimer y dos componentes TImage. Los dos componentes
TImage representarán la imgMosca y la flor respectivamente, mientras el
componente TTimer se usará para revisar lo que está ocurriendo cada
cierto tiempo.

http://programacion-de-juegos.gdsweb.com.ar/ (17 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Asumo que ya ha escrito los procedimientos de random. Dele doble clic al


componente TTimer en su formulario y escriba las líneas de codigo que
se muestran debajo. Note, que yo he nombrado al componente de
TTimer, como Cronómetro.

procedure Tform1.CronómetroTimer(Sender: Tobject);


var
Direccion: integer;
begin
Direccion := Azar(5);

// Se aleja
if Direccion = 1 then
if ImgMosca.Top = ImgFlor.Top then ImgMosca.Top :=
ImgMosca.Top + 8
else
if ImgMosca.Left =ImgFlor.Left then
ImgMosca.Left:=ImgMosca.Left+8;

// Se acerca
if Direccion = 2 then
if ImgMosca.Top < ImgFlor.Top then ImgMosca.Top :=
ImgMosca.Top + 8
else
if ImgMosca.Left<ImgFlor.Left then ImgMosca.Left :=
ImgMosca.Left+8
else
if ImgMosca.Top > ImgFlor.Top then ImgMosca.Top :=
ImgMosca.Top - 8
else
if ImgMosca.Left >ImgFlor.Left then ImgMosca.Left
:=ImgMosca.Left-8;

// Baja
if Direccion = 3 then
ImgMosca.Top := ImgMosca.Top + 8;

http://programacion-de-juegos.gdsweb.com.ar/ (18 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

// Sube
if Direccion = 4 then
ImgMosca.Top := ImgMosca.Top - 8;

// Derecha
if Direccion = 5 then
ImgMosca.Left := ImgMosca.Left + 8;

// Izquierda
if Direccion = 6 then
ImgMosca.Left := ImgMosca.Left - 8;

end;

Primeramente, hemos definido una variable en la que ponemos el


resultado de nuestro número aleatorio, llamada Direccion. En la línea
Direccion := Azar(5)+ 1 (que me da un número aleatorio entre cero y
cinco y le suma uno) para que el resultado sea cualquier número entre
uno y seis. Cada uno de estos seis números representa una acción
diferente que la imgMosca puede tomar. Los primeros dos representan la
imgMosca 'alejándose' de la flor o yendo hacia la flor, mientras que los
cuatro últimos representan la imgMosca que sube, baja, vuela a
izquierda y derecha. Se puede crear una acción bastante realista de una
imgMosca. Siéntase libre para jugar y modificarlo a su gusto.

La segunda alternativa

Para el segundo programa, usted necesitará dos componentes TImage y


un componente TButton, y ningún componente TTimer. Gran parte del
código usado en el ejemplo anterior se vuelve a repetir para el
movimiento de la imgMosca. Lo mismo pasa el procedimiento aleatorio, el
cual se debe escribir al comienzo. Usted también necesitará agregar el
procedimiento de Retraso (Sleep o Delay) que vimos en el capítulo 6,
como se ve debajo.

http://programacion-de-juegos.gdsweb.com.ar/ (19 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

procedure Delay(Num: longint);


var
tc: longint;
begin
tc :=GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount-tc) >= Num);
end;
Usaremos el evento del Formulario OnActivate para poner el resto de
nuestro codigo. Esto significa básicamente que cuando nuestro programa
corra, el siguiente código se ejecutará.
procedure TForm1.FormActivate(Sender: TObject);
var
Direccion: integer;
Contador: integer;
begin
contador :=0;
repeat
Delay(400);
Direccion := Azar(6);

// Se aleja
repeat
contador := contador + 1;
if Direccion = 1 then
if ImgMosca.Top = ImgFlor.Top then ImgMosca.Top
:=ImgMosca.Top + 8
else
if ImgMosca.Left=ImgFlor.Left then
ImgMosca.Left:=ImgMosca.Left+8;
until contador = 10;
contador := 0;

// Se acerca
repeat

http://programacion-de-juegos.gdsweb.com.ar/ (20 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

contador := contador + 1;
if Direccion = 2 then
if ImgMosca.Top < ImgFlor.Top then ImgMosca.Top
:=ImgMosca.Top + 8
else
if ImgMosca.Left <ImgFlor.Left then
ImgMosca.Left:=ImgMosca.Left+8
else
if ImgMosca.Top > ImgFlor.Top then ImgMosca.Top :=
ImgMosca.Top -8
else
if ImgMosca.Left>ImgFlor.Left then
ImgMosca.Left:=ImgMosca.Left-8;
until contador = 10;
contador := 0;

// Baja
repeat
contador := contador + 1;
if Direccion = 3 then
ImgMosca.Top := ImgMosca.Top + 8;
until contador = 10;
contador := 0;

// Sube
repeat
contador := contador + 1;
if Direccion = 4 then
ImgMosca.Top := ImgMosca.Top - 8;
until contador = 10;
contador := 0;

// Derecha
repeat
contador := contador + 1;
if Direccion = 5 then
ImgMosca.Left := ImgMosca.Left + 8;

http://programacion-de-juegos.gdsweb.com.ar/ (21 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

until contador = 10;


contador := 0;

// Izquierda
repeat
contador := contador + 1;
if Direccion = 6 then
ImgMosca.Left := ImgMosca.Left - 8;
until contador = 10;
contador := 0;

end;

La primera cosa que usted notará es que se ha introducido otra variable


llamada Contador. Esta variable se usa en nuestro repeat...until para
decidir cuántas veces se repetirá. Notará que hemos colocado contador
:= 0 a lo largo del programa ,ésto es sólo para asegurarnos que después
de cada vuelta el valor del contador se restablece a cero, para no causar
ningún error. Así, la diferencia principal entre este método y el anterior es
que tenemos ahora un bucle repetitivo , que indica la cantidad de veces
que se moverá en cada una de las seis direcciones. Por último debe
agregar la línea siguiente antes del fin; en el procedimiento anterior:

until bBotonPulsado = True;


También, dele doble clic en el botón y escriba el siguiente código:
bBotonPulsado := True;

Finalmente, agregue la próxima línea en su sección de variables debajo


la línea Form1: TForm1;:

bBotonPulsado: Boolean;

Espero que lo disfruten y analicen , para que puedan sacar buen partido
de este capítulo.

http://programacion-de-juegos.gdsweb.com.ar/ (22 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Capítulo 9 – Introducción a los Tiles (fondos mapeados)

En este capítulo estaremos creando nuestro propio mapa de tiles basado


en tres bitmaps diferentes, cada uno cuadrado y del mismo tamaño. El
objetivo será mover un personaje a través de una especie de grilla.

Creando los mapas

La primer cosa que necesitamos hacer es crear las tres imágenes que
vamos a usar para el mapa. En este caso tengo tres tiles (recuadros) de
60 * 60 pixels, uno con una imagen de árboles, una de césped y una de
agua. Puede ver estas imágenes debajo con sus respectivos nombres .
Cree un TImage para cada tile y ponga AutoSize y Visible a falso. Ya que
la propiedad visible está en falso, no interesa donde coloque las
imágenes porque el programa las colocará en forma de mosaico (tiles).

ImgArboles ImgCesped ImgAgua

Una vez que los haya insertado es momento de escribir el programa que
pondrá las imágenes dónde nosotros queremos. Necesitaremos usar una
instrucción llamada CopyRect.

Previamente inicializamos nuestro vector (array) el cual se usará para


dibujar nuestro mapa en la pantalla. Lo que hacemos es asignar un
número a cada una de nuestras tres imágenes, 0 para ImgArboles, 1 para
ImgCesped y 2 para ImgAgua . Digamos que queremos algo así:
tenemos un mapa que va a ser de cinco por cinco, con un circulo de agua
en el exterior, árboles en el centro y césped en todas las otras zonas,
entonces tendríamos lo siguiente:

http://programacion-de-juegos.gdsweb.com.ar/ (23 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

222222
211112
210012
211112
222222

Esto daría el cuadro siguiente en la pantalla:

Para representar esto en nuestro programa necesitamos las líneas


siguientes en la declaración de constantes.

http://programacion-de-juegos.gdsweb.com.ar/ (24 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

arr: array[0..5, 0..4] of integer =


((2, 2, 2, 2, 2),
(2, 1, 1, 1, 2),
(2, 1, 0, 1, 2),
(2, 1, 0, 1, 2),
(2, 1, 1, 1, 2),
(2, 2, 2, 2, 2));

La primer columna de la izquierda (de números 2) representará la línea


base de nuestro mapa cuando aparece en la pantalla. Si usted fuera a
tener un mapa más grande o más pequeño que esto debería ajustar los 5
y 4 en el [0 ..5, 0 ..4] .

Estas líneas no harán nada por sí solas, nos falta nuestra instrucción
CopyRect. Seleccione la solapa System de componentes y elija el
componente PaintBox.

Una vez que haya agregado el componente y puesto su propiedad Align a


alClient. Esto hará que el PaintBox cubra todo el formulario. Muévase a la
solapa de Eventos en el Inspector de Objetos pulse doble clic sobre
OnPaint. Esto creará el código en el cual vamos a escribir las próximas
líneas..
procedure TForm1.PaintBox1Paint(Sender: TObject);
var
x: integer;
y: integer;
begin
for x := 0 to 5 do begin
for y := 0 to 4 do begin
case arr[x, y] of

0: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60,
(x*60)+59,(y*60)+59),ImgArboles.Canvas,Rect(0,0,59,59));

1: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60,
(x*60)+59,(y*60)+59),ImgCesped.Canvas,Rect(0,0,59,59));

2: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60,

http://programacion-de-juegos.gdsweb.com.ar/ (25 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

(x*60)+59,(y*60)+59),ImgAgua.Canvas,Rect(0,0,59,59));

end;
end;
end;
end;
Tomaremos la línea siguiente para describir cómo funciona.
1: PaintBox1.Canvas.CopyRect(Rect(x*60,y*60,(x*60)+59,
(y*60)+59),ImgCesped.Canvas,Rect(0,0,59,59));
CopyRect dibujará un rectángulo en el canvas del PaintBox. Lo que
necesita son las coordenadas del ángulo superior izquierdo y del inferior
derecho del rectángulo a copiar.
Así la línea PaintBox1.Canvas.CopyRect(Rect(0,0,59,59)) dibujaría un
rectangulo desde las coordenadas (0,0) hasta (59,59).

Ya es hora de que pruebe el programa, tendrá un mapa de seis por


cinco, utilizando las tres imágenes anteriores. Juegue un poco con él
,cambiándole los valores para entender su funcionamiento.

Ya tenemos nuestro fondo . Como ejercicio realice un mapa más grande,


agregue más imágenes al fondo.

Capítulo 10 – Moviendo Personajes sobre un Tilemap

Esta vez veremos como mover un personaje sobre un fondo usando el


mouse y cómo saber en qué sección del mapa se encuentra.

Manejando los sprites con el mouse

Lo primero que necesitamos hacer es escribir el procedimiento


OnMouseDown. Para hacer esto, seleccione su Paintbox, dele doble click
en el inspector de objetos, al lado de la línea que dice OnMouseDown. El
código básico lo pone delphi automáticamente, este código se ejecuta
siempre que el botón del mouse es pulsado.

http://programacion-de-juegos.gdsweb.com.ar/ (26 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Se preguntará por qué nosotros no usamos el procedimiento OnClick. La


razón es bastante simple. El evento OnMouseDown devuelve las
coordenadas exactas en las que el mouse se encontraba cuando fue
pulsado, como puede verse en el código:
procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button:
TMouseButton;Shift: TShiftState; X,Y:Integer);

Las letras X e Y representan las coordenadas X e Y del mouse al ser


pulsado. Si usted hubiera utilizado el evento OnClick obtendría la línea
siguiente:

procedure TForm1.PaintBox1Click(Sender: TObject);

Esto es claramente inútil ya que no me devuelve ninguna coordenada. La


única información que obtendremos es que el mouse ha sido pulsado.

Ahora podemos comenzar la escritura del código. Nuestro tile es de 60


por 60 pixels. Queremos saber sobre qué tile pulsó el mouse, para mover
nuestro personaje hacia él. Para ello necesitaremos un par de nuevas
variables que llamaremos mousex y mousey. Agregue las líneas
siguientes antes del begin:

Var
mousex: integer;
mousey: integer;

Recuerde que como las variables son enteras para dividirlas por 60
usaremos div para obtener un número entero. Agregue lo siguiente
después del begin.

mousex := X div 60;


mousey := Y div 60;

Esto significa que si el usuario hace clic sobre el formulario en las

http://programacion-de-juegos.gdsweb.com.ar/ (27 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

coordenadas (224,156), la variable mousex será 3 (porque 224 dividido


por 60 es 3.73 con el número entero convertido en 3 en lugar de 4), y
mousey será 2 (como 156 dividido por 60 es 2.6). Una vez hecho esto
debemos rearmar las coordenadas para ubicar el comienzo del tile
deseado:

ImgPersonaje.Left := mousex * 60;


ImgPersonaje.Top := mousey * 60;
Así, en el caso de las coordenadas anteriores de (224,156), el resultado
final a la que se moverá la imagen de nuestro personaje será (180,120)
(qué es la posición del tile (3,2)). Esto es todo lo que usted necesita
sobre el tema del uso del mouse en un tilemap. ¡Obviamente si tiene un
fondo mapeado en su pantalla, no necesita preocuparse de que su
personaje se salga del borde, ya no puede hacer clic fuera de la misma.

Averiguando la posición de un personaje

Verificar si su personaje está en el agua, en el césped o en el bosque es


muy simple. Lo que deseamos averiguar es dónde se encuentra, para
que siempre que usted haga clic en el agua, la imagen se convierta en su
Personaje hundiéndose en el agua. Primero agregue un nuevo
componente TImage llamado ImgEnElAgua e inserta la imagen
pertinente. De nuevo, use la Transparencia y AutoSize para ajustarlo.
Luego necesitamos agregar un par de líneas a nuestro procedimiento
MouseDown:
if arr[mousex,mousey] = 2 then ImgPersonaje.Picture :=
ImgEnElAgua.Picture;

Esto verifica que el tile actual, en el que estamos parados (mousex,


mousey), tenga valor 2. Si es así, entonces ese tile es el del agua, y la
imagen del personaje cambiará a la del que se está hundiendo. Como
ejercicio pueden realizar un personaje subiendo una colina, mostrando
una imagen de él trepando.

http://programacion-de-juegos.gdsweb.com.ar/ (28 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Animación sin parpadeos

Una de las cosas más difíciles de realizar en cualquier lenguaje es una


animación con movimientos suaves, evitando el parpadeo típico de
redibujar un gráfico.

Para este ejercicio necesitaremos un TImage, TPaintBox y un TTimer.

Los Timage

Usamos tres TImage para este ejemplo. El primero para la imagen del
Fondo (que llamaremos ImgFondo), el segundo es el Sprite o Personaje
(ImgSprite), y el tercero es la Máscara de nuestro sprite (ImgMascara).
Estos gráficos son:

El Sprite

Su máscara respectiva

La utilidad de la máscara es indicarle a la pc, qué puntos han de ser


transparentes. Comenzamos dibujando la máscara y el sprite real encima
de ella. Sin una máscara encontraríamos que nuestro sprite está
ligeramente transparente lo cual puede ser deseable en ciertas
situaciones, pero este no es el caso. Debe poner la propiedad de
transparente en falso para las tres TImage.

Los PaintBox

Utilizaremos dos paintbox, un buffer de la imagen (temporal), y una


imagen terminada o final (visible), El buffer es donde realizaremos todos
los movimientos y dibujos (cortado, copiado, pegado), mientras que el

http://programacion-de-juegos.gdsweb.com.ar/ (29 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

otro solamente se utilizará para mostrar el resultado final. Para programar


nuestros movimientos debemos tener en cuenta lo siguiente::

● Dibujar nuestra imagen de fondo en el Buffer (memoria temporal).


● Dibujar la máscara (la forma del pacman) sobre el fondo

● Dibujar nuestro Sprite (pacman), sobre la máscara recién pintada.

● Copiar el resultado desde nuestro buffer hasta el paintBox de

resultado.
Este último paintBox (el de resultado) es el único que ve el usuario, El
paintBox buffer y el de resultado necesitan ser exactamente del mismo
tamaño que nuestra Imagen de Fondo. Debe poner la propiedad visible
del ImgBuffer a falso y en verdadero la del PaintBox de resultado.
El Buffer puede colocarlo en cualquier parte de la pantalla, ya que no es
visible, el ImgVisible debe ubicarlo donde quiera que se vea el resultado
final.

El TTimer

Simplemente fije la propiedad de Intervalo a 20, y la propiedad Enabled a


True.

En resumen

Escriba lo siguiente en la sección de variables.


RecFondo: TRect;

RecImagen: TRect;

RecMascara: TRect;

iX : Integer;
iY : Integer;

function RecSprite( X, Y: Integer ): TRect;

http://programacion-de-juegos.gdsweb.com.ar/ (30 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Las primeras tres variables son para guardar el área del fondo, la imagen
del sprite, y la máscara respectivamente. Las dos variables siguientes
son las coordenadas del sprite, y la función RecSprite que nos permite
mover el sprite en pantalla. También necesitamos una constante que
indique el ancho.

Const
AnchoSprite : Integer = 28;

El código para el procedimiento FormCreate.


procedure TForm1.FormCreate(Sender: TObject);
begin

iX := 10;
iY := 440;

RecFondo := Rect(0, 0, ImgFondo.Width, ImgFondo.Height);

RecImagen := Rect(0, 0, AnchoSprite, ImgSprite.Height);

RecMascara := Rect(0, 0, AnchoSprite, ImgSprite.Height);


end;

Las primeras dos líneas indican la posición de comienzo del personaje


(sprite) en este caso (10,440). Inicializamos las variables RecFondo,
RecImagen y RecMascara.

Codifiquemos la función como sigue.


function TForm1.RecSprite(X, Y: Integer):TRect;
begin
RecSprite := Rect(X, Y, X+AnchoSprite, Y+ImgSprite.Height);
end;

Cuando llamamos a la función RecSprite Me devuelve la posición, alto y


ancho que ocupará mi sprite.

El código principal se escribirá en el evento OnTimer.

http://programacion-de-juegos.gdsweb.com.ar/ (31 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

procedure TForm1.Timer1Timer(Sender: TObject);


begin
ImgBuffer.Canvas.CopyMode := cmSrcCopy;
ImgBuffer.Canvas.CopyRect(RecFondo, ImgFondo.Canvas, RecFondo );

ImgBuffer.Canvas.CopyMode := cmSrcAnd;
ImgBuffer.Canvas.CopyRect(RecSprite(iX,iY), ImgMascara.Canvas, RecMascara );

ImgBuffer.Canvas.CopyMode := cmSrcPaint;
ImgBuffer.Canvas.CopyRect(RecSprite(IX,IY), ImgSprite.Canvas, RecImagen );

iX := iX + 4;

ImgVisible.Canvas.CopyMode := cmSrcCopy;
ImgVisible.Canvas.CopyRect(RecFondo, ImgBuffer.Canvas, RecFondo );

end;

Lo primero que hace es copiar nuestro fondo. La primer línea selecciona


el modo de copia cmSrcCopy. Este modo significa que el bitmap se
copiará tal cual al ImgBuffer. En la próxima línea usamos CopyRect para
copiar ImgFondo (nuestra imagen de fondo).

Las otras dos líneas son similares, pero en este caso copian la máscara
con un modo de copia AND.

Solo nos falta copiar el sprite sobre la máscara con cmSrcPaint que es
como realizar un OR con la imagen, manteniendo la transparencia.
Aunque hemos terminado de modificar nuestro sprite, aún no vemos
ningún cambio en la pantalla, debemos copiar el ImgBuffer al ImgVisible,
sumando 4 a la coordenada iX para que la próxima vez que se llame al
evento OnTimer, parezca que nuestro sprite está caminando.
Resumen de los pasos hechos en el código:

● Copiar ImgFondo a ImgBuffer


● Copiar ImgMascara (AND) en ImgBuffer
● Copiar ImgSprite sobre (OR) el ImgBuffer

http://programacion-de-juegos.gdsweb.com.ar/ (32 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

● Aumentar iX
● Copiar ImgBuffer, en ImgVisible

Comenzamos con algo un poco más divertido, intentaremos hacer que el


pacman abra y cierre la boca mientras se mueve.

Comencemos inicializando las constantes y variables.

iCuadrosAnimacion : Integer = 6;

Necesitamos dos Trect extras.

RecImagen2: TRect;

RecMascara2: TRect;

iCuadro : Integer;

Los TRects representan nuestro segundo cuadro de la animación del


sprite y su máscara. La variable iCuadro representa el cuadro (fotograma)
de la animación que se está mostrando..

Escriba el siguiente código en el procedimiento FormCreate.

iCuadro := 1;

RecImagen2 := Rect(AnchoSprite + 1, 0, AnchoSprite*2 + 1,


ImgSprite.Height);

RecMascara2 := Rect(AnchoSprite + 1, 0, AnchoSprite*2 + 1,


ImgSprite.Height);

Debemos modificar el procedimiento OnTimer para indicar que finalice la


animación tras los seis cuadros.

http://programacion-de-juegos.gdsweb.com.ar/ (33 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

procedure TForm1.Timer1Timer(Sender: TObject);


begin

ImgBuffer.Canvas.CopyMode := cmSrcCopy;
ImgBuffer.Canvas.CopyRect(RecFondo, ImgFondo.Canvas, RecFondo);

if iCuadro <= (iCuadrosAnimacion / 2) then begin

// Dibuja la mascara (Frame 1)


ImgBuffer.Canvas.CopyMode := cmSrcAnd;
ImgBuffer.Canvas.CopyRect(RecSprite(IX,IY), ImgMascara.Canvas,
RecMascara);

// Dibuja el Sprite (Frame 1)


ImgBuffer.Canvas.CopyMode := cmSrcPaint;
ImgBuffer.Canvas.CopyRect(RecSprite(IX,IY), ImgSprite.Canvas, RecImagen);
end

else

begin

// *** dibuja la máscara (Frame 2) ***


ImgBuffer.Canvas.CopyMode := cmSrcAnd;
ImgBuffer.Canvas.CopyRect(RecSprite(IX,IY), ImgMascara.Canvas,
RecMascara2);

// *** dibuja el sprite (Frame 2) ***


ImgBuffer.Canvas.CopyMode := cmSrcPaint;
ImgBuffer.Canvas.CopyRect(RecSprite(IX,IY), ImgSprite.Canvas, RecImagen2);

end;

iX := iX + 1;

// el cuadro es 1
iCuadro := iCuadro + 1;
if iCuadro > iCuadrosAnimacion then iCuadro := 1;

ImgVisible.Canvas.CopyMode := cmSrcCopy;
ImgVisible.Canvas.CopyRect(RecFondo, ImgBuffer.Canvas, RecFondo);

http://programacion-de-juegos.gdsweb.com.ar/ (34 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

end;

Esto es todo lo que debe saber de animación, ya puede comenzar a crear


sus propios personajes animados.

Capítulo 12 – Uso del teclado

Tenemos dos opciones para leer el teclado. La primera sería usar código
ASCII y la segunda las constantes de delphi VK_... .Veremos las dos
opciones.

ASCII

Obviamente necesitamos conocer el código ASCII de cada tecla..

Tecla Valor Tecla Valor


A 65 Numpad + 107
B 66 Numpad - 109
C 67
D 68 Insert 45
E 69 Delete 46
F 70 Home 36
G 71 End 35
H 72 Page Up 33
I 73 Page Down 34
J 74
K 75 Esc 27
L 76 Caps Lock 20
M 77 Shift 16
N 78 Ctrl 17
O 79 Alt 18
P 80 Spacebar 32
Q 81 Return 13
R 82 Backspace 8
S 83

http://programacion-de-juegos.gdsweb.com.ar/ (35 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

T 84 Left Arrow 37
U 85 Up Arrow 38
V 86 Right Arrow 39
W 87 Down Arrow 40
X 88
Y 89
F1 112
Z 90
F2 113
0 48 F3 114
1 49 F4 115
2 50 F5 116
3 51 F6 117
4 52 F7 118
5 53 F8 119
6 54 F9 120
7 55 F10 121
8 56 F11 122
9 57 F12 123

Si desea averiguar el valor ASCII de alguna tecla no listada puede recurrir


al siguiente procedimiento en el evento de OnKeyDown escriba:

ShowMessage(VarToStr(Key));

Podemos utilizar la tecla Esc para que el usuario abandone el juego..

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:


TShiftState);
begin
if key = 27 then close;
end;

Utilizamos el procedimiento FormKeyDown que nos permite tomar el


código ASCII de la tecla Esc (27), y cerramos nuestro programa.

Tenga presente si utiliza el procedimiento OnKeyDown para revisar el


teclado, que no distingue mayúsculas de minúsculas, y devuelve siempre
el valor de la tecla en mayúscula. El evento OnKeyPress sí hace esta

http://programacion-de-juegos.gdsweb.com.ar/ (36 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

distinción. La desventaja de usar el evento OnKeyPress es que no


verifica si se pulsan varias teclas simultáneamente.

Si utilizamos el evento OnKeyPress para mover nuestro Sprite podemos


hacer lo siguiente:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);


begin
if Key = 'a' then Sprite.Left := Sprite.Left - 1;
if Key = 'd' then Sprite.Left := Sprite.Left + 1;
end;
Ojo, si el usuario tuviese pulsado Caps, el programa no reconocería las
teclas del ejemplo (que están en minúscula).
En cambio, con el evento OnKeyDown, utilizamos el código ASCII como
sigue:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
if key = 65 then Image1.Left := Image1.Left - 1;
if key = 68 then Image1.Left := Image1.Left + 1;
end;

Para no tener que memorizar los códigos ASCII, se pueden utilizar los
códigos VK_.. que son constantes definidas en delphi.

Códigos de teclas Virtuales (VK)

Como ejemplo verificaremos la pulsación del cursor izquierdo.

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:


TShiftState);
begin
if Key = vk_left then Image1.Left := Image1.Left - 1;
end;
Tabla de Códigos de Teclas Virtuales.

http://programacion-de-juegos.gdsweb.com.ar/ (37 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

VK_UP Tecla de Cursor Arriba


VK_DOWN Tecla de Cursor Abajo
VK_LEFT Tecla de Cursor Izquierda
VK_RIGHT Tecla de Cursor Derecha
VK_INSERT Insert
VK_DELETE Delete
VK_HOME Home
VK_END End
VK_NEXT Page Down
VK_PRIOR Page Up

VK_BACK Backspace
VK_RETURN Return o Intro
VK_SHIFT Shift
VK_CONTROL Control
VK_MENU Alt
VK_CAPITAL Caps Lock
VK_SPACE Barra de Espacio

VK_PAUSE Pausa
VK_SCROLL Scroll Lock
VK_NUMLOCK Num Lock

VK_NUMPAD 0 - 9 Numeros 0 - 9 teclado numérico


VK_MULTIPLY Asterisco teclado numérico
VK_DIVIDE Barra dividir teclado numérico
VK_ADD Suma teclado numérico
VK_SUBTRACT Resta teclado numérico
VK_DECIMAL Punto teclado numérico

VK_F1 - F24 F1 - 24 (teclas de función)

Recuerde que no se pueden utilizar estos código virtuales VK, con el


evento OnKeyPress.

Para terminar con el ejemplo de uso del teclado un ejemplo de como


mover el PacMan con el evento OnKeyDown.

http://programacion-de-juegos.gdsweb.com.ar/ (38 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:


TShiftState);
begin
if Key = 37 then IX := IX - 1; // Izquierda
if Key = 38 then IY := IY - 1; // Arriba
if Key = 39 then IX := IX + 1; // Derecha
if Key = 40 then IY := IY + 1; // Abajo
end;

Capítulo 13 – Uso del Mouse

El evento OnClick
El evento OnClick no es muy utilizado en los juegos, tan solo se usa para
seleccionar un menú de opciones o pulsar algún botón. Necesitamos
algún evento que nos devuelva las coordenadas del mouse en X e Y.
Para esto usaremos el evento OnMouseDown.

OnMouseDown

El evento OnMouseDown dará el X e Y del mouse, esto es sumamente


útil al intentar mover un personaje por la pantalla haciendo clic.

Otra ventaja es que verifica el por separado el botón izquierdo, medio y


derecho, así como también si se pulsan simultaneamente Alt, shift o
Control, esto le dará un mayor control al usuario.

OnMouseUp

Es igual al evento OnMouseDown salvo que se activa cuando el botón del


mouse se suelta. Todo lo demás trabaja la misma manera..

OnMouseMove

Esto es util por ejemplo si se quiere dibujar por pantalla, o para arrastrar y
soltar diferentes objetos..

http://programacion-de-juegos.gdsweb.com.ar/ (39 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Un Ejemplo...
Reunamos todo esto y hagamos un programita, por ejemplo movamos
nuestra imgMosca. Escriba el código siguiente en OnMouseDown del
formulario:
procedure TForm1.FormMouseDown(Sender: TObject; Button:
TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
PosX := ImgMosca.Left;
PosY := ImgMosca.Top;
MouseX := X;
MouseY := Y;

while (PosX <> MouseX) do begin


if MouseX > PosX then PosX := PosX + 1
else if MouseX<PosX then PosX:=PosX - 1;
ImgMosca.Left := PosX;
end;

while (PosY <> MouseY) do begin


if MouseY > PosY then PosY := PosY + 1
else if MouseY<PosY then PosY:=PosY - 1;
ImgMosca.Top := PosY;
end;
end;

Recuerde agregar las siguientes variables en la sección var:

PosX: integer;
PosY: integer;
MouseX: integer;
MouseY: integer;

Lo primero que hacemos al pulsar sobre el formulario es poner en PosX y


PosY la posición de imgMosca, después los valores de MouseX y
MouseY en las coordenadas donde se pulsó.

http://programacion-de-juegos.gdsweb.com.ar/ (40 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Ahora ya estamos en condiciones de mover nuestra imgMosca por la


pantalla hacia la posición pulsada. Se sumará o restará según las
posiciones como lo hicimos anteriormente hasta que la imgMosca se
ubique en la misma posición que el mouse..
Para que la imgMosca vuele un poco más lentamente debemos agregar
un TTimer, y podemos mejorar un poco el algoritmo de vuelo para que
parezca más realista, debemos alterar un poco el código.

Movimiento del código actual Movimiento deseado

Los cambios que necesitamos hacer son los siguientes.

procedure Delay(Num: longint);


var
tc: longint;
begin
tc :=GetTickCount;
repeat
Application.ProcessMessages;
until ((GetTickCount-tc) >= Num);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button:


TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
PosX := ImgMosca.Left;
PosY := ImgMosca.Top;
MouseX := X;
MouseY := Y;

while (PosX <> MouseX) or (PosY <> MouseY)


do begin

http://programacion-de-juegos.gdsweb.com.ar/ (41 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Delay(10);
if (PosX <> MouseX) then begin
if MouseX > PosX then PosX :=PosX+1
else if MouseX<PosX then PosX :=PosX-1;
ImgMosca.Left := PosX;
end;

if (PosY <> MouseY) then begin


if MouseY > PosY then PosY :=PosY+1
else if MouseY<PosY then PosY :=PosY-1;
ImgMosca.Top := PosY;
end;
end;
end;

Como tarea queda que mejoren el algoritmo evitando el parpadeo de la


imgMosca, como se vió en el capítulo 11.

Capítulo 14 – Scroll (desplazamiento de una imagen)

Hemos aprendido cómo lograr una animación sin parpadeos, ahora


veremos cómo mover nuestro fondo para que paresca que nuestro
personaje está caminando a lo largo del paisaje.

Desplazar nuestra imagen no es tan difícil como se podría pensar.


Utilizaremos un código similar al de mover nuestro Pacman, cambiando
las coordenadas de un TRect para mostrar la porción de la imagen total
que queremos ver.
El diagrama de abajo ilustra esto, sólo el área de la imagen delimitada por
TRect será visible al usuario. Disminuyendo la coordenada X de la
esquina superior izquierda, y de la esquina inferior derecha, movemos el
TRect a lo largo de la imagen, creando el efecto de desplazamiento.

http://programacion-de-juegos.gdsweb.com.ar/ (42 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Los principales cambios son cambiar el tamaño del RecFondo.

X1 := 0; Y1 := 0;
X2 := ImgFondo.Width;
Y2 := ImgFondo.Height;
RecFondo := Rect( X1, Y1, X2, Y2);

También debemos declarar estas cuatro variables X1, X2, Y1, e Y2 en la


sección private, escribamos una función que use esas coordenadas, y
devuelva un TRect (X1,Y1,X2,Y2). .

function TForm1.Desplazar:TRect;
begin
Result := Rect(X1,Y1,X2,Y2);
end;

La función la llamaremos desde el procedimiento OnTimer. Donde la


primer parte de este procedimiento dibuja nuestro fondo, en el buffer,
quedando así:

ImgBuffer.Canvas.CopyRect(Desplazar, ImgFondo.Canvas, RecFondo );

Cambiemos la palabra RecFondo por Desplazar en el primer parámetro


de CopyRect. Ya estamos listos para iniciar el verdadero movimiento,
decrementando las coordenadas X1 y X2.

Agregue las siguientes líneas al procedimiento OnTimer:


X1 := X1 - 1;
X2 := X2 - 1;

http://programacion-de-juegos.gdsweb.com.ar/ (43 of 44) [05/04/2004 19:47:24]


Capítulo 1 - El componente Timage

Ahora tenemos el problema de que la imagen se mueve, pero se corta al


finalizar la misma, debemos encontrar la forma de que sea un bucle sin
fin. Que el dibujo vuelva a comenzar.

Cambie el código así.

if X1 > -640 then


begin
X1 := X1 - 1;
X2 := X2 - 1;
end;

Esta es una versión simple, lo que hace es detener la imagen al llegar al


fin de la misma. para que retome desde el comienzo escriba:

if X1 > - 640 then


begin
X1 := X1 - 1;
X2 := X2 - 1;
end
else
begin
X1 := 0;
X2 := ImgFondo.Width;
end;
Por el momento es todo, espero que puedan crear cosas interesantes, lo
próximo sería adentrarnos en Direct X, DirectSound, etc; lo cual lo
veremos si Dios quiere en un próximo cursillo.
Saludos de parte del equipo GDS.
Gabriela y Darío.
Si quieres estudiar con nosotros envíanos un mail a
clases@gdsweb.com.ar clases a distancia o presenciales, estamos
en Villa Urquiza, Capital Federal (Argentina).

http://programacion-de-juegos.gdsweb.com.ar/ (44 of 44) [05/04/2004 19:47:24]