2.
Entrando a modo
gráfico y dibujando.
Contenido
de este apartado:
2.1.
Pautas generales.
Los pasos básicos serán practicamente los mismos,
usemos el lenguaje que usemos:
- Deberemos
entrar a modo
gráfico, y además generalmente deberemos indicar
cuantos
puntos queremos en pantalla y cuantos colores. Esta elección
no
siempre es trivial: cuantos más puntos y más
colores
queramos en pantalla, más costará "mover" toda
esa
información, así que se necesitará un
ordenador
más rápido (no sólo el nuestro,
también el
de las demás personas que usen nuestro juego) y
más
habilidad por nuestra parte a la hora de programar.
- Además
tenemos el
problema añadido de que no todos los ordenadores permiten
todos
los modos gráficos, por lo que deberíamos
descubrir
qué permite el ordenador "cliente" de nuestro juego y
adaptarnos
a sus posibilidades.
- Una
vez en modo
gráfico, tendremos órdenes preparadas para la
mayoría de las necesidades habituales... pero frecuentemente
no
para todo lo que se nos ocurra, así que alguna vez tendremos
que
crear nuestras propias rutinas en casos concretos.
- Algunas
órdenes a las
que estamos acostumbrados no las podremos usar. Por ejemplo, es
frecuente que no podamos usar desde modo gráfico la orden
que se
encarga de leer todo un texto que teclee un usuario (scanf en C, readln
en Pascal, input en Basic). En caso de que queramos "imitar" el
funcionamiento de esas órdenes, supondrá un
trabajo
adicional para nosotros (por ejemplo, en el caso de esa orden, se
debería poder escribir texto, borrarlo en caso de
error sin "estropear" el fondo,
controlando también lo que ocurre al llegar al extremo de la
pantalla o bien si
se pulsan teclas "especiales" como las flechas y Esc).
Por otra parte, las órdenes más habituales que
usaremos
serán las siguientes:
- Algunas
propias de las
bibliotecas gráficas, y que nos permitirán desde
lo
más básico (que es con lo que empezaremos), como
dibujar
líneas, rectángulos o escribir textos, hasta
opciones
avanzadas para representación y manipulación de
imágenes planas y de figuras en tres dimensiones (que
veremos
más adelante).
- Otras
generales del lenguaje
escogido, que van desde las órdenes "habituales" para
controlar
el flujo de un programa (si..entonces, repetir..hasta) hasta
órdenes más específicas (como las que
generan
números al azar).
En este apartado comentaremos cómo se entra a modo
gráfico y como se dibujan los elementos habituales
(líneas, rectángulos, círculos,
puntos, etc) con
las herramientas que hemos escogido.
En
primer lugar,
utilizaremos el modo gráfico más
estándar,
que encontraremos en cualquier tarjeta gráfica VGA o
superior (cualquier PC posterior al 1992 debería tenerla): 320x200
puntos, en 256 colores.
Más adelante veremos cómo
cambiar
a otros modos que nos permitan obtener imágenes de mayor
calidad.
2.2
Cómo
hacerlo en el caso del lenguaje C y la biblioteca Allegro.
Los pasos básicos con C y
Allegro son:
- Inicialización: Entre
los "includes" deberemos añadir <allegro.h>, y al
principio de nuestro "main" la orden allegro_init();
- Entrar a modo gráfico:
set_gfx_mode(GFX_SAFE,ancho,alto,0,0).
De momento sólo nos importan los dos primeros números:
anchura y altura (en puntos) de la pantalla (320x200, por ahora). Esta
función nos devolvera 0 si todo ha ido bien, o un valor distinto
de cero si no se ha podido entrar al modo gráfico que hemos
elegido.
- Dibujar una línea
entre dos puntos: line(screen,x1,y1,x2,y2, color);, donde
x1, y1 son las coordenadas horizontal y vertical del primer punto, x2 e
y2 son las del segundo punto. "screen" indica dónde queremos
dibujar (en la pantalla, ya veremos otros usos). "color" es el color en
el que queremos que se dibuje la línea; si queremos que sea un
color de la paleta estándar, podemos usar construcciones
como palette_color[15] (el color 15 de la paleta estándar
de un PC es el color blanco).
- Salir del modo
gráfico: añadiremos la línea END_OF_MAIN();
después de "main".
Vamos
a verlo un ejemplo "que funcione", que
dibuje
una diagonal en pantalla:
/*----------------------------*/
/*
Intro a la programac de
*/
/*
juegos, por Nacho Cabanes */
/*
*/
/*
IPJ01C.C
*/
/*
*/
/*
Primer ejemplo: entra a
*/
/*
modo gráfico y dibuja
una */
/*
línea diagonal en la pan-
*/
/*
talla.
*/
/*
*/
/*
- MinGW DevStudio 2.05 */
/* (gcc 3.4.2) y
Allegro */
/* 4.03, Windows
XP
*/
/*----------------------------*/
#include
<allegro.h>
#include
<conio.h>
main()
{
allegro_init();
if
(set_gfx_mode(GFX_SAFE,320,200,0,0)!=0){
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message(
"Incapaz
de
entrar a modo grafico\n%s\n",
allegro_error);
return
1;
}
line(screen,20,10,310,175,
palette_color[15]);
getch();
}
END_OF_MAIN();
|
Sólo hay dos cosas
"nuevas" frente a lo que habíamos preparado:
- En caso de error, salimos a
modo texto (GFX_TEXT), mostramos un mensaje de error (una aviso nuestro
más el mensaje de error preparado por Allegro, y usamos para
ello la función auxiliar "allegro_message"), y salimos con el
código de error 1.
- Antes de terminar el
programa, esperamos a que el usuario pulse una tecla, con la
función "getch()", que no es exclusiva de Allegro, sino que se
encuentra en "conio.h".
El resultado será simplemente este (recuerda que en el apartado 1 tienes la forma
de teclear y compilar este fuente):

Demos
un repaso rápido a las posibilidades
más
básicas
de esta biblioteca, en lo que se refiere a modo
gráfico.
- Dibujar
un punto en un cierto color: void putpixel(BITMAP *bmp, int x, int y,
int
color);
- Dibujar
una línea: void line(BITMAP *bmp, int x1, int y1, int x2,
int
y2,
int color);
- Línea
horizontal: void hline(BITMAP *bmp, int x1, int y, int x2, int
color);
- Línea
vertical: void vline(BITMAP *bmp, int x, int y1, int y2, int
color);
- Recuadro:
void rect(BITMAP *bmp, int x1, int y1, int x2, int y2, int
color);
- Recuadro
relleno: void rectfill(BITMAP *bmp, int x1, int y1, int x2, int y2, int
color);
- Círculo:
void circle(BITMAP *bmp, int x, int y, int radius, int color);
- Círculo
relleno: void circlefill(BITMAP *bmp, int x, int y, int radius, int
color);
- Elipse:
void ellipse(BITMAP *bmp, int x, int y, int rx, int ry, int
color);
- Elipse
rellena: void ellipsefill(BITMAP *bmp, int x, int y, int rx, int ry,
int
color);
- Arco
circular: void arc(BITMAP *bmp, int x, y, fixed ang1, ang2, int r, int
color);
(Como
hemos comentado antes, el primer parámetro "BITMAP *bmp"
especifica
dónde se dibujará cada una de esas figuras; para
nosotros
lo habitual por ahora será indicar "screen" -la
pantalla-).
También
podemos rellenar una cierta zona de la pantalla con
- void
floodfill(BITMAP *bmp, int x, int y, int color);
O
leer el color de un punto con
- int
getpixel(BITMAP *bmp, int x, int y);
Para
elegir modo de pantalla
se usa la rutina que ya hemos
visto:
int
set_gfx_mode(int card, int w, int h, int v_w, int v_h);
El
parámetro "card" (tarjeta) normalmente debería
ser
GFX_AUTODETECT
(autodetección); w y h son la anchura (width) y altura
(height)
en puntos, y v_w y v_h son la anchura y altura de la pantalla
"virtual",
más grande que la visible, que podríamos utilizar
para
hacer
algún tipo de scroll, y que nosotros no usaremos por
ahora.
Pero...
¿y el número de colores? Se indica con
- void
set_color_depth(int depth);
Donde
"depth" es la "profundidad" de color en bits. El valor por defecto es 8
(8 bits = 256 colores), y otros valores posibles son 15, 16 (65.536
colores), 24 y 32
bits ("color verdadero").
Ahora
vamos a ver un ejemplo algo más completo:
/*----------------------------*/
/*
Intro a la programac de
*/
/*
juegos, por Nacho Cabanes */
/*
*/
/*
IPJ02C.C
*/
/*
*/
/*
Segundo
ejemplo:
*/
/*
Figuras básicas en modo
*/
/*
640x480 puntos, 64k color */
/*
*/
/*
Comprobado
con:
*/
/*
- Djgpp 2.03 (gcc 3.2)
*/
/*
y Allegro
4.02
*/
/*----------------------------*/
#include
<allegro.h>
#include
<conio.h>
main()
{
allegro_init();
set_color_depth(16);
if
(set_gfx_mode(GFX_SAFE,640,480,0,0)!=0){
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message(
"Incapaz
de
entrar a modo grafico\n%s\n",
allegro_error);
return
1;
}
line(screen,20,10,310,175,
palette_color[15]);
line(screen,639,0,0,479,
palette_color[14]);
rectfill(screen,30,30,300,200,
palette_color[3]);
ellipse (screen,320,200,50,100,
palette_color[11]);
getch();
}
END_OF_MAIN();
|
El
resultado de este programa sería algo como

Hay
muchas más posibilidades, pero las iremos viendo
según
las
vayamos necesitando...
2.3.
Cómo hacerlo en el caso de Free Pascal.
En Free Pascal sería:
- Inicialización:
Debemos incluir uses graph; al principio de nuestro
fuente "main" la orden allegro_init();
- Entrar a modo
gráfico: initgraph(gd, gm, '');.
En esta orden "gd" es el "driver gráfico" a usar. Para 256
colores indicaríamos antes d := D8bit; (un poco
más adelante veremos los principales drivers disponibles); "gm"
es el modo de pantalla (referido a la cantidad de puntos), que en este
caso sería gm := m320x200;
- Dibujar una línea
entre dos puntos: line(x1,y1,x2,y2),
donde x1, y1 son las coordenadas horizontal y vertical del primer
punto, x2 e y2 son las del segundo punto. Para indicar el color se la
línea, usamos antes setcolor(color),
donde "color" es un
color de la paleta estándar (15 es el blanco).
- Salir del modo
gráfico: closeGraph; justo antes del fin del
programa.
Vamos
a verlo en la práctica:
(*----------------------------*) (* Intro a la programac de *) (* juegos, por Nacho Cabanes *) (* *) (* IPJ01P.PAS *) (* *) (* Primer ejemplo: entra a *) (* modo gráfico y dibuja una *) (* línea diagonal en la pan- *) (* talla. *) (* *) (* Comprobado con: *) (* - FreePascal 2.0 -Windows *) (*----------------------------*)
uses graph, crt;
var gd,gm, error : integer;
BEGIN gd := D8bit; gm := m320x200; initgraph(gd, gm, '');
error := graphResult; if error <> grOk then begin writeLn('No se pudo entrar a modo grafico'); writeLn('Error encontrado: '+ graphErrorMsg(error) ); halt(1); end;
setColor(15); line (20,10, 310,175);
readkey; closeGraph; END.
|
(Recuerda que en el apartado 1 tienes cómo teclearlo
y probarlo).
Es
posible que obtengamos el
error "Invalid graphics mode". Sería porque nuestro
ordenador no permite el modo gráfico que hemos elegido. Ante la
duda, podemos hacer que lo detecte, usando gd:=0; gm:=0;
Igual que en el ejemplo en C,
las únicas cosas que aparecen en este fuente y que no
habíamos comentado aun son:
- graphResult nos dice si el
paso a modo gráfico ha sido correcto. Si devuelve un valor
distinto de grOk, querrá decir que no se ha podido, y podremos
ayudarnos de "graphErroMsg" para ver qué ha fallado.
- readkey, de la unidad crt,
espera a que pulsemos una tecla (en este caso lo usaremos antes de
salir, para que tengamos tiempo de ver lo que aparece en pantalla).
Las posibilidades
más básicas
de la biblioteca gráfica de Free
Pascal
son:
- Dibujar
un punto en un color: putpixel(x,y, color);
- Cambiar
el color de dibujo: setColor(c);
- Dibujar
una línea en ese color: line(x1, y1, x2, y2);
- Recuadro:
rectangle(x1, y1, x2, y2);
- Recuadro
relleno (barra): bar(x1, y1, x2, y2);
- Elegir
tipo de relleno y color de relleno: setFillStyle(patron, color);
- Círculo:
circle(x, y, radio);
- Elipse:
ellipse(x, y, anguloIni, anguloFin, radioX, radioY);
- Elipse
rellena: fillEllipse(x, y, radioX, radioY);
- Rellenar
una cierta zona de la pantalla: floodfill(x, y, colorBorde);
- Leer
el color de un punto: getpixel(x, y); (devuelve un valor de tipo
Word)
Para
elegir modo de pantalla
se usa la rutina que ya hemos
visto:
int
initgraph( driver, modo, situacDrivers);
En
su uso más sencillo, tenemos:
- Driver
indica la cantidad de colores: D1bit para blanco y negro, D2bit para 4
colores, D4bit para 16 colores, D8bit para 256 colores,
D16bit
para
65536 colores. Existen otros modos que aún no
están
disponibles
(24 bits, 32 bits), y alguno específico de ciertos
ordenadores
(como
4096 colores para Commodore Amiga).
- Modo
indica la cantidad de puntos en pantalla. Los que más
usaremos
son
m320x200, m640x480, m800x600, pero existen otros muchos, algunos de los
cuales son específicos de ciertos ordenadores (Amiga, Atari,
Mac).
- SituacDeDivers
se puede dejar en blanco (una cadena vacía, ' ') salvo si
quisiéramos
usar tipos de letra de los que Borland creó para Turbo
Pascal,
pero
eso es algo que no haremos, al menos no por ahora.
Un
ejemplo un poco más completo es:
(*----------------------------*)
(*
Intro a la programac de
*)
(*
juegos, por Nacho Cabanes *)
(*
*)
(*
IPJ02P.PAS *)
(*
*)
(*
Segundo
ejemplo:
*)
(*
Figuras basicas en modo
*)
(*
640x480 puntos,16 colores *)
(*
*)
(*
Comprobado
con:
*)
(*
- FreePascal 2.0 -Windows
*)
(*----------------------------*)
uses
graph,
crt;
var
gd,gm,
error :
integer;
BEGIN
gd :=
D4bit;
gm :=
m640x480;
initgraph(gd,
gm,
'');
error :=
graphResult;
if
error <>
grOk then
begin
writeLn('No
se pudo entrar a modo grafico');
writeLn('Error
encontrado: '+
graphErrorMsg(error));
halt(1);
end;
setColor(15);
line (20,10,310,175);
setColor(14);
line (639,0,0,
479);
setFillStyle(
SolidFill,3);
bar(30,30,300,200);
setColor(11);
ellipse (320,200,0,360,50,100);
readkey;
closeGraph;
END.
|
El
resultado de este programa, si compilamos para Windows, es el
siguiente:

2.4.
Cómo
hacerlo en el caso de Java.
En
el lenguaje Java las cosas cambian ligeramente. La sintaxis recuerda
mucho
a la de C, pero muchas de las ideas base son distintas:
- Nuestros
programas creados en Java podrán funcionar en cualquier
equipo
para
el que exista una "máquina virtual Java", lo que supone que
funcionarán
en más de un equipo/sistema operativo distinto sin problemas
y
sin
cambios.
- Por
el otro lado, la existencia de esta "capa intermedia" hace que nuestros
programas puedan funcionar algo más lento si
están
creados
en Java que si es en C++ o en Pascal. No es grave, con la velocidad que
tienen los ordenadores actuales, y menos si nuestros juegos no son
excesivamente
complejos.
- Además,
en Java existe la posibilidad de crear aplicaciones capaces de
funcionar
"por sí mismas", o bien otras pequeñas
aplicaciones que
funcionan
dentro de una página Web, que son los llamados "Applets".
También
existen versiones "limitadas" del lenguaje Java para
pequeños
dispositivos
como ciertos teléfonos móviles o PDAs. Nosotros
empezaremos
por crear "Applets" y más adelante veremos qué
cambia si
queremos crear aplicaciones completas y si queremos hacer algo para
nuestro
teléfono móvil.
El
ejemplo de cómo cambiar a modo gráfico y dibujar
una
diagonal
en un Applet sería:
/*----------------------------*/
/*
Intro a la programac de */
/*
juegos, por Nacho Cabanes */
/*
*/
/*
ipj01j.java
*/
/*
*/
/*
Primer ejemplo: entra a */
/* modo gráfico y dibuja una */
/*
línea diagonal en la pan- */
/*
talla.
*/
/*
*/
/*
Comprobado
con:
*/
/*
- JDK
1.5.0
*/
/*----------------------------*/
import
java.awt.*;
public
class
ipj01j extends
java.applet.Applet
{
public
void
paint(Graphics
g)
{
g.setColor(
Color.yellow
);
g.drawLine(
20,
10,
310,
175
);
}
} |
(Recuerda que en el apartado 1 tienes
cómo teclearlo y probarlo).
Como
es un Applet, está diseñado para ser usado desde
una
página
Web. Por tanto, tendremos que crear esa página Web.
Bastaría
con teclear lo siguiente desde cualquier editor de texto:
<html>
<head>
<title>IPJ
- Ejemplo
1</title>
</head>
<body>
<h1>IPJ
-
Ejemplo
1</h1>
<hr>
<applet
code=ipj01j.class
width=320
height=200>
alt=El
navegador no esta mostrando
el APPLET
</applet>
</body>
</html>
|
Guardamos
este fichero y hacemos doble clic para probarlo desde nuestro
navegador.
Si nuestro navegador no reconoce el lenguaje Java, veríamos
el
aviso
"El navegador no está mostrando el APPLET", pero si todo ha
ido
bien, debería aparecer algo como

Las posibilidades
más
básicas de las
rutinas gráficas
de Java son muy similares a las que hemos visto con Allegro y con Free
Pascal, con alguna diferencia. Por ejemplo, en los
rectángulos
no
se indican las coordenadas de las dos esquinas, sino una esquina, la
anchura
y la altura. De igual modo, en las elipses no se indican el centro y
los
dos radios, sino como el rectángulo que las rodea.
Detallando un
poco
más:
// Escribir texto: mensaje,
coordenada x (horizontal) e y (vertical)
g.drawString( "Hola Mundo!",
100, 50 );
// Color: existen nombres
predefinidos
g.setColor( Color.black
);
// Línea: Coordenadas
x e y de los extremos
g.drawLine( x1, y1, x2,
y2 );
// Rectángulo: Origen,
anchura y altura
g.drawRect( x1, y1, ancho,
alto );
// Rectángulo relleno:
idéntico
g.fillRect( x1, y1, ancho,
alto );
// Rectángulo redondeado:
similar + dos redondeos
g.drawRoundRect( x1, y1,
x2, y2, rnd1, rnd2 );
// Rectángulo redondeado
relleno: igual
g.fillRoundRect( x1, y1,
x2, y2, rnd1, rnd2 );
// Óvalo (elipse):
Como rectángulo que lo rodea
g.drawOval( x1, y1, ancho,
alto );
// Óvalo relleno:
idéntico
g.fillOval( x1, y1, ancho,
alto );
Ahora
vamos a ver un ejemplo algo más completo con alguna de
ellas:
/*----------------------------*/
/*
Intro a la programac de */
/*
juegos, por Nacho Cabanes */
/*
*/
/*
ipj02j.java
*/
/*
*/
/*
Segundo
ejemplo:
*/
/* Figuras básicas en modo */
/* 640x480
puntos
*/
/*
*/
/*
Comprobado
con:
*/
/*
- JDK
1.4.2_01
*/
/*----------------------------*/
import
java.awt.*;
public
class
ipj02j extends
java.applet.Applet
{
public
void
paint(Graphics
g)
{
//
Primero borro el fondo en negro
g.setColor(
Color.black
);
g.fillRect(
0,
0,
639,
479
);
//
Y ahora dibujo las figuras del ejemplo
g.setColor(
Color.white
);
g.drawLine(
20,
10,
310,
175
);
g.setColor(
Color.yellow
);
g.drawLine(
639,
0,
0,
479);
g.setColor(
Color.blue
);
g.fillRect(
30,
30,
270,
170
);
g.setColor(
Color.cyan
);
g.drawOval(
270,
100,
100,
200
);
}
}
|
La
página Web encargada de mostrar este Applet no
tendría
grandes
cambios si comparamos con la anterior. Poco más que el
nombre de
la clase, los "cartelitos" y el tamaño:
<html>
<head>
<title>IPJ
- Ejemplo 2</title>
</head>
<body>
<h1>IPJ
-
Ejemplo 2</h1>
<hr>
<applet
code=ipj02j.class
width=640
height=480>
alt=El
navegador no esta mostrando
el APPLET
</applet>
</body>
</html>
|
Y
el resultado sería este:

Hay
muchas más posibilidades, pero las iremos viendo
según
las
vayamos necesitando...
 
|