2012-03-21 5 views
11

Sto lavorando a un gioco di trading spaziale 3D con alcune persone, e una delle cose che mi è stato assegnato è creare un tunnel di guida che il la nave viaggia attraverso, con il tunnel fatto di quadrati che l'utente vola verso la loro destinazione, aumentando di numero man mano che l'utente si avvicina alla destinazione.Targeting per computer di orientamento simulatore spaziale con quadrante concentrico

È solo necessario rendere i quadrati per i punti davanti alla nave, poiché è tutto ciò che è visibile all'utente. Sulla loro strada verso una destinazione, il computer della nave dovrebbe piazzare quadrati sull'HUD che rappresentano punti fissi nello spazio tra te e la destinazione, che sono piccoli in lontananza e diventano più grandi man mano che i punti si avvicinano all'aereo.

guidance squares example

che ho avuto un andare a implementare questo e non riesco a capirlo, utilizzando prevalentemente logaritmi (Math.log10(x) e tali). Ho cercato di ottenere la posizione della nave in "spazio logaritmico" per scoprire da quale indice iniziare quando disegno i quadrati, ma poi il fatto che ho solo una distanza dalla destinazione per lavorare confonde la questione, specialmente quando considera che il numero di quadrati deve variare dinamicamente per assicurarsi che rimangano fissi nelle posizioni giuste nello spazio (cioè i quadrati sono posizionati a intervalli di circa 200 prima di essere trasformati logaritmicamente).

Riguardo a ciò, ho avuto un'implementazione funzionante con la nave tra un inizio di 0.0d e la fine di 1.0d, sebbene l'implementazione non fosse così bella. Ad ogni modo, il problema si riduce essenzialmente alla natura 1d. Qualsiasi consiglio sarebbe apprezzato con questo problema, compresi possibili soluzioni alternative per ottenere lo stesso effetto o soluzioni.

Frontier: Elite 2

(Inoltre, c'è un video di Youtube che mostra questo effetto: http://www.youtube.com/watch?v=79F9Nj7GgfM&t=3m5s)

Cheers,
Chris

Edit: riformulato l'intera questione.

Edit: nuovo codice banco di prova:

package st; 

import java.awt.BorderLayout; 
import java.awt.Canvas; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GraphicsDevice; 
import java.awt.GraphicsEnvironment; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.image.BufferStrategy; 
import java.text.DecimalFormat; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

public class StUI2 extends JFrame { 
    public static final double DEG_TO_RAD = Math.PI/180.0d; 
    public static final DecimalFormat decimalFormat = new DecimalFormat("0.0000"); 

    public static final Font MONO = new Font("Monospaced", Font.PLAIN, 10); 

    public class StPanel extends Canvas { 
     protected final Object imgLock = new Object(); 
     protected int lastWidth = 1, lastHeight = 1; 
     protected boolean first = true; 
     protected Color bgColour = Color.DARK_GRAY, gridColour = Color.GRAY; 

     double shipWrap = 700; 
     double shipFrame = 100; 
     double shipPos = 0; 
     long lastUpdateTimeMS = -1; 
     long currUpdateTimeMS = -1; 

     public StPanel() {  
      setFocusable(true); 
      setMinimumSize(new Dimension(1, 1)); 
      setAlwaysOnTop(true); 
     } 

     public void internalPaint(Graphics2D g) { 
      synchronized (imgLock) { 
       if (lastUpdateTimeMS < 0) { 
        lastUpdateTimeMS = System.currentTimeMillis(); 
       } 
       currUpdateTimeMS = System.currentTimeMillis(); 
       long diffMS = currUpdateTimeMS - lastUpdateTimeMS; 

       g.setFont(MONO); 

       shipPos += (60d * ((double)diffMS/1000)); 
       if (shipPos > shipWrap) { 
        shipPos = 0d; 
       } 

       double shipPosPerc = shipPos/shipWrap; 
       double distToDest = shipWrap - shipPos; 
       double compression = 1000d/distToDest; 

       g.setColor(bgColour); 
       Dimension d = getSize(); 
       g.fillRect(0, 0, (int)d.getWidth(), (int)d.getHeight()); 

       //int amnt2 = (int)unlog10((1000d/distToDest)); 

       g.setColor(Color.WHITE); 
       g.drawString("shipPos: " + decimalFormat.format(shipPos),  10, 10); 
       g.drawString("distToDest: " + decimalFormat.format(distToDest), 10, 20); 

       g.drawString("shipWrap: " + decimalFormat.format(shipWrap), 150, 10); 

       int offset = 40; 

       g.setFont(MONO); 

       double scalingFactor = 10d; 

       double dist = 0; 
       int curri = 0; 
       int i = 0; 
       do { 
        curri = i; 
        g.setColor(Color.GREEN); 

        dist = distToDest - getSquareDistance(distToDest, scalingFactor, i); 
        double sqh = getSquareHeight(dist, 100d * DEG_TO_RAD); 
        g.drawLine(30 + (int)dist, (offset + 50) - (int)(sqh/2d), 30 + (int)dist, (offset + 50) + (int)(sqh/2d)); 
        g.setColor(Color.LIGHT_GRAY); 
        g.drawString("i: " + i + ", dist: " + decimalFormat.format(dist), 10, 120 + (i * 10)); 
        i++; 
       } while (dist < distToDest); 

       g.drawLine(10, 122, 200, 122); 
       g.drawString("last/i: " + curri + ", dist: " + decimalFormat.format(dist), 10, 122 + (i * 10)); 

       g.setColor(Color.MAGENTA); 
       g.fillOval(30 + (int)shipPos, offset + 50, 4, 4); 

       lastUpdateTimeMS = currUpdateTimeMS; 
      } 
     } 

     public double getSquareDistance(double initialDist, double scalingFactor, int num) { 
      return Math.pow(scalingFactor, num) * num * initialDist; 
     } 

     public double getSquareHeight(double distance, double angle) { 
      return distance/Math.tan(angle); 
     } 

     /* (non-Javadoc) 
     * @see java.awt.Canvas#paint(java.awt.Graphics) 
     */ 
     @Override 
     public void paint(Graphics g) { 
      internalPaint((Graphics2D)g); 
     } 

     public void redraw() { 
      synchronized (imgLock) { 
       Dimension d = getSize(); 
       if (d.width == 0) d.width = 1; 
       if (d.height == 0) d.height = 1; 

       if (first || d.getWidth() != lastWidth || d.getHeight() != lastHeight) { 
        first = false; 

        // remake buf 
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
        //create an object that represents the device that outputs to screen (video card). 
        GraphicsDevice gd = ge.getDefaultScreenDevice(); 
        gd.getDefaultConfiguration(); 

        createBufferStrategy(2); 

        lastWidth = (int)d.getWidth(); 
        lastHeight = (int)d.getHeight(); 
       } 

       BufferStrategy strategy = getBufferStrategy(); 
       Graphics2D g = (Graphics2D)strategy.getDrawGraphics(); 
       internalPaint(g); 
       g.dispose(); 
       if (!strategy.contentsLost()) strategy.show(); 
      } 
     } 
    } 

    protected final StPanel canvas; 

    protected Timer viewTimer = new Timer(1000/60, new ActionListener() {  
     @Override 
     public void actionPerformed(ActionEvent e) { 
      canvas.redraw(); 
     } 
    }); 
    { 
     viewTimer.setRepeats(true); 
     viewTimer.setCoalesce(true); 
    } 

    /** 
    * Create the applet. 
    */ 
    public StUI2() { 
     JPanel panel = new JPanel(new BorderLayout()); 
     setContentPane(panel); 
     panel.add(canvas = new StPanel(), BorderLayout.CENTER); 
     setVisible(true); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setSize(800, 300); 
     setTitle("Targetting indicator test #2"); 
     viewTimer.start(); 
    } 

    public static double unlog10(double x) { 
     return Math.pow(10d, x); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       StUI2 ui = new StUI2(); 
      } 
     }); 
    } 
} 
+1

1) Non mescolare Swing ('JApplet') e AWT (componenti' Canvas'). 2) Un'applet è leggermente più difficile da testare per gli altri. Si prega di considerare lo sviluppo utilizzando un'applicazione/applet ibrida. 3) Hai una domanda? Che cos'è? –

+1

OK. Ora ho eseguito il codice. Oltre alla domanda, non sono ancora chiaro su cosa dovrebbe accadere. I punti rosso e giallo dovrebbero essere allineati? Anche il mestiere magenta si muove da sinistra a destra. Il modello giallo è presumibilmente ciò che il pilota vede dalla finestra frontale (sarebbe proiettato sulla parete destra dalla nostra prospettiva)? –

+0

Sì, sarebbe l'ideale se i punti rosso e giallo fossero allineati. Devo produrre una piccola sottosezione dei punti rossi, che * dovrebbe * essere i punti gialli. Dovrebbero rimanere in punti fissi nello spazio sul percorso target relativo alla distanza dal bersaglio. –

risposta

10

Supponendo che si desidera che le piazze di essere uguale altezza (quando li raggiunge), è possibile calcolare un fattore di scala in base alla distanza dalla destinazione (d) e l'altezza richiesta dei quadrati al loro arrivo (h).

Da queste due informazioni è possibile calcolare la tangente inversa (atan) dell'angolo (alpha) tra la linea che collega la nave alla destinazione (linea orizzontale nella vostra immagine) e la linea che collega la parte superiore delle piazze con la destinazione (linea angolata nell'immagine).

EDIT: corretto
formula Utilizzando l'angolo, si può calcolare l'altezza della piazza (h') in qualsiasi data distanza dalla destinazione: si conosce la distanza dalla destinazione (d') e l'angolo (alpha); L'altezza del quadrato a distanza d' è h'=r'*sin(alpha) - sin(alpha)=cos(alpha)*tan(alpha) e r'=d'/cos(alpha) (la distanza tra la destinazione e la parte superiore del quadrato - il "raggio"). O più facilmente: h'=d'*tan(alpha).

Nota: adottando l'algoritmo di altezza variabile (quando li raggiunge) quadrati è relativamente semplice: il calcolo dell'angolo, appena assumere un (phantom) quadrato dell'altezza fissa e scalare i quadrati relativamente a questo.

Se l'altezza del quadrato alla distanza d' viene calcolata per te dalla libreria grafica, tanto meglio, è sufficiente calcolare le distanze per posizionare i quadrati.

Quali distanze per posizionare i quadrati dalla destinazione?

1) Se si desidera visualizzare un numero variabile di quadrati (davanti alla nave), ma potenzialmente un numero infinito di quadrati da considerare (in base a d), è possibile scegliere la distanza del quadrato più vicino alla destinazione (d1) e calcolare le distanze degli altri quadrati con la formula s^k*k*d1, dove s (fattore di scala) è un numero> 1 per il numero (numero dalla destinazione). È possibile interrompere l'algoritmo quando il risultato è maggiore di d.

Si noti che se d è sufficientemente grande, i quadrati più vicini alla distanza bloccherà la destinazione (ce ne sono molti e le loro altezze sono piccole a causa dell'angolo basso). In questo caso puoi introdurre una distanza minima (possibilmente basata su d), al di sotto della quale non visualizzi i quadrati - dovrai sperimentare con i valori esatti per vedere ciò che sembra giusto/accettabile.

2) Se si desidera un importo fisso di quadrati (sn) mostrando sempre, indipendentemente dal d, è possibile calcolare le distanze dei quadrati dalla destinazione dalla formula d*s^k, dove s è un numero < 1, k è l'indice del quadrato (contando dalla nave). La considerazione sui quadratini probabilmente non si applica qui a meno che sn non sia elevato.

Per fissare il codice aggiornato, modificare la parte relavant a:

double dist = 0; 
double d1 = 10; 
int curri = 0; 
int i = 1; 
int maxSquareHeight = 40; 
double angle = Math.atan(maxSquareHeight/distToDest); 
while (true) 
{ 
    curri = i; 
    g.setColor(Color.GREEN); 

    dist = getSquareDistance(d1, scalingFactor, i); 
    if (dist > distToDest) { 
    break; 
    } 
    double sqh = getSquareHeight(dist, angle); 
    g.drawLine(30 + (int)(shipWrap - dist), offset+50-(int)(sqh/2d), 30 + (int)(shipWrap - dist), offset+50+(int)(sqh/2d)); 
    g.setColor(Color.LIGHT_GRAY); 
    i++; 
} 

public double getSquareHeight(double distance, double angle) { 
    return distance * Math.tan(angle); 
} 

Si dovrebbe anche ridurre scalingFactor alla grandezza del ~ 1.5.

MODIFICA: Se si sostituisce la formula s^k*k*d1 con s^(k-1)*k*d1, il primo riquadro sarà esattamente alla distanza d1.

EDIT: altezza piazza fissa calcolo formula

EDIT: codice aggiornato

+0

Saluti - proverà questo e vi richiamerò :) –

+0

Formule aggiornate nel 3 ° paragrafo – Attila

+0

Riguardo l'ordine delle operazioni su 's^k * k * d1', è '(s^(k * k)) * d1'? –