2014-03-24 74 views
0

我已經制作了一個自頂向下的遊戲,我希望我的敵人能夠在屏幕上以弧線移動。現在他們在屏幕的兩個邊緣之間以一條直線移動。我在一個邊上生成一個起始位置,然後在屏幕上的某個位置找到一個隨機位置,並計算移動速度,將角度的sin/cos乘以它們的速度變量。在兩點之間創建一個用於插值的Java點

我想用這些指向它們之間生成一些弧,然後用它來移動我的敵人。我想也許某種樣條可能會做到這一點,但我不完全確定如何創建一個樣條,也不是更重要的是如何使用它來插入我的角色。我認爲在這一點上它更像是一個數學問題而不是編程,但我希望有人能夠幫助。謝謝。

+0

你有試過什麼嗎? – bjb568

回答

0

是的,樣條線會適合你。具體來說,我會推薦一個三次樣條,因爲如果你想要做一個不同的形狀,也許街頭霸王風格的勾拳,你可以重複使用相同的代碼。我記得立方樣條是一個體面的,一般的解決方案。

就解決三次樣條問題而言,我會建議您只使用Google來獲得對您有意義的僞代碼。只有當你真的想在飛行中一般地求解合適的三次樣條時才這樣。

在實踐中,我想你想要的形狀幾乎都是一樣的?如果是這樣,您可能可以解決一些樣條曲線的一般情況,並將其保存到某些快速數據結構中以提高性能。例如,對於y=x,保存必要信息(預處理)的合適陣列將是x[0] = 1,x[1] = 1,x[2] = 2 ... x[n] = n

實際上,您可以想出一個方程來建模一個簡單的兩點樣條。三次方程有4個未知數。所以你至少有兩個數據點,你是起點和終點。另外,你可以計算他跳躍時的派生率。對於你的第四點,你可以使用你希望他跳過的另一點,或者他登陸時的派生點。然後使用https://www.wolframalpha.com/爲您解答等式。或者用一個方程來求解立方體。

你可以做的另一件事就是使用二次方程+重力+風阻計算弧。 Google再次知道如何解決這個問題。這個網頁是我很快發現的,看起來可以做到這一點。 http://www.physicsclassroom.com/class/vectors/Lesson-2/Non-Horizontally-Launched-Projectiles-Problem-Solv

0

當您打算使用樣條曲線時,可以使用已經在Java中提供的Path2D類。你可以組裝通過

  • 移動到某一點
  • 將線段追加
  • 附加一個二次曲線段
  • 附加一個三次曲線段

所以組裝該任意路徑路徑應該很簡單:您可以創建一個二次曲線,該曲線從屏幕左邊緣的隨機點開始,到屏幕右邊緣的隨機點結束。作爲控制點(對於兩端),您可以在屏幕中心的任意位置使用一個點。 (當你設法將路徑表示爲一個通用的Path2D時,你可能會想象你在爲敵人設計路徑時有相當多的自由,他們可以以圓圈或之字形運行,就像你喜歡...)

這裏可能更棘手的是讓敵人跟着這條路。

第一步還不是很棘手:你可以沿着這條路走一個PathIterator。但是這個PathIterator只會返回一個單獨的段 - 即二次曲線。這可以通過創建一個展平PathIterator來緩解。這將把所有的曲線轉換成線段(分辨率可以很高,所以你不會注意到任何角落)。

但是,現在出現了非常棘手的部分:迭代這些線段時,移動速度可能會有所不同:根據原始二次曲線的曲率,可能會創建更多或更少的線段。在最壞的情況下,當所有3點都在一條線上時,只有一條線段會被創建,並且敵人會一步步穿過整個屏幕。所以你必須確保這個路徑以恆定的速度遍歷。您必須計算在路徑上迭代時已走過的距離,並可能在路徑的兩點之間插入一個位置。

我很快組裝了一個例子。這當然不是防彈的,但可以作爲一個起點。

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.Shape; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Path2D; 
import java.awt.geom.PathIterator; 
import java.awt.geom.Point2D; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 


public class SplineMovementTest 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static PathFollower pathFollower; 

    private static void createAndShowGUI() 
    { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().setLayout(new BorderLayout()); 

     final Random random = new Random(0); 

     final SplineMovementPanel p = new SplineMovementPanel(); 

     JButton generateButton = new JButton("Generate"); 
     generateButton.addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       Shape spline = generateSpline(p, 
        random.nextDouble(), 
        random.nextDouble(), 
        random.nextDouble()); 
       p.setSpline(spline); 
       pathFollower = new PathFollower(spline); 
       p.repaint(); 
      } 
     }); 
     frame.getContentPane().add(generateButton, BorderLayout.NORTH); 
     startAnimation(p); 

     frame.getContentPane().add(p, BorderLayout.CENTER); 
     frame.setSize(800, 800); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    private static Shape generateSpline(
     JComponent c, double yLeft, double yCenter, double yRight) 
    { 
     Path2D spline = new Path2D.Double(); 
     double x0 = 0; 
     double y0 = yLeft * c.getHeight(); 
     double x1 = c.getWidth()/2; 
     double y1 = yCenter * c.getHeight(); 
     double x2 = c.getWidth(); 
     double y2 = yRight * c.getHeight(); 
     spline.moveTo(x0, y0); 
     spline.curveTo(x1, y1, x1, y1, x2, y2); 
     return spline; 
    } 

    private static void startAnimation(final SplineMovementPanel p) 
    { 
     Timer timer = new Timer(20, new ActionListener() 
     { 
      double position = 0.0; 

      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       position += 0.005; 
       position %= 1.0; 
       if (pathFollower != null) 
       { 
        Point2D point = pathFollower.computePointAt(
         position * pathFollower.getPathLength()); 
        p.setObjectLocation(point); 
       } 
      } 
     }); 
     timer.start(); 
    } 
} 

class PathFollower 
{ 
    private final List<Point2D> points; 
    private final double pathLength; 

    PathFollower(Shape spline) 
    { 
     points = createPointList(spline); 
     pathLength = computeLength(points); 
    } 

    public double getPathLength() 
    { 
     return pathLength; 
    } 

    Point2D computePointAt(double length) 
    { 
     if (length < 0) 
     { 
      Point2D p = points.get(0); 
      return new Point2D.Double(p.getX(), p.getY()); 
     } 
     if (length > pathLength) 
     { 
      Point2D p = points.get(points.size()-1); 
      return new Point2D.Double(p.getX(), p.getY()); 
     } 
     double currentLength = 0; 
     for (int i=0; i<points.size()-1; i++) 
     { 
      Point2D p0 = points.get(i); 
      Point2D p1 = points.get(i+1); 
      double distance = p0.distance(p1); 
      double nextLength = currentLength + distance; 
      if (nextLength > length) 
      { 
       double rel = 1 - (nextLength - length)/distance; 
       double x0 = p0.getX(); 
       double y0 = p0.getY(); 
       double dx = p1.getX() - p0.getX(); 
       double dy = p1.getY() - p0.getY(); 
       double x = x0 + rel * dx; 
       double y = y0 + rel * dy; 
       return new Point2D.Double(x,y); 
      } 
      currentLength = nextLength; 
     } 
     Point2D p = points.get(points.size()-1); 
     return new Point2D.Double(p.getX(), p.getY()); 
    } 

    private static double computeLength(List<Point2D> points) 
    { 
     double length = 0; 
     for (int i=0; i<points.size()-1; i++) 
     { 
      Point2D p0 = points.get(i); 
      Point2D p1 = points.get(i+1); 
      length += p0.distance(p1); 
     } 
     return length; 
    } 

    private static List<Point2D> createPointList(Shape shape) 
    { 
     List<Point2D> points = new ArrayList<Point2D>(); 
     PathIterator pi = shape.getPathIterator(null, 0.1); 
     double coords[] = new double[6]; 
     while (!pi.isDone()) 
     { 
      int s = pi.currentSegment(coords); 
      switch (s) 
      { 
       case PathIterator.SEG_MOVETO: 
        points.add(new Point2D.Double(coords[0], coords[1])); 

       case PathIterator.SEG_LINETO: 
        points.add(new Point2D.Double(coords[0], coords[1])); 
      } 
      pi.next(); 
     } 
     return points; 
    } 

} 


class SplineMovementPanel extends JPanel 
{ 
    void setSpline(Shape shape) 
    { 
     this.spline = shape; 
    } 

    void setObjectLocation(Point2D objectLocation) 
    { 
     this.objectLocation = objectLocation; 
     repaint(); 
    } 
    private Shape spline = null; 
    private Point2D objectLocation = null; 


    @Override 
    protected void paintComponent(Graphics gr) 
    { 
     super.paintComponent(gr); 
     Graphics2D g = (Graphics2D)gr; 
     g.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 

     if (spline != null) 
     { 
      g.setColor(Color.BLACK); 
      g.draw(spline); 
     } 

     if (objectLocation != null) 
     { 
      g.setColor(Color.RED); 
      int x = (int)objectLocation.getX()-15; 
      int y = (int)objectLocation.getY()-15; 
      g.fillOval(x, y, 30, 30); 
     } 
    } 


} 
相關問題