2007年12月8日土曜日

相互作用が働く粒子の運動

相互作用が働く粒子の運動2のJava移植版。アプレットはこちらです。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;

public class HSPAtom extends JApplet implements Runnable, MouseListener {
private Vector<Particle> particles = new Vector<Particle>();
private float h = 0.0f;
private final int NUM_MEMBERS = 12;
private MyPanel panel;
private Random random = new Random();

/**
* アプレットの初期化
*/
public void init() {
panel = new MyPanel();
add(panel, BorderLayout.CENTER);
makeParticles();
addMouseListener(this);

Thread thread = new Thread(this);
thread.start();
}

/**
* スレッド
*/
public void run() {
Rectangle rect = new Rectangle(getSize());
while(true) {
try {
Enumeration<Particle> e = particles.elements();
while(e.hasMoreElements()) {
Particle particle = e.nextElement();
particle.move(particles, rect);
}
panel.repaint();
Thread.sleep(40);
} catch(Exception e) {

}
}
}

/**
* 粒子を全消去し、新たに一定数の粒子を作成する
* 粒子の色も変更される
*/
private void makeParticles() {
h = random.nextFloat();
particles.clear();
Dimension size = getSize();
for(int i=0; i<NUM_MEMBERS; i++) {
Particle particle = new Particle(
random.nextDouble() * size.width,
random.nextDouble() * size.height);
particles.add(particle);
}
}
public void mouseClicked(final MouseEvent event) {
if(javax.swing.SwingUtilities.isRightMouseButton(event)){
// 右クリックの場合 - 粒子を作成し直す
makeParticles();
} else if(javax.swing.SwingUtilities.isLeftMouseButton(event)){
// 左クリックの場合 - 粒子を追加する
Particle particle = new Particle(
event.getX(), event.getY());
particles.add(particle);
}
}
public void mouseEntered(final MouseEvent event) {}
public void mouseExited(final MouseEvent event) {}
public void mousePressed(final MouseEvent event) {}
public void mouseReleased(final MouseEvent event) {}

/**
* オリジナルのパネル
*/
private class MyPanel extends JPanel{
public void paintComponent(final Graphics g) {
Dimension size = getSize();
Graphics2D g2d = (Graphics2D)g;

// 画面の消去
g.setColor(Color.black);
g.fillRect(0, 0, size.width, size.height);

// 粒子の描画
g2d.setColor(Color.getHSBColor(h, 1.0f, 1.0f));
Enumeration<Particle> e = particles.elements();
while(e.hasMoreElements()) {
Particle particle = e.nextElement();
g2d.fill(particle);
}
}
}
/**
* 粒子を表すクラス
* Ellipse2D.Doubleを拡張し、Graphics2Dのfillメソッドを利用できるようにした
*/
private class Particle extends Ellipse2D.Double {
private double veloX, veloY;
private static final int
RADIUS = 5,
PARTY_DIST = 120;
/**
* コンストラクタ
* @param x 粒子の位置(X座標)
* @param y 粒子の位置(Y座標)
*/
private Particle(double x, double y) {
super(x, y, RADIUS * 2, RADIUS * 2);
}
/**
* 速度計算と移動を同時に行う(厳密には別々に行うべき)
* @param party 自分自身を含むすべての粒子が代入されているVector
* @param size 行動範囲の広さ
*/
private void move(final Vector<Particle> party, final Rectangle area) {
double ax = 0.0, ay = 0.0;
Enumeration<Particle> e = party.elements();
while(e.hasMoreElements()) {
Particle target = e.nextElement();
if(!target.equals(this)) {
double
distance = Math.sqrt(
Math.pow(x - target.x, 2)
+ Math.pow(y - target.y, 2)),
theta = Math.atan2(target.y - y, target.x - x),
speed = Math.abs(distance - PARTY_DIST) * (distance - PARTY_DIST) / 5000;

ax += speed * Math.cos(theta);
ay += speed * Math.sin(theta);
}
}
veloX = 0.9 * (veloX + ax);
veloY = 0.9 * (veloY + ay);

this.x = limit(this.x + veloX, area.x + RADIUS, area.x + area.width - RADIUS);
this.y = limit(this.y + veloY, area.y + RADIUS, area.y + area.height - RADIUS);
}
}
/**
* HSPのlimit関数と同じ
*/
private static double limit(final double value, final double min, final double max) {
return Math.max(min, Math.min(value, max));
}
}

2 件のコメント:

y.tack さんのコメント...

おぉー!Java Versionだー!
なにげにAppletとかSwingとかawtとか使ってるし。
僕もJavaは少々、勉強しましたが
Appletについては読んだことがないです
Swingとかawtについてもちょこっとしか
読んだ記憶がないです

Javaの書籍は何冊か持っていますが
言語の解説が主で
Applet、Swing、awt等、実践に必要そうな
部分についてはなかなか書いていないですよね
ellerさんはそういったものをどうやって学んだんですか?
参考までに聞いてみました

eller さんのコメント...

re:no.44さんこんにちは。

私はJavaの勉強はほとんど「独習Java第3版」で済ませました。アプレットやswingなんかもほとんどこれですねー。

あとはネットに転がってる短いスクリプトを拾ったり解説文を読みあさったり。
Sunのドキュメントはもちろんですが、JavaDriveさんにもお世話になりました。

こんなところでしょうか?