0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ゲームで使える曲線に沿った移動

Last updated at Posted at 2025-01-28

はじめに

ゲームにおいて、敵の移動などにおいて、直線的な移動ではなくて、なめらかなカーブに沿った動きをしたいことがあります。曲線を描くのではなく、軌跡として扱います。以下の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);
}

image.png

二次のベジェ曲線

こちらの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);
}

image.png

三次のベジェ曲線(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);
}

image.png

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);
}

image.png

向き

向きも変えたいという場合は、
bezierTangent
curveTangent
命令を使うと楽と思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?