2012-03-21 2 views
11

Я работаю над играми с 3D-пространством с некоторыми людьми, и одна из вещей, которые мне назначили, - это сделать «туннель» компьютера для инструкций, корабль проходит через туннель, состоящий из квадратов, которые пользователь пролетает до места назначения, увеличиваясь в количестве, когда пользователь приближается к месту назначения.Ориентация на симулятор космического корабля с таргетингом концентрических индикаторов

Нужно только отображать квадраты для очков перед кораблем, так как это все, что видно пользователю. По пути в пункт назначения компьютер корабля должен помещать квадраты на HUD, которые представляют собой фиксированные точки в пространстве между вами и пунктом назначения, которые являются небольшими на расстоянии и становятся больше, поскольку точки приближаются к кораблю.

guidance squares example

Я был пойти на реализацию этого и не могу показаться, чтобы выяснить это, в основном, с помощью логарифмов (Math.log10(x) и такие). Я попытался получить позицию корабля в «логарифмическом пространстве», чтобы выяснить, с какого индекса начинать рисовать квадраты, но тогда тот факт, что у меня только расстояние до места назначения, чтобы работать с смущением, особенно когда вы что число квадратов должно динамически меняться, чтобы убедиться, что они остаются фиксированными в правильных местах в пространстве (т. е. квадраты расположены с интервалами 200 или около того, прежде чем они будут преобразованы логарифмически).

В связи с этим у меня была рабочая реализация с кораблем между началом 0.0d и концом 1.0d, хотя реализация была не такой приятной. Во всяком случае, проблема по существу сводится к 1-й природе. Любые советы будут оценены с этой проблемой, включая возможные обходные пути для достижения такого же эффекта или решения.

Frontier: Elite 2

(Кроме того, есть Youtube видео, показывающее этот эффект: http://www.youtube.com/watch?v=79F9Nj7GgfM&t=3m5s)

Приветствия,
Chris

Edit: перефразировать весь вопрос.

Edit: новый код обкатки:

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) Не следует смешивать Свинг ('JApplet') & AWT (' Canvas') компоненты. 2) Апплет немного сложнее тестировать другие. Пожалуйста, подумайте о разработке с использованием гибридного приложения/апплета. 3) У вас есть вопрос? Что это? –

+1

ОК. Теперь я запускаю код. Помимо вопроса, я все еще не совсем понимаю, что должно произойти. Должны ли красные и желтые точки выравниваться? Кроме того, пурпурный корабль движется влево-вправо. Является ли желтый узор якобы тем, что пилот видит передним окном (проецируется на правой стене с нашей точки зрения)? –

+0

Да, было бы идеально, если бы красные и желтые точки были выровнены. Мне нужно создать небольшой подраздел красных точек, который должен * быть желтыми точками. Они должны оставаться в неподвижных точках в пространстве на целевом пути, относящемся к расстоянию до цели. –

ответ

10

Предполагая, что вы хотите, квадраты равной высоты (при их достижении), вы можете вычислить коэффициент масштабирования в зависимости от расстояния до пункта назначения (d) и требуемую высоту квадратов при их достижении (h).

Из этих двух частей информации вы можете рассчитать обратный тангенс (atan) угла (alpha) между линией, соединяющей судно с пунктом назначения (горизонтальная линия на вашем изображении) и линией, соединяющей верхнюю часть квадратов с местом назначения (угловая линия на вашем изображении).

EDIT: исправлены
формула Используя угол, можно вычислить высоту квадрата (h') на любом заданном расстоянии от места назначения: вы знаете, расстояние до пункта назначения (d') и угол (alpha); Высота квадрата на расстоянии d' составляет h'=r'*sin(alpha) - sin(alpha)=cos(alpha)*tan(alpha) и r'=d'/cos(alpha) (расстояние между пунктом назначения и верхней частью площади - «радиус»). Или проще: h'=d'*tan(alpha).

Примечание: принятие алгоритма к разной высоте (когда вы их достигаете) квадраты относительно просты: при вычислении угла просто предположите (фантомный) квадрат фиксированной высоты и масштабируйте квадраты относительно этого.

Если высота квадрата на расстоянии d' рассчитана для вас графической библиотекой, тем лучше, вам нужно всего лишь выяснить расстояния, чтобы разместить квадраты.

Какие расстояния для размещения площадей от места назначения?

1) Если вы хотите, чтобы отображалось различное количество квадратов (перед кораблем), но потенциально бесконечное количество квадратов (на основе d), вы можете выбрать расстояние от ближайшего квадрата до места назначения (d1) и рассчитать расстояния других квадратов по формуле s^k*k*d1, где s (коэффициент масштабирования) представляет собой число> 1 для k 'й площади (считая от пункта назначения). Вы можете остановить алгоритм, когда результат больше d. Обратите внимание, что если d достаточно велико, квадраты, наиболее близкие к расстоянию, будут блокировать пункт назначения (их много, а их высоты малы из-за низкого угла). В этом случае вы можете ввести минимальное расстояние (возможно, основанное на d), ниже которого вы не показываете квадраты - вам придется поэкспериментировать с точными значениями, чтобы увидеть, что выглядит правильно/приемлемо.

2) Если вы хотите фиксированную сумму квадратов (sn), показывающую всегда, независимо от d, вы можете рассчитать расстояние квадратов от назначения по формуле d*s^k, где s является числом < 1, k является индекс квадрата (считая с корабля). Рассмотрение мелких квадратов, вероятно, не применимо здесь, если sn не является высоким.

Чтобы исправить обновленный код, изменить relavant часть к:

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

Вы должны также уменьшить scalingFactor до величины ~ 1,5.

EDIT: Если вы замените формулу s^k*k*d1 на s^(k-1)*k*d1, то первый квадрат будет точно на расстоянии d1.

EDIT: фиксированный квадрат высоты расчетная формула

EDIT: обновленный код

+0

Cheers - попробуем это и вернемся к вам :) –

+0

Обновленные формулы в третьем абзаце – Attila

+0

Что касается порядка операций на 's^k * k * d1', это '(s^(k * k)) * d1'? –