¿Es una mala idea "mapear" la posición del mouse en la pantalla para que la detección de colisión funcione independientemente de la resolución?

16

Considere un juego cuya resolución predeterminada es 800x600. Los objetos con máscaras de colisión se colocan en un mundo de juego de tamaño 800x600. Las máscaras de colisión pueden detectar cuándo el mouse colisiona con ellas.

Ahora considere que escalamos el juego hasta 1024x768 (supongamos que escalamos los gráficos simplemente renderizando todo en una capa y luego escalando toda la capa a la vez). Tenemos dos opciones para hacer que las colisiones con el mouse funcionen correctamente en esta nueva resolución:

A.) Escala el mundo a 1024x768 y escala la máscara de colisión de cada objeto en consecuencia.

B.) "Asigna" la posición del mouse al mundo original (800x600).

Por "mapa" quiero decir simplemente escalar la posición del mouse en el mundo original de 800x600. Entonces, por ejemplo, si la posición del mouse en la pantalla es (1024, 768), entonces la posición del mouse en el mundo es (800, 600).

Ahora, obviamente, la opción B requiere mucho menos cómputo y probablemente sea menos propensa a errores geométricos, pero también me parece un poco "hack", ya que hay consecuencias imprevistas de seguir con este método que será un infierno solucionar más adelante.

¿Con qué método debo ir: A, B u otra cosa?

user3002473
fuente
2
Como señaló Classic Thunder, las coordenadas de visualización no deberían ser las mismas que las coordenadas mundiales o las coordenadas de los objetos. Por lo general, desea tener transformaciones (básicamente, como dice asignaciones , pero generalmente se hace con matemáticas de matriz).
Dan

Respuestas:

38

Típicamente (incluso para juegos 2D) hay un sistema de coordenadas separado para el juego que es independiente de la resolución, esto se conoce como el espacio mundial. Esto le permite escalar a una resolución arbitraria.

La forma más fácil de lograr esto es usar una cámara 2D, que es esencialmente una matriz que define la transición del espacio mundial (sus unidades arbitrarias) al espacio de la pantalla (los píxeles en la pantalla). Esto hace que tratar con las matemáticas sea trivial.

Eche un vistazo a la sección a continuación en Desplazamiento de cámara XNA 2d: ¿por qué usar transformación de matriz?

Hace que sea muy fácil convertir entre definiciones de sistema de coordenadas

Para ir de la pantalla al espacio mundial simplemente use Vector2.Transform. Esto se usa comúnmente para obtener la ubicación del mouse en el mundo para la selección de objetos.

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));

Para ir del mundo al espacio de la pantalla, simplemente haga lo contrario.

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

No hay inconvenientes para usar una matriz que no sea un poco de aprendizaje.

Trueno clásico
fuente
... y, en términos generales, el hardware moderno está diseñado para operaciones matriciales a través de arquitecturas de vectorización como SSE, NEON, etc. Por lo tanto, es la elección inteligente: ahorrará ciclos de CPU en los enfoques no vectorizados.
Ingeniero
1
Descargo de responsabilidad leve: XNA fue descontinuado por microsoft, pero Monogame usa la misma API.
Pharap
1
Claro, es inteligente usar matrices para traducir entre los dos sistemas de coordenadas. Pero, ¿cómo responde eso a la pregunta? Aún debe decidir si desea asignar del sistema A al sistema B o de B a A y cuáles son las consecuencias, si las hay.
mastov
"¿Es una mala idea" mapear "la posición del mouse en la pantalla para que la detección de colisión funcione independientemente de la resolución?" es respondido por "es inteligente usar matrices para traducir entre los dos sistemas de coordenadas" ...
ClassicThunder
También respondo: "Aún debe decidir si desea asignar del sistema A al sistema B o de B a A y cuáles son las consecuencias, si las hay". diciendo que debe usar uno arbitrario que no esté relacionado con la resolución y la escala de la misma. Entonces C -> A o C -> B dependiendo de si A o B es la resolución. Por supuesto, puede hacer que C sea igual a una resolución base que diseñe y escale desde allí. El punto es que todas las matemáticas suceden en el mismo sistema de coordenadas y solo se escala para la representación.
ClassicThunder
2

Otra opción sería: en cada evento de movimiento del mouse de entrada, mueva el cursor del mouse en el juego por el número de píxeles del juego correspondiente al número de píxeles en el evento del mouse. Esto es natural para los juegos 3D que bloquean el puntero real del mouse en el centro y giran la dirección del objetivo en una cantidad correspondiente al movimiento del mouse de entrada, pero puede hacerlo de la misma manera moviendo un sprite que representa el cursor del mouse en el juego.

Obviamente, debe ignorar los eventos de movimiento del mouse de entrada causados ​​por deformarlo hacia el centro, y si su juego tiene algún retraso de entrada, la falta de respuesta del cursor será el aspecto más discordante y notable.

Parcialmente, la solución que use dependerá de la importancia de la posición del mouse para el juego. Si se trata de un RTS y el jugador simplemente está haciendo clic para seleccionar unidades, probablemente pueda simplemente elegir el A o B que sea más fácil. Si es un tirador de arriba hacia abajo y el mouse controla directamente los movimientos del personaje, entonces probablemente querrás una solución más profunda que limite la cantidad de variabilidad en la forma en que el personaje puede moverse en función no solo de la resolución, sino también de cosas como el movimiento del mouse velocidad. Si el mouse controla la dirección de orientación, entonces querrás una solución diferente, etc.

Aleatorio832
fuente
0

La respuesta de ClassicThunder es correcta, pero me gustaría proporcionar un ejemplo de un medio alternativo / más simple para lograr el efecto deseado. Esta es una solución más simple para la creación rápida de prototipos, en los casos en que no tiene acceso a una biblioteca con todas las funciones, o en los casos en que no tiene acceso a una GPU (por ejemplo, en sistemas integrados).

Para realizar dicha asignación, puede utilizar la siguiente función (suponga que se define en la clase estática Helper):

static float Map(float value, float fromLow, float fromHigh, float toLow, float toHigh)
{
    return ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)) + toLow;
}

(No especificó un idioma, pero veo que tiene algún conocimiento de C #, por lo que mi ejemplo está en C #).

Luego puede usar esta función así:

float mouseXInWorld = Helper.Map(Mouse.X, 0, Screen.Width - 1, camera.Bounds.X, camera.Bounds.X + camera.Bounds.Width - 1);
float mouseYInWorld = Helper.Map(Mouse.Y, 0, Screen.Height - 1, camera.Bounds.Y, camera.Bounds.Y + camera.Bounds.Height - 1);

Donde camera.Boundshay un rectángulo que representa el área del mundo que la cámara puede ver (es decir, el área que se proyecta en la pantalla).

Si tiene una clase Vectoro Point, podría simplificar aún más este proceso creando un equivalente 2D de la función de mapa, de esta manera:

static Vector Map(Vector value, Rectangle fromArea, Rectangle toArea)
{
    Vector result = new Vector();
    result.X = Map(value.X, fromArea.X, fromArea.X + fromArea.Width - 1, toArea.X, toArea.X + toArea.Width - 1);
    result.Y = Map(value.Y, fromArea.Y, fromArea.Y + fromArea.Height - 1, toArea.Y, toArea.Y + toArea.Height - 1);
    return result;
}

Lo que haría que su código de mapeo sea simple:

Vector mousePosInWorld = Map(Mouse.Pos, Screen.Bounds, camera.Bounds);
Pharap
fuente
-1

Opción (C): cambie la resolución de la pantalla a 800x600.

Incluso si no haces esto, considéralo como un experimento mental. En ese caso, es responsabilidad de la pantalla cambiar el tamaño de los gráficos para que se ajusten a su tamaño físico, y luego es responsabilidad del sistema operativo proporcionarle eventos de puntero con una resolución de 800x600.

Creo que todo depende de si sus gráficos son bitmap o vectoriales. Si son mapas de bits y está renderizando a un búfer de 800x600, entonces sí, es mucho más fácil reasignar el mouse al espacio de la pantalla e ignorar la resolución real de la pantalla. Sin embargo, la gran desventaja de esto es que la ampliación puede parecer fea, especialmente si está haciendo gráficos de estilo de "8 bits" en bloques.

pjc50
fuente