1

パーティクルシステムを構築しています。追加したい機能の1つは、「ターゲット」機能です。私ができるようにしたいのは、各パーティクルにX、Yターゲットを設定し、それを直線ではなく、パーティクルに適用されている他のすべてのモーションエフェクトを考慮してそこに移動させることです。

私のパーティクルが持っている関連パラメータ:

  • posx、posy:任意の値で初期化します。各ティックで、speedxとspeedyがそれぞれposxとposyに追加されます
  • speedx、speedy:任意の値で初期化します。各ティックで、accelxとaccelyがそれぞれspeedxに追加されます(もしあれば)
  • accelx、accely:任意の値で初期化します。現在の実装では、パーティクルの寿命を通じて一定に保たれます。
  • 寿命:任意の値で始まり、システムのティックごとに1が減少します。

私が達成したいのは、パーティクルが最後のライフティックでターゲットX、Yに到達し、元の値(速度と加速度)から開始して、ターゲットに向かう動きが「スムーズ」に見えるようにすることです。ティックごとに必要な加速力を再計算しながら、ターゲットの方向に加速することを考えていました。それは正しくないと思いますが、いくつかの提案を聞きたいです。

4

3 に答える 3

5

「スムーズな」モーションの場合、速度を一定に保つか、加速度を一定に保つか、ジャークを一定に保ちます。それはあなたが「スムーズ」と呼ぶものとあなたが「退屈」と呼ぶものに依存します。加速度を一定に保ちましょう。

物理学の観点から、あなたはこの制約を持っています

targetx - posx = speedx*life + 1/2accelx * life * life
targety - posy = speedy*life + 1/2accely * life * life

移動距離がですのでv*t+1/2at^2。未知の加速度を解くと

accelx = (targetx - posx - speedx*life) / (1/2 * life * life)
accely = (targety - posy - speedy*life) / (1/2 * life * life)

(これがスピーディーに機能するには、時間と同じ単位である必要があります。たとえば、「1ティックあたりのピクセル数」であり、寿命は「ティック」の数です。)

オイラー積分を使用するため、これによってパーティクルがターゲットに正確に配置されるわけではありません。しかし、それが本当の問題になるとは思えません。

魅力のように機能します:

結果

別の写真、今回は絶え間ないジャーク

jerkx = 6.0f*(targetx-x - speedx*life - 0.5f*accelx*life*life)/(life*life*life) 

カーブに別の曲がりがあるようです... ここに画像の説明を入力してください

Javaコード

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

@SuppressWarnings("serial")
public class TargetTest extends JPanel {

  List<Particle> particles = new ArrayList<Particle>();
  float tx, ty; // target position

  public TargetTest() {

    tx = 400;
    ty = 400;
    for (int i = 0; i < 50; i++)
      particles.add(new Particle(tx / 2 + (float) (tx * Math.random()), ty / 2
          + (float) (ty * Math.random())));

    this.setPreferredSize(new Dimension((int) tx * 2, (int) ty * 2));
  }

  @Override
  protected void paintComponent(Graphics g1) {
    Graphics2D g = (Graphics2D) g1;
    g.setColor(Color.black);
    // comment next line to draw curves
    g.fillRect(0, 0, getSize().width, getSize().height);

    for (Particle p : particles) {
      p.update();
      p.draw(g);
    }
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        JFrame f = new JFrame("Particle tracking");
        final TargetTest world = new TargetTest();
        f.add(world);

        // 1 tick every 50 msec
        new Timer(50, new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent arg0) {
            world.repaint();
          }
        }).start();

        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
      }
    });
  }

  class Particle {
    float x, y;// position
    float vx, vy;// speed
    float ax, ay;// acceleration
    float jx, jy;// jerk

    int life; // life

    float lastx, lasty;// previous position, needed to draw lines
    int maxlife; // maxlife, needed for color

    public Particle(float x, float y) {
      this.x = x;
      this.y = y;
      // pick a random direction to go to
      double angle = 2 * Math.PI * Math.random();
      setVelocity(angle, 2);// 2 pixels per tick = 2 pixels per 50 msec = 40
                            // pixels per second

      // the acceleration direction 'should' be close to being perpendicular to
      // the speed,
      // makes it look interesting, try commenting it if you don't believe me ;)
      if (Math.random() < 0.5)
        angle -= Math.PI / 2;
      else
        angle += Math.PI / 2;
      // add some randomness
      angle += (Math.random() - 0.5) * Math.PI / 10;
      setAcceleration(angle, 0.1);

      life = (int) (100 + Math.random() * 100);
      maxlife = life;
      lastx = x;
      lasty = y;
    }

    public void setVelocity(double angle, double speed) {
      vx = (float) (Math.cos(angle) * speed);
      vy = (float) (Math.sin(angle) * speed);
    }

    public void setAcceleration(double angle, double speed) {
      ax = (float) (Math.cos(angle) * speed);
      ay = (float) (Math.sin(angle) * speed);
    }

    @SuppressWarnings("unused")
    private void calcAcceleration(float tx, float ty) {
      ax = 2 * (tx - x - vx * life) / (life * life);
      ay = 2 * (ty - y - vy * life) / (life * life);
    }

    private void calcJerk(float tx, float ty) {
      jx = 6.0f * (tx - x - vx * life - 0.5f * ax * life * life)
          / (life * life * life);
      jy = 6.0f * (ty - y - vy * life - 0.5f * ay * life * life)
          / (life * life * life);
    }

    public void update() {
      lastx = x;
      lasty = y;
      if (--life <= 0)
        return;

      // calculate jerk
      calcJerk(tx, ty);
      // or uncomment and calculate the acceleration instead
      // calcAcceleration(tx,ty);

      ax += jx;
      ay += jy;// increase acceleration

      vx += ax;
      vy += ay;// increase speed

      x += vx;
      y += vy;// increase position
    }

    public void draw(Graphics2D g) {
      if (life < 0)
        return;
      g.setColor(new Color(255 - 255 * life / maxlife, 
            255 * life / maxlife,0));
      g.drawLine((int) x, (int) y, (int) lastx, (int) lasty);
    }
  }
}
于 2011-03-30T11:11:21.967 に答える
2

粒子には、初期速度からの慣性に対応する力(Fv)が最初に「適用」されていると考えることができます。次に、ターゲットまでの距離に比例する引力(Fa)を適用します。次に、これらの力を合計し、粒子の重量を指定して、時刻tで考慮する加速度を推定できます。

Fa(t) = (Constant / distanceToTarget(t))* [direction to target]
Fv(t) = [initialForce] * dampening(t)
a(t) = (Fa(t) + Fv(t)) / mass

次に、通常どおりv(t-1)とa(t)からv(t)を計算できます。

編集:パーティクルの寿命をターゲットまでの距離から直接計算できることを忘れました(たとえば、寿命=距離/ initialDistanceは開始時に1から始まり、ターゲットの近くで0に近づきます)

編集:これは一種の磁石と考えることができます。力の公式については、ウィキペディアを参照してください。

于 2011-03-30T10:42:56.797 に答える
1

使用できる動きの1つは、均一な加速ですhttp://en.wikipedia.org/wiki/Acceleration#Uniform_acceleration

パーティクルはスモスをターゲットに向かって移動させ、かなり高速でヒットします

定められた基準を満たすには、次の手順を実行します。

  • ターゲットからの距離を計算します。速度がこれから変化しないと仮定すると、パーティクルはライフタイムの終わりにあります。

  • この距離は次の方程式に入れられます:http : //upload.wikimedia.org/math/6/2/9/6295e1819e6bfe1101506caa4b4ec706.png

  • これを加速として使用します

  • xとyに対して別々にこれを行います

于 2011-03-30T11:01:43.817 に答える