• No results found

Probablemente el mayor inconveniente que presenta el mini-mapa obtenido en los apartados anteriores es que el zoom de la cámara se configura a priori (mediante su parámetro “Orthographic Scale”), y no cambia mientras el juego está corriendo. Esto obliga a adoptar un compromiso entre el nivel de detalle (deseado cuando se hacen movimientos pequeños) y el área cubierta por el mapa (se prefiere que sea grande cuando el protagonista se desplaza a gran velocidad).

Una solución a este problema es modificar el nivel de zoom en función de la velocidad del objeto protagonista, de manera que a baja velocidad haya mucho detalle, pero según se acelere la cámara se “aleje” y aumente la superficie visible. Para ello solamente es necesario acceder a las variables que contienen o definen ambas magnitudes y relacionarlas mediante una ecuación.

Implementación y control del mini-mapa de orientación

El efecto zoom de la cámara, como se ha indicado en el apartado 6.2.1, está gobernado por su parámetro “Orthographic Scale”, al tratarse de una cámara ortográfica. Su valor se consulta o modifica accediendo al atributo “ortho_scale” del objeto “camara_mapa”.

En cuanto a la velocidad de la pelota, lo más sencillo es obtenerla del atributo “worldLinearVelocity”, presente en todos los objetos del juego. Este atributo contiene un vector tridimensional con las tres componentes de la velocidad del objeto en cada momento. Como no es deseable que el zoom reaccione a los movimientos verticales (si lo hiciera, cambiaría por ejemplo al saltar), solo se tienen en cuenta las dos primeras componentes, correspondientes al plano horizontal. La manera más rápida de conocer el dato de interés, la velocidad absoluta, es crear un nuevo vector con estas dos componentes y consultar el atributo “length”, que contiene su módulo. En el script se ha denominado “velocidad_pelota”.

La relación entre esta velocidad y la escala de la cámara se establece de la siguiente manera: en vez de hacer depender la escala únicamente de la velocidad, se define como la suma de la escala que tiene inicialmente y un valor que depende de la velocidad. De esta forma es posible ajustar el valor base (el zoom cuando la pelota está parada) directamente en el visor 3D. Para ello se define una variable en el nivel superior que contenga dicha escala inicial, en este caso llamada “escala_camara_inicial”, y en cada cuadro se calcula la nueva escala (“escala_camara_deseada”) sumándole una cantidad que depende de la velocidad de la pelota (en concreto se suma el valor de la velocidad multiplicado por un una constante, “SENSIBILIDAD_ZOOM”, definida en el nivel superior). Ver Fragmento de código 46.

# Resto de asignaciones...

escala_camara_inicial = camara_mapa.ortho_scale SENSIBILIDAD_ZOOM = 3

def main():

# Resto de lógica...

velocidad_pelota = Vector(pelota.worldLinearVelocity[0:2]).length

escala_camara_deseada = escala_camara_inicial + SENSIBILIDAD_ZOOM

* velocidad_pelota

camara_mapa.ortho_scale = escala_camara_deseada

Fragmento de código 46. Control del zoom de la cámara en función de la velocidad de la pelota.

Si se añaden estos cambios a los realizados anteriormente se observará cómo efectivamente la cámara “se aleja” según la pelota acelera. Sin embargo aparece también la consecuencia indeseada de que cambios bruscos en la velocidad (que desde el punto de vista del jugador no se perciben como tal, por ejemplo un choque lateral con una pared, o pasar por escalones) ocasionan “saltos” de zoom muy notorios y molestos. Asimismo, a la vez que el resto de los objetos aparecen más pequeños según se aumenta la velocidad, el icono que representa al objeto protagonista hace lo mismo, pudiendo llegar al extremo de ser indistinguible. A continuación se explican posibles soluciones para ambos problemas.

Para suavizar los cambios bruscos de zoom se usa el método explicado en la última parte del apartado 7.6: en lugar de introducir directamente el valor calculado (“escala_camara_deseada”), se aplica una fracción de la diferencia entre dicho valor y el que “escala_camara” tiene actualmente. La fracción de la diferencia, que determina la rapidez con la que se alcanzarán los valores que debería tomar la variable si no se usara este método se controla en este caso mediante la constante “SUAVIDAD_ZOOM”, definida en el nivel superior. Su valor podrá oscilar entre 0 (el nivel de zoom no cambia) y 1 (el nivel de zoom

cambia inmediatamente). Si estos valores resultan anti intuitivos, por ser los más pequeños los que más suavidad ocasionan, la fracción puede definirse como “1- SUAVIDAD_ZOOM”. En el Fragmento de código 47 aparecen las líneas que habría que añadir al módulo para conseguir este suavizado. # Resto de asignaciones... SUAVIDAD_ZOOM = 0.1 def main(): # Resto de lógica...

escala_camara_actual = camara_mapa.ortho_scale

escala_camara_deseada = escala_camara_inicial + SENSIBILIDAD_ZOOM

* velocidad_pelota

escala_camara_final = escala_camara_actual + SUAVIDAD_ZOOM * (escala_camara_deseada - escala_camara_actual)

camara_mapa.ortho_scale = escala_camara_final

Fragmento de código 47. Control del zoom de la cámara suavizando los cambios bruscos.

En cuanto al tamaño del icono, la solución es aplicarle, en cada momento, un factor de escala que compense los cambios en el zoom de la cámara. Consiste en hacer que entre la escala que tiene el icono en cada momento y la que tiene al principio haya la misma relación que entre el valor en cada instante y el inicial de “Orthographic Scale” de la cámara. Con lo cual en un primer paso se calcula el cociente entre “escala_camara_final” y “escala_camara_inicial”, y posteriormente se multiplica el resultado (“relacion_escalas”) por “escala_icono_inicial” para obtener el valor a aplicar.

La información sobre la escala de los objetos está almacenada en sus atributos “localScale” y “worldScale”, que en este caso serán equivalentes, dado que el icono no tiene ninguna relación de parentesco. Como de estos dos solamente “localScale” es modificable desde un script, se trabajará con el mismo. Estos atributos son vectores tridimensionales pero, dado que el plano vertical no interviene en el mini-mapa, se trabaja sólo con las dos primeras componentes. Para poder multiplicar todos los elementos de un vector por un número directamente (escribiendo “vector_resultado = vector_origen * número”), es necesario

que esté representado por un objeto de clase “Vector”, ya que Python no permite multiplicar una lista de números por un número.

Implementación y control del mini-mapa de orientación

# Resto de asignaciones...

escala_icono_inicial = Vector(icono.localScale[0:2])

def main():

# Resto de lógica...

relacion_escalas = escala_camara_final/escala_camara_inicial;

escala_icono_deseada = escala_icono_inicial * relacion_escalas;

icono.localScale[0:2] = escala_icono_deseada

Fragmento de código 48. Escalado del icono que representa al objeto protagonista para que su tamaño aparente no varíe al cambiar el zoom de la cámara.

Combinando lo explicado hasta ahora se tiene un mini-mapa que cumple el objetivo principal, es decir, representar con claridad la posición del objeto protagonista en el mapa.