円運動
ある点を中心に回転するオブジェクトです。円の方程式を用いると実現できます。
円運動
上の図を見てください。水色の物体が中心 (cx,cy)、半径rの円上をくるくる回転してると考えます。このとき、中心と物体のなす角度をθ(シータ)、物体の位置を (x,y) とします。このとき、次の方程式が成り立ちます。
x = cx + r * cos(θ) y = cy + r * sin(θ)
これは円の方程式と呼ばれます。cosとsinはコサイン、サインという関数です。
水色の物体が円上を回転するとは、すなわち時間の経過にしたがってθが増えることです。この角度θは時間tを使って次のようにあらわせます。
θ = ω * t
ω(オメガ)は角速度と呼ばれます。つまり、角度=角速度*時間です。直線上の運動で距離=速度*時間、x=v*tというのがあったと思いますが、距離が角度、速度が角速度になっただけですね。速度を大きくすると動きが速くなるように角速度を大きくすると回転が速くなります。
上のθを円の方程式に代入すると
x = cx + r * cos(ω * t) y = cy + r * sin(ω * t)
です。これで運動を表せます。スレッドなどを使ってtを増やしていくとそれに合わせて水色の物体の位置(x,y)が円上を動くわけです。
Ballクラス
ではプログラムを見てみます。
public class Ball { private double x, y; // 位置 private double cx, cy; // 回転の中心座標 private double radius; // 回転半径 private double velocity; // 角速度(度/秒) private Color color; // 円の色 public Ball(double cx, double cy, double radius, double velocity, Color color) { this.cx = cx; this.cy = cy; this.radius = radius; this.velocity = velocity; this.color = color; x = cx + radius; y = cy; } public void draw(Graphics g) { g.setColor(color); g.fillOval((int) x, (int) y, 16, 16); } public void update(double t) { x = cx + radius * Math.cos(Math.toRadians(velocity * t)); y = cy + radius * Math.sin(Math.toRadians(velocity * t)); } }
update()を見てください。ωはvelocityという変数で表しています。またsin、cosはJavaではMath.sin()、 Math.cos()で使えます。Math.toRadians()というのは角度の単位を度からラジアンに直しています。Math.sin()と Math.cos()の角度はラジアンであらわす必要があるからです。
BallオブジェクトはMainPanelで作っています。
ball = new Ball[NUM_BALL]; ball[0] = new Ball(WIDTH / 2, HEIGHT / 2, 200, 90, Color.CYAN); ball[1] = new Ball(WIDTH / 2, HEIGHT / 2, 100, 120, Color.RED); ball[2] = new Ball(WIDTH / 4, HEIGHT / 4, 100, 150, Color.ORANGE);
90、120、150が角速度です。単位は度なのでball[0]は1秒間に90度、ball[1]は1秒間に120度回転します。
ゲームループ
ゲームループでは時間tを進めて、ボールの位置を更新します。ゲームループ内で50ミリ秒間休止しているので1秒で20回くらいwhileループの処理が実行されます。というわけで1回の処理で進める時間は1/20で0.05秒としています。
public void run() { while (true) { // 時間をすすめる // ゲームループは1秒間に20回呼ばれるので1回で0.05秒だけ進める t += 0.05; for (int i = 0; i < NUM_BALL; i++) { ball[i].update(t); } repaint(); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } }