Como se comentó anteriormente, una vez se detecte un choque (en realidad se detecta la proximidad de otro objeto), si la pelota era visible en el momento de la detección, se debe impedir que se aplique a la cámara una velocidad lateral del mismo signo que la que llevaba antes de chocar, de manera que no atraviese el objeto contra el que ha chocado. Por el contrario, si la pelota no era visible se debe permitir que la cámara atraviese la pared, ya que el objetivo del desplazamiento lateral será recuperar la visibilidad.
En el módulo correspondiente (en este caso “control_camara_3.py”), la lógica necesaria en cada cuadro se distribuye en tres secciones (ver Fragmento de código 22):
Control de la cámara
- En primer lugar se interpretan el estado del sensor “Near” (llamado “sensor_camara_cerca_lateral”) y el resultado del método “rayCastTo”: si el sensor “Near” es positivo, es decir hay otro objeto cerca (en este caso sólo puede ser una pared), la variable “pared_cerca_lateral” es verdadera, y viceversa; si el método “rayCastTo” devuelve un objeto distinto de la pelota, la variable “hay_obstaculo” será verdadera, en caso contrario falsa.
- A continuación se deduce, con base en lo anterior, si es necesario bloquear la velocidad lateral, y en caso afirmativo, qué sentido (sólo se debe evitar que la cámara se siga desplazando hacia la pared). La información del resultado de este bloque se guarda en la variable “parar_velocidad_lateral”, que indica si hay que evitar las velocidades laterales negativas (cuando su valor es -1), positivas (1) o si no hay que hacerlo, en función de la velocidad lateral de la cámara en el cuadro anterior. Esta variable debe perdurar entre cuadros: mientras la cámara esté cerca de una pared deberá seguir evitándose que se acerque a ella, sin embargo una vez que se ha parado no podría saberse, si no perdurase, la velocidad que llevaba antes de chocar (“velocidad_lateral_anterior” sería nula); por tanto “parar_velocidad_lateral” debe mantener el mismo valor mientras el sensor “Near” esté activo. Los pasos que se dan son los siguientes:
• Si se detecta la cercanía de otro objeto, y la pelota está visible, la variable “parar_velocidad_lateral” será 1 o -1, y habrá que deducir su valor. Si no, será nula.
• En caso de que se haya detectado, si la variable “parar_velocidad_lateral” era nula anteriormente (el actual es el primer cuadro en que se detecta el choque) habrá que calcular su valor; si no, se mantiene el anterior.
• En caso de que fuera nula, su nuevo valor será -1 si la velocidad lateral que llevaba la cámara anteriormente “velocidad_lateral_anterior” era negativa, 1 en caso contrario. Esta lógica de decisión es adecuada para conseguir un comportamiento correcto en la mayoría de los casos, pero fallará en situaciones donde la cámara esté cerca de una pared y no se haya movido el ratón con anterioridad, ya que “velocidad_lateral_anterior” será nula. La solución es tomar la decisión en función del sentido de giro sobre sí misma de la cámara (la cámara gira tanto cuando se mueve la pelota como cuando se mueve ella misma). El cálculo del sentido de giro se cubre en el apartado 5.6.2 (página 71), por lo que a partir de entonces esta decisión se tomará basándose en el mismo.
• Si se cumplen las condiciones anteriores pero la cámara acaba de atravesar una pared (recordar que se permite si la pelota no es visible), el signo de la velocidad a evitar no será el que llevaba en el cuadro anterior, si no el contrario. Para saber si se da esta situación hay que comprobar la variable “pelota_visible_cuadro_anterior”, que es global y se define al final de este
bloque lógico como el contrario de “hay_obstaculo”; si es falsa efectivamente se acaba de atravesar una pared, y por tanto habrá que invertir el valor de “parar_velocidad_lateral”.
- Posteriormente se ejecuta el resto de la lógica con normalidad, calculado todas las velocidades correspondientes en cada cuadro. Aunque en este caso el orden de estos dos primeros bloques podría haberse invertido, posteriormente se añadirán funcionalidades que dependan del estado de “parar_velocidad_lateral”, por lo que debe definirse previamente.
- Por último, justo antes de aplicar finalmente las velocidades, es necesario determinar si la lateral se debe anular o no: si “parar_velocidad_lateral” no es nula, y la velocidad lateral que se ha calculado en función del movimiento del ratón tiene su mismo signo, así deberá hacerse, pasando a ser “velocidad_lateral_final” igual a cero. La igualdad de signos se comprueba mediante la función “coinciden_signos”, (apartado 7.9.5, página 153)
En el Fragmento de código 22 aparece toda la lógica relacionada con lo anterior. Se recomienda observarlo con atención para entender su funcionamiento, siguiendo los caminos que se siguen en función de diferentes situaciones. Para probar el comportamiento en el fichero de ejemplo se deben activar tanto la primera parte de la función “main” del módulo “control_camara_3.py”, que contiene la interpretación de los sensores, del método “rayCast” y la decisión del sentido de giro a evitar, como el bloque que decide si finalmente se debe anular la velocidad lateral que se ha calculado, titulado “Parar velocidad lateral”.
Control de la cámara
# Resto de asignaciones...
parar_velocidad_lateral = 0
pelota_visible_cuadro_anterior = 0
sensor_camara_cerca_lateral =
camara_principal.sensors['cerca_lateral']
sensor_camara_cerca_lateral.distance = 1 sensor_camara_cerca_lateral.resetDistance = 1 def main(): global velocidad_lateral_anterior global parar_velocidad_lateral global pelota_visible_cuadro_anterior
# Interpretar estado del sensor y resultado del método
pared_cerca_lateral = sensor_camara_cerca_lateral.positive hay_obstaculo = False if camara_principal.rayCastTo(pelota) ==
pelota else True
# Deducir qué sentido de giro se debe evitar
if pared_cerca_lateral and not hay_obstaculo:
if parar_velocidad_lateral == 0: parar_velocidad_lateral = 1 if velocidad_lateral_anterior > 0 else -1 if not pelota_visible_cuadro_anterior: parar_velocidad_lateral = - parar_velocidad_lateral else: parar_velocidad_lateral = 0 pelota_visible_cuadro_anterior = 1 - hay_obstaculo # Resto de lógica...
# Decidir si la velocidad lateral calculada se debe aplicar o no
if parar_velocidad_lateral: if coinciden_signos(parar_velocidad_lateral, velocidad_lateral_final): velocidad_lateral_final = 0 # Resto de lógica...
Fragmento de código 22. Tratamiento de los choques causados por un desplazamiento lateral.