1 {** Interpreta y dibuja los datos del modelo en un formulario<br>
\r
4 10/11/00: Se maneja la excepción para evitar usar la camara cuando el cameraman fue destruido (ECameramanDestruido).
\r
5 Esta es propagada (por ahora) para que el controlador (formulario) frene el timer
\r
6 02/12/00: Se mejoran los graficos usando transparencias en los bitmaps y se da la opcion de presentar
\r
7 los graficos con transparencias (alta calidad) o no (a través del atributo aAltaCalidad y
\r
8 los métodos mSetAltaCalidad, mSetBajaCalidad y mCambiarCalidad).
\r
9 Se mejora la performance gracias a la nueva implementación de mDibujar, ya que los
\r
10 bitmas se cargan una sola vez en memoria (en un array aBitmaps) en vez de cargarse
\r
11 y liberarse cada vez que se actualiza la pantalla como sucedía anteriormente.
\r
12 Se implementa el soporte de visualización de un objeto volador lockeado (utilizando
\r
13 otra lista de bitmaps con los gráficos de los objetos lockeados, aBitmapsLockeados).
\r
14 08/12/00: Se agregan múltiples cámaras: Derecha, Izquierda, Arriba, Abajo, Atrás, Del Misil. Para hacerlo
\r
15 se agragega un array de camaras y un atributo que indica la camara actual. Tambien se agregan
\r
16 métodos para cambiar la cámara actual, etc.
\r
17 Se arregla el destructor que no liberaba todos los objetos.
\r
18 09/12/00: Se reemplaza la vista del misil por una mas general (vista del arma) que permite ver a traves de
\r
19 cualquier arma disparada. Se implementa correctamente esta vista.
\r
20 Se agrega una vista tipo mapa.
\r
21 18/12/00: Se corrige un bug que hacía que en ciertas circunstancias no se encuentren las imágenes, agragando
\r
29 {$IFDEF DebugAlgoWars}
\r
44 tArrayBitmaps = array [OV_NAVEPESADA..OV_MISDIR] of TBitmap;
\r
45 tArrayCamaras = array [CAMARA_FRONTAL..CAMARA_ARMA] of cCamara;
\r
47 {** Interpreta y dibuja los datos del modelo en un formulario}
\r
48 cVista = class{$IFDEF DebugAlgoWars}( cObjeto ){$ENDIF}
\r
50 aFormulario: TCustomForm; // Formulario en el cual dibuja
\r
51 aRegion: HRgn; // Región del formulario en la que dibuja
\r
52 aCamara: tCamaras; // Cámara seleccionada actualmente
\r
53 aCamaras: tArrayCamaras; // Multiples cámaras
\r
54 aBitmaps: tArrayBitmaps; // Lista con los bitmaps
\r
55 aBitmapsLocked: tArrayBitmaps; // Lista con los bitmaps
\r
56 aAltaCalidad: boolean; // Indica si las imagenes se ven con transparencias.
\r
57 {$IFDEF DebugAlgoWars}
\r
58 aListaProy: cLista; // Lista de objetos proyectados (se guarda para poder
\r
59 // implementar el método mGetDebugInfo
\r
62 {** Obtiene el lado menor del formulario}
\r
63 function mGetFormLado: integer;
\r
64 {** Convierte el tamaño obtenido de la cámara a uno proporcional en píxeles}
\r
65 function mGetTam( proy: tPProy ): integer;
\r
66 {** Convierte la componente en x obtenida de la cámara a una proporcional en píxeles}
\r
67 function mGetX( proy: tPProy ): integer;
\r
68 {** Convierte la componente en y obtenida de la cámara a una proporcional en píxeles}
\r
69 function mGetY( proy: tPProy ): integer;
\r
70 {** Dibuja un ObjetoVolador}
\r
71 procedure mDibujarOV( proy: tPProy );
\r
72 {** Dibuja el ObjetoVolador lockeado por la nave propia}
\r
73 procedure mDibujarOVLockeado( proy: tPProy );
\r
74 {** Muestra un mensaje de game over}
\r
75 procedure mGameOver;
\r
76 {** Convierte un tipo tObjetosVoladores al nombre del archivo que guarda su bitmap}
\r
77 function mObjetoVoladorToFilename( obj: tObjetosVoladores ): string;
\r
78 {** Convierte un tipo tObjetosVoladores al nombre del archivo que guarda su bitmap lockeado}
\r
79 function mObjetoVoladorLockedToFilename( obj: tObjetosVoladores ): string;
\r
80 {** Crea una cámara según el tipo}
\r
81 function mCrearCamara( cam: tCamaras; ov: cObjetoVolador ): cCamara;
\r
84 constructor create( formulario: TCustomForm; ov: cObjetoVolador; calidad: boolean = true );
\r
85 {** Dibuja todos los Objetos Voladores que ve la cámara}
\r
86 procedure mDibujarVista( oEspacio: cEspacio );
\r
87 {** Define el formulario en donde dibujar}
\r
88 procedure mSetForm( oForm: TCustomForm );
\r
89 {** Setea gráficos de alta calidad}
\r
90 procedure mSetAltaCalidad;
\r
91 {** Setea gráficos de baja calidad}
\r
92 procedure mSetBajaCalidad;
\r
93 {** Invierte la calidad de los gráficos. Es decir, si estaban en baja los pone
\r
94 en alta y vice versa.}
\r
95 procedure mCambiarCalidad;
\r
96 {$IFDEF DebugAlgoWars}
\r
97 {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
98 y la información entregada depende del parámetro tDebugInfo.}
\r
99 function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;
\r
101 {** Permite realizar el cambio de camara}
\r
102 procedure mCambiarCamara( cam: tCamaras );
\r
103 {** Cambia a la siguiente cámara}
\r
104 procedure mCamaraSiguiente;
\r
105 {** Devuelve que camara esta activa}
\r
106 function mGetCamaraStr: string;
\r
107 {** Crea la cámara del arma}
\r
108 procedure mCrearCamaraDeArma( a: cArma );
\r
110 destructor destroy; override;
\r
122 @param formulario Formulario en donde dibujará la vista
\r
123 @param ov Objeto Volador en el cual montar la cámara}
\r
124 constructor cVista.create(formulario: TCustomForm; ov: cObjetoVolador; calidad: boolean);
\r
126 obj: tObjetosVoladores;
\r
131 for cam := CAMARA_FRONTAL to pred( CAMARA_ARMA ) do
\r
132 aCamaras[cam] := mCrearCamara( cam, ov );
\r
133 aCamaras[CAMARA_ARMA] := nil;
\r
134 aCamara := CAMARA_FRONTAL;
\r
135 aAltaCalidad := calidad;
\r
136 {$IFDEF DebugAlgoWars}
\r
139 mSetForm( formulario );
\r
140 // Carga gráficos Comunes
\r
141 for obj := OV_NAVEPESADA to OV_MISDIR do begin
\r
142 bitmap := TBitmap.create;
\r
143 with bitmap do begin
\r
144 LoadFromFile( mObjetoVoladorToFilename( obj ) );
\r
145 TransparentColor := clBlack;
\r
146 TransparentMode := tmFixed;
\r
147 Transparent := aAltaCalidad;
\r
149 aBitmaps[obj] := bitmap;
\r
151 // Carga gráficos Lockeados
\r
152 for obj := OV_NAVEPESADA to OV_NAVEPROPIA do begin
\r
153 bitmap := TBitmap.create;
\r
154 with bitmap do begin
\r
155 LoadFromFile( mObjetoVoladorLockedToFilename( obj ) );
\r
156 TransparentColor := clBlack;
\r
157 TransparentMode := tmFixed;
\r
158 Transparent := aAltaCalidad;
\r
160 aBitmapsLocked[obj] := bitmap;
\r
165 destructor cVista.destroy;
\r
167 obj: tObjetosVoladores;
\r
170 for cam := CAMARA_FRONTAL to CAMARA_ARMA do
\r
171 aCamaras[cam].free;
\r
172 for obj := OV_NAVEPESADA to OV_MISDIR do begin
\r
173 aBitmaps[obj].free;
\r
174 aBitmapsLocked[obj].free;
\r
176 {$IFDEF DebugAlgoWars}
\r
181 {** Dibuja un ObjetoVolador
\r
182 @param proy Puntero a un elemento del tipo tProyeccion con los datos de la proyeccion
\r
183 de un determinado objeto volador (proporcionado por la cámara)}
\r
184 procedure cVista.mDibujarOV(proy: tPProy);
\r
189 tam := mGetTam(proy);
\r
190 rect.Left := mGetX(proy);
\r
191 rect.top := mGetY(proy);
\r
192 rect.right := rect.left + tam;
\r
193 rect.bottom := rect.top + tam;
\r
194 // crea una region de dibujo //solo bmp
\r
195 // asigna la region anterior
\r
196 SelectClipRgn( aFormulario.canvas.handle, aRegion );
\r
197 // dibuja el bmp entero entre los puntos de rect o rect1
\r
198 aFormulario.canvas.StretchDraw( rect, aBitmaps[proy^.oOV.mDibujar] );
\r
201 {** Dibuja el ObjetoVolador lockeado por la nave propia
\r
202 @param proy Puntero a un elemento del tipo tProyeccion con los datos de la proyeccion
\r
203 de un determinado objeto volador (proporcionado por la cámara)}
\r
204 procedure cVista.mDibujarOVLockeado(proy: tPProy);
\r
209 tam := mGetTam(proy);
\r
210 rect.Left := mGetX(proy);
\r
211 rect.top := mGetY(proy);
\r
212 rect.right := rect.left + tam;
\r
213 rect.bottom := rect.top + tam;
\r
214 // crea una region de dibujo //solo bmp
\r
215 // asigna la region anterior
\r
216 SelectClipRgn( aFormulario.canvas.handle, aRegion );
\r
217 // dibuja el bmp entero entre los puntos de rect
\r
218 aFormulario.canvas.StretchDraw( rect, aBitmapsLocked[proy^.oOV.mDibujar] );
\r
221 {** Dibuja todos los Objetos Voladores que ve la cámara
\r
222 @param oEspacio Espacio del cual obtener la lista de objetos a interpretar por la cámara
\r
224 procedure cVista.mDibujarVista( oEspacio: cEspacio );
\r
228 {$IFNDEF DebugAlgoWars}
\r
229 aListaProy: cLista;
\r
232 {$IFDEF DebugAlgoWars}
\r
233 // Libera la lista vieja
\r
237 //mantiene el circulo negro
\r
238 aFormulario.canvas.brush.Color := clblack;
\r
239 aFormulario.canvas.ellipse( 0, 0, mGetFormLado, mGetFormLado );
\r
240 if aCamaras[aCamara] = nil then // Si es la camara es nil
\r
241 mCamaraSiguiente; // Selecciona la camara siguiente
\r
242 try // Probamos que el cameraman no este destruido
\r
243 aListaProy := aCamaras[aCamara].mProcesar( oEspacio.mGetObjetos );
\r
244 for i := 0 to aListaProy.Count - 1 do begin
\r
245 pProy := aListaProy.items[i];
\r
246 // Si el objeto volador lockeado por la nave propia es el actual...
\r
247 if oEspacio.mGetNavePropia.mGetLockeado = pProy^.oOV then
\r
248 mDibujarOVLockeado( aListaProy.items[i] ) // lo dibuja de una forma distinta
\r
250 mDibujarOV( aListaProy.items[i] ); // lo dibuja de la forma normal
\r
252 except // Si esta destruido cae en una excepcion
\r
253 on e: ENavePropiaDestruida do begin
\r
254 mGameOver; // Muestra el mensaje de GAME OVER
\r
255 raise; // Propaga la excepcion
\r
257 on e: ECameramanDestruido do begin // Si fue destruido el cameraman
\r
258 mCamaraSiguiente; // pasa a la siguiente
\r
263 {** Obtiene el lado menor del formulario
\r
264 @return El alto o el ancho del formulario, dependiendo de cual sea menor}
\r
265 function cVista.mGetFormLado: integer;
\r
267 if aFormulario.ClientWidth > aFormulario.ClientHeight then
\r
268 result := aFormulario.ClientHeight
\r
270 result := aFormulario.ClientWidth;
\r
274 {** Convierte el tamaño obtenido de la cámara a uno proporcional en píxeles
\r
275 @param proy Puntero a un elemento del tipo tProyeccion con los datos de la proyeccion
\r
276 de un determinado objeto volador (proporcionado por la cámara)
\r
277 @return Tamaño del objeto en píxeles (tamaño del lado del cuadrado que se usará para
\r
278 dibujar el bitmap)}
\r
279 function cVista.mGetTam(proy: tPProy): integer;
\r
281 // Se calcula tomando un valor de la supuesta cabina de 1/2 metro, a partir de ahi es una
\r
282 // regla de 3 simple.
\r
283 // NOTA: como los objetos quedan demasiado grandes, en vez de tomarse 1/2 metro, se toma mas pequeña
\r
284 // La dimension se multiplica por 2 porque es el radio de la nave
\r
285 // TAM = tam * (dim * 2) * (lado / 2) / 25 (metros) = tam * dim * lado / 25
\r
286 result := round( proy^.tam * proy^.oOV.mGetDimension * mGetFormLado / 25 );
\r
289 {** Convierte la componente en x obtenida de la cámara a una proporcional en píxeles
\r
290 @param proy Puntero a un elemento del tipo tProyeccion con los datos de la proyeccion
\r
291 de un determinado objeto volador (proporcionado por la cámara)
\r
292 @return Componente en X del objeto en píxeles (x de la esquina superior izquierdadel
\r
293 cuadrado que se usará para dibujar el bitmap)}
\r
294 function cVista.mGetX(proy: tPProy): integer;
\r
296 // Se calcula por medio de una regla de 3 simple teniendo en cuenta los tamaños maximos y se le
\r
297 // resta la mitad del tamaño porque se dibuja a partir de la esquina superior izquierda, no a
\r
298 // partir del centro como es en el modelo.
\r
299 result := round( proy^.x * (mGetFormLado / 2) / aCamaras[aCamara].mGetRadioPantalla + mGetFormLado / 2 ) -
\r
300 mGetTam( proy ) div 2;
\r
303 {** Convierte la componente en y obtenida de la cámara a una proporcional en píxeles
\r
304 @param proy Puntero a un elemento del tipo tProyeccion con los datos de la proyeccion
\r
305 de un determinado objeto volador (proporcionado por la cámara)
\r
306 @return Componente en Y del objeto en píxeles (y de la esquina superior izquierdadel
\r
307 cuadrado que se usará para dibujar el bitmap)}
\r
308 function cVista.mGetY(proy: tPProy): integer;
\r
310 // Se calcula por medio de una regla de 3 simple teniendo en cuenta los tamaños maximos y se le
\r
311 // resta la mitad del tamaño porque se dibuja a partir de la esquina superior izquierda, no a
\r
312 // partir del centro como es en el modelo.
\r
313 result := round( proy^.y * (mGetFormLado / 2) / aCamaras[aCamara].mGetRadioPantalla + mGetFormLado / 2 ) -
\r
314 mGetTam( proy ) div 2;
\r
317 {** Define el formulario en donde dibujar
\r
318 @param oForm Formulario en el cual dibujará la vista}
\r
319 procedure cVista.mSetForm(oForm: TCustomForm);
\r
321 aFormulario := oForm;
\r
322 aRegion := CreateEllipticRgn( 0, 0, mGetFormLado, mGetFormLado );
\r
325 {$IFDEF DebugAlgoWars}
\r
326 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos.
\r
327 @return Cadena de texto con el estado del Objeto.
\r
328 @param debugLevel Cantidad de información requerida}
\r
329 function cVista.mGetDebugInfo( debugLevel: tDebugInfo ): string;
\r
331 i: integer; // contador
\r
332 proy: tPProy; // variable temporal para obtener info de la proyeccion
\r
335 result := 'Cámara: ' + #13 + #10;
\r
336 try // Probamos que el cameraman no este destruido
\r
337 camInfo := aCamaras[aCamara].mGetDebugInfo( debugLevel );
\r
338 except // Si esta destruido cae en una excepcion
\r
339 on e: ECameramanDestruido do
\r
340 camInfo := e.Message;
\r
342 result := result + camInfo;
\r
343 // Genera el string con el estado del Espacio
\r
344 if aListaProy <> nil then begin
\r
345 for i := 0 to aListaProy.Count - 1 do begin
\r
346 proy := aListaProy.Items[i];
\r
347 result := result + #13 + #10 +
\r
348 'ObjetoVolador Proyectado ' + IntToStr( i ) + ': ' + proy^.oOV.ClassName +
\r
349 ' | X: ' + IntToStr( mGetX( proy ) ) +
\r
350 ' | Y: ' + IntToStr( mGetY( proy ) ) +
\r
351 ' | Tam: ' + IntToStr( mGetTam( proy ) );
\r
352 if debugLevel > DI_NORMAL then
\r
353 result := result + #13 + #10 +
\r
354 'X (cámara): ' + FloatToStrF( proy^.x, ffNumber, 5, 5 ) +
\r
355 ' | Y (cámara): ' + FloatToStrF( proy^.y, ffNumber, 5, 5 ) +
\r
356 ' | Tam (cámara): ' + FloatToStrF( proy^.tam, ffNumber, 5, 5 );
\r
362 {** Muestra un mensaje de game over}
\r
363 procedure cVista.mGameOver;
\r
371 rect.bottom := 250;
\r
372 // crea una region de dibujo //solo bmp
\r
373 // asigna la region anterior
\r
374 SelectClipRgn( aFormulario.canvas.handle, aRegion );
\r
375 // dibuja el bmp entero entre los puntos de rect o rect1
\r
376 bitm := TBitMap.create;
\r
377 bitm.LoadFromFile( 'bitmaps\gameover.bmp' );
\r
378 aFormulario.canvas.StretchDraw( rect, bitm );
\r
379 // canvas.stretchdraw(rect1,bitm);
\r
383 {** Convierte un tipo tObjetosVoladores al nombre del archivo que guarda su bitmap
\r
384 @param obj Tipo de objeto volador
\r
385 @return Nombre del archivo que almacena el bitmap que lo representa}
\r
386 function cVista.mObjetoVoladorToFilename(obj: tObjetosVoladores): string;
\r
388 result := ExtractFileDir( ParamStr( 0 ) ) + '\bitmaps\';
\r
390 OV_METEORITO: result := result + 'meteorito.bmp';
\r
391 OV_LASER: result := result + 'laser.bmp';
\r
392 OV_MISIL: result := result + 'misil.bmp';
\r
393 OV_MISDIR: result := result + 'misildirigido.bmp';
\r
394 OV_NAVEPROPIA: result := result + 'navepropia.bmp';
\r
395 OV_NAVEPESADA: result := result + 'navepesada.bmp';
\r
396 OV_NAVELIVIANA: result := result + 'naveliviana.bmp';
\r
397 OV_NAVEESPIA: result := result + 'naveespia.bmp';
\r
398 OV_NAVESUICIDA: result := result + 'navesuicida.bmp';
\r
399 else result := result + 'desconocido.bmp';
\r
403 {** Convierte un tipo tObjetosVoladores al nombre del archivo que guarda su bitmap lockeado
\r
404 @param obj Tipo de objeto volador
\r
405 @return Nombre del archivo que almacena el bitmap que lo representa}
\r
406 function cVista.mObjetoVoladorLockedToFilename(
\r
407 obj: tObjetosVoladores): string;
\r
409 result := ExtractFileDir( ParamStr( 0 ) ) + '\bitmaps\';
\r
411 OV_METEORITO: result := result + 'meteorito_l.bmp';
\r
412 OV_NAVEPROPIA: result := result + 'navepropia_l.bmp';
\r
413 OV_NAVEPESADA: result := result + 'navepesada_l.bmp';
\r
414 OV_NAVELIVIANA: result := result + 'naveliviana_l.bmp';
\r
415 OV_NAVEESPIA: result := result + 'naveespia_l.bmp';
\r
416 OV_NAVESUICIDA: result := result + 'navesuicida_l.bmp';
\r
417 else result := result + 'desconocido_l.bmp';
\r
421 {** Setea gráficos de alta calidad}
\r
422 procedure cVista.mSetAltaCalidad;
\r
424 if not aAltaCalidad then // Si no estan seteados como de alta calidad...
\r
428 {** Setea gráficos de baja calidad}
\r
429 procedure cVista.mSetBajaCalidad;
\r
431 if aAltaCalidad then // Si no estan seteados como de alta calidad...
\r
435 {** Invierte la calidad de los gráficos. Es decir, si estaban en baja los pone
\r
436 en alta y vice versa.}
\r
437 procedure cVista.mCambiarCalidad;
\r
439 obj: tObjetosVoladores;
\r
441 aAltaCalidad := not aAltaCalidad;
\r
442 for obj := OV_NAVEPESADA to OV_MISDIR do
\r
443 aBitmaps[obj].Transparent := aAltaCalidad;
\r
444 for obj := OV_NAVEPESADA to OV_NAVEPROPIA do
\r
445 aBitmapsLocked[obj].Transparent := aAltaCalidad;
\r
448 procedure cVista.mCambiarCamara(cam : tCamaras);
\r
450 if aCamaras[cam] <> nil then // Si esta creada es camara, la cambia
\r
454 function cVista.mGetCamaraStr: string;
\r
457 CAMARA_FRONTAL: result := 'Cámara Frontal';
\r
458 CAMARA_LATDER: result := 'Cámara Lateral Derecha';
\r
459 CAMARA_LATIZQ: result := 'Cámara Lateral Izquierda';
\r
460 CAMARA_TRASERA: result := 'Cámara Trasera';
\r
461 CAMARA_ARRIBA: result := 'Cámara Superior';
\r
462 CAMARA_ABAJO: result := 'Cámara Inferior';
\r
463 CAMARA_MAPA: result := 'Mapa del Escenario';
\r
464 CAMARA_ARMA: result := 'Cámara en el Arma';
\r
468 {** Crea una cámara según el tipo
\r
469 @param cam Tipo de Cámara
\r
470 @param ov Portador de la cámara
\r
471 @return Nueva cámara creada}
\r
472 function cVista.mCrearCamara(cam: tCamaras; ov: cObjetoVolador): cCamara;
\r
475 CAMARA_FRONTAL: result := cCamaraFrontal.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
476 CAMARA_LATDER: result := cCamaraLatDer.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
477 CAMARA_LATIZQ: result := cCamaraLatIzq.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
478 CAMARA_TRASERA: result := cCamaraTrasera.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
479 CAMARA_ARRIBA: result := cCamaraArriba.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
480 CAMARA_ABAJO: result := cCamaraAbajo.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
481 CAMARA_MAPA: result := cCamaraMapa.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
482 CAMARA_ARMA: result := cCamaraFrontal.create( ov, 1 ); // Se la crea con un poco mas de angulo que el comun
\r
486 {** Cambia a la siguiente cámara}
\r
487 procedure cVista.mCamaraSiguiente;
\r
491 cam := succ( aCamara ); // Pasa a la próxima
\r
492 if cam > CAMARA_ARMA then // Si se paso del ultimo ...
\r
493 aCamara := CAMARA_FRONTAL // Vuelve a la primera
\r
495 if cam = CAMARA_ARMA then // Si es la camara del misil...
\r
496 if aCamaras[aCamara] = nil then // Si no esta activa...
\r
497 aCamara := CAMARA_FRONTAL // Vuelve a la camara frontal
\r
498 else // si esta todo normal...
\r
500 else // si esta todo normal...
\r
504 {** Crea la cámara del arma
\r
505 @param ov Objeto Volador portador de la camara}
\r
506 procedure cVista.mCrearCamaraDeArma(a: cArma);
\r
508 if a <> nil then begin
\r
509 if aCamaras[CAMARA_ARMA] <> nil then
\r
510 aCamaras[CAMARA_ARMA].free;
\r
511 aCamaras[CAMARA_ARMA] := mCrearCamara( CAMARA_ARMA, a );
\r