首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >航天模拟器同心指示方阵制导计算机目标

航天模拟器同心指示方阵制导计算机目标
EN

Stack Overflow用户
提问于 2012-03-21 00:31:22
回答 1查看 1K关注 0票数 11

我正在和一些人一起做一个3D空间交易游戏,我被分配做的一件事就是制作一个引导计算机“隧道”,飞船通过这个隧道,这个隧道是由用户飞到目的地的正方形组成的,随着用户离目的地越来越近,这个隧道的数量也在增加。

它只需要渲染方格为前面的点,因为这是所有可见的用户。在前往目的地的途中,飞船的计算机应该在HUD上放置方格,表示你和目的地之间的不动点,它们在距离上很小,并且在接近飞船的时候变得越来越大。

我尝试过实现这一点,但似乎无法理解,主要是使用对数(Math.log10(x)等)。我试着得到船在“对数空间”中的位置,以帮助找出绘制正方形时应该从哪个索引开始,但是当我只有距离目的地的距离来处理这个问题时,尤其是当你考虑到方格的数量必须动态变化,以确保它们固定在正确的空间位置时(也就是说,这些方块在被对数转换之前的间隔是200左右)。

关于这一点,我有一个在0.0d开始到1.0d结束之间的ship的工作实现,尽管实现不是很好。总之,这个问题本质上归结为一维性质。如能就这一问题提出任何建议,包括可能的解决办法,以达到同样的效果或解决办法,我们将不胜感激。

(还有一个Youtube视频显示了这个效果:http://www.youtube.com/watch?v=79F9Nj7GgfM&t=3m5s)

干杯,

克里斯

编辑:改写了整个问题。

编辑:新的测试床代码:

代码语言:javascript
复制
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();
            }
        });
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-26 14:53:12

假设您希望这些方块的高度相等(当您到达它们时),您可以根据到达它们的距离(d)和所需的方块高度(h)来计算缩放因子。

根据这两条信息,您可以计算连接船到目的地的直线(图像中的水平线)和连接正方形顶部与目的地的直线(图像中的角度线)之间的角度(atan)的逆切线(alpha)。

编辑:更正

使用角度的公式,您可以计算正方形(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 (缩放因子)是k'th平方的一个数>1(从目的地算)。当结果大于d时,可以停止算法。

请注意,如果d足够大,距离最近的方块将阻塞目的地(其中有许多,由于角度较低,它们的高度很小)。在这种情况下,您可以引入一个最小的距离(可能基于d),在该距离以下不显示方格--您将不得不试验确切的值,以确定什么看起来正确/可接受。

2)如果您希望始终显示固定数量的平方(sn),则可以使用公式d*s^k计算正方形与目的地的距离,其中s是一个数字< 1,k是该平方的指数(从船舶上计数)。关于小方格的考虑可能不适用于这里,除非sn很高。

若要修复更新的代码,请将相关部分更改为:

代码语言:javascript
复制
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的量级。

编辑:如果您将公式s^k*k*d1替换为s^(k-1)*k*d1,那么第一个正方形将恰好位于距离d1

编辑:固定正方形高度计算公式

编辑:更新的代码

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9797009

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档