はじめに
ゲームにおいて、敵の移動などにおいて、直線的な移動ではなくて、なめらかなカーブに沿った動きをしたいことがあります。曲線を描くのではなく、軌跡として扱います。以下の4種、
エルミート曲線
二次のベジェ曲線
三次のベジェ曲線(processing機能)
Catmull-Rom曲線(processing機能)
の実装について紹介します。
エルミート曲線
こちらの式を使います。
p0とp1は始点と終点を表し、
m0とm1は始点と終点における方向(ベクトル)です
変数tを0から1に変化させると、曲線の軌跡が得られます。
PVector p0 = new PVector( 0, 200);
PVector p1 = new PVector(400, 200);
PVector m0 = new PVector(300, -300);
PVector m1 = new PVector(300, 300);
void setup() {
size(400, 400);
}
void draw() {
background(255);
for (float t=0; t<=1.0; t+=0.05) {
PVector p = hermite(t);
circle(p.x, p.y, 4);
println(t);
}
PVector cha = hermite(frameCount%100*0.01);
circle(cha.x, cha.y, 20);
}
PVector hermite(float t) {
PVector r = new PVector(0, 0);
r.x = (2f*t*t*t-3f*t*t+1f)*p0.x + (t*t*t-2f*t*t+t)*m0.x -(2f*t*t*t-3f*t*t)*p1.x + (t*t*t-t*t)*m1.x;
r.y = (2f*t*t*t-3f*t*t+1f)*p0.y + (t*t*t-2f*t*t+t)*m0.y -(2f*t*t*t-3f*t*t)*p1.y + (t*t*t-t*t)*m1.y;
return(r);
}
二次のベジェ曲線
こちらのQuadratic Bézier curvesの式を使います。
p0とp1は始点と終点を表し、
c0は間の制御点です。
変数tを0から1に変化させると、曲線の軌跡が得られます。
PVector p0 = new PVector( 0, 200);
PVector p1 = new PVector(400, 200);
PVector c0 = new PVector(200, 0);
//PVector m0 = new PVector(300, -300);
//PVector m1 = new PVector(300, 300);
void setup() {
size(400, 400);
}
void draw() {
background(255);
for (float t=0; t<=1.0; t+=0.05) {
PVector p = bezier2(t);
circle(p.x, p.y, 4);
println(t);
}
PVector cha = bezier2(frameCount%100*0.01);
circle(cha.x, cha.y, 20);
}
PVector bezier2(float t) {
PVector r = new PVector(0, 0);
r.x = (1f-t)*(1f-t)*p0.x + (2f*t-2f*t*t)*c0.x +t*t*p1.x;
r.y = (1f-t)*(1f-t)*p0.y + (2f*t-2f*t*t)*c0.y +t*t*p1.y;
return(r);
}
三次のベジェ曲線(processing機能)
processingにbezierPointという便利な命令があります。
p0とp3は始点と終点を表し、
p1とp2は間の制御点です。
変数tを0から1に変化させると、曲線の軌跡が得られます。
PVector p0 = new PVector( 0, 200);
PVector p1 = new PVector(100, 100);
PVector p2 = new PVector(300, 100);
PVector p3 = new PVector(400, 200);
void setup() {
size(400, 400);
}
void draw() {
background(255);
for (float t=0; t<=1.0; t+=0.05) {
PVector p = bezier3(t);
circle(p.x, p.y, 4);
println(t);
}
PVector cha = bezier3(frameCount%100*0.01);
circle(cha.x, cha.y, 20);
}
PVector bezier3(float t) {
PVector r = new PVector(0, 0);
r.x = bezierPoint(p0.x, p1.x, p2.x, p3.x, t);
r.y = bezierPoint(p0.y, p1.y, p2.y, p3.y, t);
return(r);
}
Catmull-Rom曲線(processing機能)
p1とp2は始点と終点を表し、
p0とp3は外側の制御点です。
変数tを0から1に変化させると、曲線の軌跡が得られます。
PVector p0 = new PVector(-200, 800);
PVector p1 = new PVector( 0, 200);
PVector p2 = new PVector(400, 200);
PVector p3 = new PVector(600, 800);
void setup() {
size(400, 400);
}
void draw() {
background(255);
for (float t=0; t<=1.0; t+=0.05) {
PVector p = curve(t);
circle(p.x, p.y, 4);
println(t);
}
PVector cha = curve(frameCount%100*0.01);
circle(cha.x, cha.y, 20);
}
PVector curve(float t) {
PVector r = new PVector(0, 0);
r.x = curvePoint(p0.x, p1.x, p2.x, p3.x, t);
r.y = curvePoint(p0.y, p1.y, p2.y, p3.y, t);
return(r);
}
向き
向きも変えたいという場合は、
bezierTangent
curveTangent
命令を使うと楽と思います。