È una cattiva idea "mappare" la posizione del mouse sullo schermo in modo che il rilevamento delle collisioni funzioni indipendentemente dalla risoluzione?


16

Prendi in considerazione un gioco con una risoluzione predefinita di 800x600. Gli oggetti con maschere di collisione vengono posizionati in un mondo di gioco di dimensioni 800x600. Le maschere di collisione possono rilevare quando il mouse si scontra con loro.

Ora considera di ridimensionare il gioco fino a 1024x768 (supponi di ridimensionare la grafica semplicemente trasformando tutto in un livello e quindi ridimensionando l'intero livello contemporaneamente). Abbiamo due opzioni per far funzionare correttamente le collisioni con il mouse in questa nuova risoluzione:

A.) Scala il mondo a 1024x768 e ridimensiona di conseguenza la maschera di collisione di ogni oggetto.

B.) "Mappa" la posizione del mouse sul mondo originale (800x600).

Per "mappa" intendo semplicemente ridimensionare la posizione del mouse sul mondo originale 800x600. Ad esempio, se la posizione del mouse sullo schermo è (1024, 768), la posizione del mouse nel mondo è (800, 600).

Ora, ovviamente, l'opzione B richiede molto meno calcolo ed è probabilmente meno soggetta a errori geometrici, ma mi sembra anche un po '"hacker", come se ci fossero conseguenze impreviste nel seguire questo metodo che sarà un inferno da risolvere in seguito.

Quale metodo dovrei seguire: A, B o qualcos'altro?


2
Come sottolineato da Classic Thunder, le coordinate di visualizzazione non devono essere le stesse delle coordinate del mondo o delle coordinate dell'oggetto. In genere si desidera avere trasformazioni (fondamentalmente, come si dice mappature , ma in genere eseguite con la matrice matematica).
Dan

Risposte:


38

In genere (anche per i giochi 2D) esiste un sistema di coordinate separato per il gioco che è indipendente dalla risoluzione, in genere denominato spazio mondiale. Ciò consente di ridimensionare a una risoluzione arbitraria.

Il modo più semplice per raggiungere questo obiettivo è utilizzare una videocamera 2D, che è essenzialmente una matrice che definisce la transizione dallo spazio mondiale (le tue unità arbitrarie) allo spazio dello schermo (i pixel sullo schermo). Questo rende la gestione della matematica banale.

Dai un'occhiata alla sezione seguente in XNA 2d Camera Scrolling: perché usare la trasformazione a matrice?

Rende davvero facile la conversione tra le definizioni del sistema di coordinate

Per passare dallo schermo allo spazio mondiale è sufficiente utilizzare Vector2.Transform. Questo è comunemente usato per ottenere la posizione del mouse nel mondo per la raccolta degli oggetti.

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

Per passare dal mondo allo spazio dello schermo, fai semplicemente il contrario.

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

Non ci sono svantaggi nell'usare una matrice diversa da quella che richiede un po 'di apprendimento.


... e in effetti, in generale, l'hardware moderno è progettato per operazioni a matrice tramite architetture di vettorializzazione come SSE, NEON, ecc. Quindi è la scelta intelligente: risparmierai cicli della CPU su approcci non vettoriali.
Ingegnere

1
Disclaimer lieve: XNA è stato sospeso da Microsoft, ma Monogame utilizza la stessa API.
Pharap,

1
Certo, è intelligente usare le matrici per tradurre tra i due sistemi di coordinate. Ma come risponde alla domanda? Devi ancora decidere se vuoi mappare dal sistema A al sistema B o da B ad A e quali sono le conseguenze, se ce ne sono.
mastov,

"È una cattiva idea" mappare "la posizione del mouse sullo schermo in modo che il rilevamento delle collisioni funzioni indipendentemente dalla risoluzione?" risponde "è intelligente usare le matrici per tradurre tra i due sistemi di coordinate" ...
ClassicThunder

Rispondo anche "Devi ancora decidere, se vuoi mappare dal sistema A al sistema B o da B ad A e quali sono le conseguenze, se ce ne sono." dicendo che dovresti usarne uno arbitrario non legato alla risoluzione e alla scala da esso. Quindi C -> A o C -> B a seconda che A o B sia la risoluzione. Ovviamente puoi avere C uguale a una risoluzione di base che disegni e scala da lì. Il punto è che tutta la matematica avviene nello stesso sistema di coordinate e si scala solo per il rendering.
ClassicThunder

2

Un'altra opzione sarebbe: Su ogni evento di movimento del mouse di input, sposta il cursore del mouse all'interno del gioco in base al numero di pixel del gioco corrispondente al numero di pixel nell'evento del mouse. Questo è naturale per i giochi 3D che bloccano il vero puntatore del mouse verso il centro e ruotano la direzione della mira di una quantità corrispondente al movimento del mouse di input, ma puoi farlo allo stesso modo spostando uno sprite che rappresenta il cursore del mouse nel gioco.

Ovviamente devi ignorare qualsiasi evento di movimento del mouse di input causato dalla deformazione al centro, e se il tuo gioco ha qualche ritardo di input in tutto il cursore, la non rispondenza sarà l'aspetto più stonante e evidente.

In parte, quale soluzione usi dipende da quanto sia importante la posizione del mouse per il gioco. Se questo è un RTS e il giocatore sta semplicemente facendo clic per selezionare le unità, probabilmente puoi semplicemente andare con qualunque A o B sia più facile. Se è uno sparatutto top-down e il mouse controlla direttamente i movimenti del personaggio, probabilmente vorrai una soluzione più approfondita che limiti la quantità di variabilità nel modo in cui il personaggio può muoversi in base non solo alla risoluzione ma anche a cose come il movimento del mouse velocità. Se invece il mouse controlla la direzione del targeting, ti consigliamo una soluzione diversa, ecc.


0

La risposta di ClassicThunder è corretta, ma vorrei fornire un esempio di un modo alternativo / più semplice per ottenere l'effetto desiderato. Questa è una soluzione più semplice per la prototipazione rapida, i casi in cui non si ha accesso a una libreria con funzionalità complete o per i casi in cui non si ha accesso a una GPU (ad esempio nei sistemi integrati).

Per eseguire tale mapping, è possibile utilizzare la seguente funzione (si supponga che sia definito nella classe statica Helper):

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

(Non hai specificato una lingua, ma vedo che hai una certa conoscenza di C #, quindi il mio esempio è in C #.)

È quindi possibile utilizzare questa funzione in questo modo:

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);

Dove camera.Bounds un rettangolo che rappresenta l'area del mondo che la telecamera può vedere (ovvero l'area proiettata sullo schermo).

Se hai una Vectoro Pointclasse, puoi semplificare ulteriormente questo processo creando un equivalente 2D della funzione mappa, in questo modo:

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;
}

Il che renderebbe semplice il tuo codice di mappatura:

Vector mousePosInWorld = Map(Mouse.Pos, Screen.Bounds, camera.Bounds);

-1

Opzione (C): ripristina la risoluzione dello schermo a 800x600.

Anche se non lo fai, consideralo come un esperimento mentale. In tal caso, è responsabilità del display ridimensionare la grafica per adattarla alle sue dimensioni fisiche, quindi la responsabilità del sistema operativo di fornire eventi puntatore con una risoluzione di 800x600.

Penso che tutto dipenda dal fatto che la tua grafica sia bitmap o vettoriale. Se sono bitmap e si esegue il rendering in un buffer 800x600, sì, è molto più semplice rimappare il mouse nello spazio dello schermo e ignorare la risoluzione reale dello schermo. Tuttavia, il grande svantaggio di questo è che l'upscaling può sembrare brutto, specialmente se stai realizzando una grafica in stile "8 bit".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.