1 {** Implementa una cámara que se encarga de representar los objetos en 2D.<br>
\r
4 10/11/00: Se agrega el manejo de excepciones para evitar usar la camara cuando el cameraman fue destruido.
\r
5 Para lograr esto se crea una excepcion (ECameramanDestruido) que se lanza cuando hay una excepcion
\r
6 de violacion de acceso a memoria. Esta excepcion debe ser manejada por quien meneje la camara y puede
\r
7 ser lanzada por mGetDebugInfo o mProyectar.
\r
8 01/12/00: Se elimina el atributo aApertura porque era absolutamente inecesario.
\r
9 Se cambia la estructura interna para que el filtrado de los objetos los realice un cFiltro.
\r
10 07/12/00: Se agregan nuevos métodos (protegidos) para obtener información de la cámara para poder crear subclases,
\r
11 para lo cual tambien se hace virtual el método mProyectar.
\r
12 08/12/00: Se quita el método para setear el filtro y se agrega un contructor que admite un filtro para reemplazarlo.
\r
13 Se cambia esta clase para que sea abstracta. Se deja la implementacion del método mProyectar para las
\r
14 subclases exlusivamente ya que ahora es abstracto. La cámara frontal (que antes se implementaba en
\r
15 esta unidad), ahora está implementado la unidad Camaras al igual que el resto.
\r
22 {$IFDEF DebugAlgoWars}
\r
37 {** Datos de un Objeto Volador procesado por una cámara }
\r
38 tProyectado = record
\r
39 oOV: cObjetoVolador;
\r
45 {** Puntero a tProyectado}
\r
46 tPProy = ^tProyectado;
\r
48 {** Excepcion producida por la cámara si se utiliza cuando el cameraman fue destruido}
\r
49 ECameramanDestruido = class( Exception )
\r
55 {** Implementa una cámara que se encarga de representar los objetos en 2D.}
\r
56 cCamara = class{$IFDEF DebugAlgoWars}( cObjeto ){$ENDIF}
\r
58 aCameraman: cObjetoVolador; // Objeto volador que porta la camara
\r
59 aRadioMaximo: tLongitud; // Alcance maximo de la camara (los
\r
60 // objetos mas lejanos no se veran)
\r
61 aRadioMinimo: tLongitud; // Alcance minimo de la camara (los
\r
62 // objetos mas cercanos no se veran)
\r
63 // Estos 3 ultimos atributos están ligados entre si (y son en parte redundantes)
\r
64 aRadioPantalla: tLongitud; // Radio de la pantalla.
\r
65 aDistPantalla: tLongitud; // Distancia (mínima) hasta la pantalla
\r
66 aCosApertura: tAngulo; // Coseno del Angulo de vision de la camara,
\r
67 // se almacena sólo el coseno porque el
\r
68 // ángulo en sí no se usa.
\r
69 aFiltro: cFiltro; // Filtro que utiliza la cámara para evaluar
\r
70 // cuales objetos están visibles y cuales no.
\r
73 {** Obtiene la proyección del objeto volador en X, Y}
\r
74 procedure mProyectar(ov: cObjetoVolador; var x, y, tam: tLongitud); virtual; abstract;
\r
75 {** Devuelve el objeto portador de la cámara}
\r
76 function mGetCameraman: cObjetoVolador;
\r
77 {** Permite asignar un nuevo portador de la cámara}
\r
78 procedure mSetCameraman( oOV: cObjetoVOlador );
\r
79 {** Devuelve distancia a la pantalla}
\r
80 function mGetDistPantalla: tLongitud;
\r
81 {** Devuelve el radio mínimo de detección}
\r
82 function mGetRadioMinimo: tLongitud;
\r
83 {** Devuelve el radio máximo de detección}
\r
84 function mGetRadioMaximo: tLongitud;
\r
85 {** Asigna un nuevo filtro}
\r
86 Procedure mSetFiltro( filtro: cFiltro );
\r
89 constructor create( cameraman: cObjetoVolador; angulo: tAngulo = PI/4; maximo: tLongitud = 5000; distPantalla: tLongitud = 0 ); overload;
\r
90 {** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado
\r
91 ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).}
\r
92 function mProcesar( l: TList ): cLista;
\r
93 {$IFDEF DebugAlgoWars}
\r
94 {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
95 y la información entregada depende del parámetro tDebugInfo.}
\r
96 function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;
\r
98 {** Obtiene el radio de la pantalla}
\r
99 function mGetRadioPantalla: tLongitud;
\r
109 {** Funcion para ordenar los elementos de la lista que se devuelve
\r
110 @param item1 Item a comparar (puntero)
\r
111 @param item2 Item a comparar (puntero)
\r
112 @return <b>1</b> si item1 > item2<br>
\r
113 <b>-1</b> si item1 < item2<br>
\r
114 <b>0</b> si item1 = item2}
\r
115 function listSort( item1, item2: pointer ): integer;
\r
120 p1 := tPProy( item1 );
\r
121 p2 := tPProy( item2 );
\r
123 if p1^.tam > p2^.tam then
\r
126 if p1^.tam < p2^.tam then
\r
133 @param cameraman Objeto Volador en el que estará montada la cámara (obligatorio)
\r
134 @param angulo Angulo de apertura (visión) de la cámara (default = pi/4)
\r
135 @param maximo Distancia máxima en la que se considera visible a un objeto (default = 5000)
\r
136 @param distPantalla Distancia hasta la pantalla de proyección (default = 0). Si tiene el valor por default
\r
137 o cualquier valor menor o igual a cero, se usa el tamaño del objeto volador}
\r
138 constructor cCamara.create(cameraman: cObjetoVolador;
\r
139 angulo: tAngulo; maximo: tLongitud;
\r
140 distPantalla: tLongitud );
\r
143 aCameraman := cameraman;
\r
144 aRadioMaximo := maximo;
\r
145 aCosApertura := cos( angulo );
\r
146 if distPantalla > 0 then begin // Si la distancia es positiva, se la asigna y calcula el radio minimo
\r
147 aDistPantalla := distPantalla;
\r
148 // El radio minimo se calcula basado en la formula sen(a) = adyacente / HIPOTENUSA
\r
149 aRadioMinimo := aDistPantalla / sin( angulo );
\r
150 end else begin // Si es negativo o cero (se paso como default o mal), lo extrae del objeto volador
\r
151 aRadioMinimo := aCameraman.mGetDimension;
\r
152 // La distancia a la pantalla se calcula basado en la formula sen(a) = ADYACENTE / hipotenusa
\r
153 aDistPantalla := sin( angulo ) * aRadioMinimo;
\r
155 // El radio de la pantalla se calcula basado en la formula cos(a) = OPUESTO / hipotenusa
\r
156 aRadioPantalla := aCosApertura * aRadioMinimo;
\r
157 // Crea un filtro frontal
\r
158 aFiltro := cFiltroFrontal.create( aCameraman, angulo, aRadioMaximo, aRadioMinimo )
\r
161 {** Procesa una lista de objetos, devolviendo solo los visibles en una lista de records tProyectado
\r
162 ordenada ascendentemente por el tamaño proporcional (es decir, el objeto de tamaño menor está primero en la lista).
\r
163 @return Lista con los objetos visibles y sus posiciones y tamaños, en un registro
\r
164 del tipo <i>tProyectado</i>, ordenados de forma ascendente según el tamaño.
\r
165 @param l Lista con los objetos a procesar}
\r
166 function cCamara.mProcesar( l: TList ): cLista;
\r
169 lProcesada: cLista;
\r
171 oOV: cObjetoVolador;
\r
176 sort: TListSortCompare;
\r
179 lProcesada := cLista.create;
\r
181 lFiltrada := aFiltro.mFiltrar( l );
\r
183 on e: EObservadorDestruido do
\r
184 raise ECameramanDestruido.create;
\r
186 for i:=0 to lFiltrada.count - 1 do begin // recorre la lista de objetos
\r
187 oOV := lFiltrada.items[i]; // obtiene el ObjetoVolador actual
\r
189 mProyectar( oOV, x, y, tam );
\r
194 lProcesada.Add( proy );
\r
197 lProcesada.Sort( sort );
\r
198 result := lProcesada;
\r
202 {$IFDEF DebugAlgoWars}
\r
203 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos:<br>
\r
204 Siempre devuelve los valores de las componentes x, y, z y si debugLevel es mayor que DI_NORMAL,
\r
205 también muestra el módulo.
\r
206 @return Cadena de texto con el estado del Objeto.
\r
207 @param debugLevel Cantidad de información requerida}
\r
208 function cCamara.mGetDebugInfo( debugLevel: tDebugInfo ): string;
\r
210 // Construye la cadena dependiendo de la cantidad de informacion que se quiera obtener
\r
211 result := 'Radio Máximo: ' + FloatToStrF( aRadioMaximo, ffNumber, 5, 5 ) +
\r
212 ' | Radio Mínimo: ' + FloatToStrF( aRadioMinimo, ffNumber, 5, 5 ) +
\r
213 ' | Radio de Pantalla: ' + FloatToStrF( aRadioPantalla, ffNumber, 5, 5 ) +
\r
214 ' | Distancia de Pantalla: ' + FloatToStrF( aDistPantalla, ffNumber, 5, 5 );
\r
215 try // Probamos que el cameraman no este destruido
\r
216 if debugLevel = DI_NORMAL then
\r
217 result := result + #13 + #10 +
\r
218 'Cameraman: ' + aCameraman.mGetDebugInfo;
\r
219 if debugLevel = DI_MAXI then
\r
220 result := result + #13 + #10 +
\r
221 'Cameraman: ' + aCameraman.mGetDebugInfo( debugLevel ); // + #13 + #10 +
\r
222 except // Si esta destruido cae en una excepcion
\r
223 on e: EAccessViolation do
\r
224 raise ECameramanDestruido.create; // Creamos una nueva excepcion especial
\r
229 {** Obtiene el radio de la pantalla
\r
230 @return Radio de la pantalla}
\r
231 function cCamara.mGetRadioPantalla: tLongitud;
\r
233 result := aRadioPantalla;
\r
236 {** Devuelve el objeto portador de la cámara
\r
237 @return Objeto portador de la cámara}
\r
238 function cCamara.mGetCameraman: cObjetoVolador;
\r
240 result := aCameraman;
\r
243 {** Permite asignar un nuevo portador de la cámara
\r
244 @param oOV Objeto volador que será en nuevo portador de la cámara}
\r
245 procedure cCamara.mSetCameraman(oOV: cObjetoVOlador);
\r
248 aFiltro.mSetObservador( oOV );
\r
251 {** Devuelve distancia a la pantalla
\r
252 @return Distancia a la pantalla}
\r
253 function cCamara.mGetDistPantalla: tLongitud;
\r
255 result:=aDistPantalla;
\r
258 {** Devuelve el radio mínimo de detección
\r
259 @return Radio mínimo de detección}
\r
260 function cCamara.mGetRadioMaximo: tLongitud;
\r
262 result:=aRadioMaximo;
\r
265 {** Devuelve el radio máximo de detección
\r
266 @return Radio máximo de detección}
\r
267 function cCamara.mGetRadioMinimo: tLongitud;
\r
269 result:=aRadioMinimo;
\r
272 {** Asigna un nuevo filtro}
\r
273 procedure cCamara.mSetFiltro(filtro: cFiltro);
\r
279 { ECameramanDestruido }
\r
282 constructor ECameramanDestruido.create;
\r
284 inherited create( 'El Cameraman fue destruido.' );
\r