I'm working on a 3D space trading game with some people, and one of the things I've been assigned to do is to make a guidance computer 'tunnel' that the ship travels through, with the tunnel made of squares that the user flies through to their destination, increasing in number as the user gets closer to the destination.
It's only necessary to render the squares for the points ahead of the ship, since that's all that's visible to the user. On their way to a destination, the ship's computer is supposed to put up squares on the HUD that represent fixed points in space between you and the destination, which are small in the distance and get larger as the points approach the craft.
I've had a go at implementing this and can't seem to figure it out, mainly using logarithms (Math.log10(x)
and such). I tried to get to get the ship position in 'logarithmic space' to help find out what index to start from when drawing the squares, but then the fact that I only have distance to the destination to work with confuses the matter, especially when you consider that the number of squares has to vary dynamically to make sure they stay fixed at the right locations in space (i.e., the squares are positioned at intervals of 200 or so before being transformed logarithmically).
With regard to this, I had a working implementation with the ship between a start of 0.0d and end of 1.0d, although the implementation wasn't so nice. Anyway, the problem essentially boils down to a 1d nature. Any advice would be appreciated with this issue, including possible workarounds to achieve the same effect or solutions.
(Also, there's a Youtube video showing this effect: http://www.youtube.com/watch?v=79F9Nj7GgfM&t=3m5s)
Cheers,
Chris
Edit: rephrased the entire question.
Edit: new testbed code:
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();
}
});
}
}
JApplet
) & AWT (Canvas
) components. 2) An applet is slightly harder for others to test. Please consider developing using a hybrid application/applet. 3) Do you have a question? What is it? – Calibrey = log(x)
problem, with some value modification (I'm working on the code now). – Orleanist