【问题标题】:Following a straight line (via Path?)沿着一条直线(通过路径?)
【发布时间】:2010-11-04 21:50:59
【问题描述】:

我正在开发一款使用射弹的游戏。所以我创建了一个 Projectile 类,并在用户触摸屏幕时创建了一个新实例:

@Override
public boolean onTouch(View v, MotionEvent e){
    float touch_x = e.getX();
    float touch_y = e.getY();
    new Projectile(touch_x, touch_y);
}

还有 Projectile 类:

public class Projectile{

    float target_x;
    float target_y;
    Path line;

    public Projectile(float x, float y){
        target_x = x;
        target_y = y;

        line = new Path();
        line.moveTo(MyGame.mPlayerXPos, MyGame.mPlayerYPos);
        line.lineTo(target_x, target_y);
    }
}

这样就形成了一个包含 2 点、玩家位置和触摸坐标的路径。我的问题是 - 你如何访问这条线上的点?例如,如果我想在直线的半点处获取 Projectile 的 x,y 坐标,或者 Projectile 在 100 个刻度后(以 X 像素/刻度的速度移动)的点?

我还需要 Projectile 在到达终点后继续移动。我需要使用 line.addPath(line) 来继续扩展路径吗?

编辑

我设法让射弹沿直线移动,但它们朝奇怪的方向移动。我不得不捏造一些代码:

private void moveProjectiles(){
        ListIterator<Projectile> it = Registry.proj.listIterator();
        while ( it.hasNext() ){
            Projectile p = it.next();
            p.TimeAlive++;

            double dist = p.TimeAlive * p.Speed;
            float dx = (float) (Math.cos(p.Angle) * dist);
            float dy = (float) (Math.sin(p.Angle) * dist);

            p.xPos += dx;
            p.yPos += -dy;
        }
    }

Angle 一定是问题所在。我正在使用这种方法,效果很好:

private double getDegreesFromTouchEvent(float x, float y){
        double delta_x = x - mCanvasWidth/2;
        double delta_y = mCanvasHeight/2 - y;
        double radians = Math.atan2(delta_y, delta_x);

        return Math.toDegrees(radians);
    }

但是,对于屏幕中心上方的触摸,它返回 0-180,对于下方的触摸,它返回 0 到 -180。这是个问题吗?

【问题讨论】:

  • 我敢打赌,您正在使用左手坐标系——屏幕左上角的 (0,0)。大多数三角函数采用右手坐标系——屏幕左下角的 (0,0)。如果您使用我的解决方案,您选择哪个坐标系都没有关系。

标签: android path coordinate-systems


【解决方案1】:

对此进行建模的最佳方法是使用parametric equations。无需使用三角函数。

class Path {
  private final float x1,y1,x2,y2,distance;

  public Path( float x1, float y1, float x2, float y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.distance = Math.sqrt( (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
  }

  public Point position( float t) {
     return new Point( (1-t)*x1 + t*x2,
                       (1-t)*y1 + t*y2);
  }

  public Point position( float ticks, float speed) {
    float t = ticks * speed / distance;
    return position( t); 
  }

}

Path p = new Path(...);
// get halfway point
p.position( 0.5);
// get position after 100 ticks at 1.5 pixels per tick
p.position( 100, 1.5);

【讨论】:

  • 如果我不能让其他方法起作用,我可能会尝试这个。这似乎更直观一点。但是,如果我想得到一个超出 (x2,y2) 的点,它会起作用吗?
  • 是的,它会起作用的。例如, p.position(2.0) 将返回到该点的两倍距离; p.position(-1.0) 将返回一个指向另一个方向的点。
  • 我第一次尝试时效果很好!谢谢!如果我想在它到达position(1) 或类似的东西时发生一些事情,它也会在未来派上用场。
【解决方案2】:

从几何中,如果它是一条直线,您可以使用极坐标计算其上的任何点。

如果你找到线的角度:

ang = arctan((target_y - player_y) / (target_x - player_x))

然后可以使用 trig 找到线上的任何点:

x = cos(ang) * dist_along_line
y = sin(ang) * dist_along_line

如果您想要中点,那么您只需将 dist_along_line 设为直线长度的一半:

dist_along_line = line_length / 2 = (sqrt((target_y - player_y)^2 + (target_x - player_x)^2)) / 2

如果您想考虑 100 个滴答后的点,以 X 像素/滴答的速度移动:

dist_along_line = 100 * X

希望有人可以评论使用 android 库更直接地执行此操作的方法。

【讨论】:

  • O_O 我可以从这里弄清楚.. 我只是不知道 trig 大声笑:P 看起来很简单,非常感谢!我会在标记为已回答之前对其进行测试。
  • 如果你想做基于图形的游戏,你肯定想研究你的三角。您也可以使用勾股定理进行计算。只需将直线视为直角三角形的斜边,将其他两侧视为 X 和 Y 坐标。
  • +1 学习三角函数!当您进入 3D 事物时,情况只会变得更糟!
  • 你必须为垂直线做一个特殊情况,否则你会在找到线的角度时得到除以零的错误
【解决方案3】:

首先Path类是用来绘制的,不是用来计算弹丸位置的。

所以您的 Projectile 类可以具有以下属性:

float positionX;
float positionY;
float velocityX;
float velocityY;

速度是从 targetX、targetY、playerX 和 playerY 计算出来的,如下所示:

float distance = sqrt(pow(targetX - playerX, 2)+pow(targetY - playerY, 2))
velocityX = (targetX - playerX) * speed / distance;
velocityY = (targetY - playerY) * speed / distance;

您在 20 个刻度后的位置是

x = positionX + 20 * velocityX;
y = positionY + 20 * velocityY;

到达 terget 所需的时间是 ticksToTarget = 距离/速度;

中途点的位置是

halfWayX = positionX + velocityX * (tickToTarget / 2);
halfWayY = positionY + velocityY * (tickToTarget / 2);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2011-10-02
    相关资源
    最近更新 更多