0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コリオリの力

Posted at

image.png

coriolisPerfect.pde
// 円柱型スペースコロニーのシミュレーション
float radius = 300;  // 画面上での円の半径(ピクセル)
float realRadius = 6.0;  // 実際のコロニーの半径(メートル)
float g = 9.8;  // 地球の重力加速度(m/s²)
float omega;  // コロニーの角速度(rad/s)
float timeScale = 0.5;  // 時間のスケール(シミュレーション速度調整用)
float dt = 0.01;  // 時間ステップ(秒)

// ボールのプロパティ
float ballX, ballY;  // ボール位置
float ballVX, ballVY;  // ボール速度
float ballRadius = 10;  // ボールの半径(描画用)
float apparentGravity = 0;  // 見かけ上の重力
ArrayList<PVector> trajectory = new ArrayList<PVector>();  // ボールの軌跡を記録

boolean ballLaunched = false;  // ボールが発射されたかどうか

// 回転の視覚化のためのマーカー
float colonyRotation = 0;  // コロニーの回転角度
ArrayList<PVector> markers = new ArrayList<PVector>();  // 回転マーカーの位置

void setup() {
  size(700, 700);
  background(0);
  
  // 地球の重力と同じになる角速度を計算
  omega = sqrt(g / realRadius)*1;
  
  // ボールの初期位置をリセット
  resetBall();
  
  // 回転マーカーを追加
  for (int i = 0; i < 8; i++) {
    float angle = TWO_PI * i / 8;
    markers.add(new PVector(cos(angle) * radius * 0.9, sin(angle) * radius * 0.9));
  }
  
  fill(255);
  textSize(14);
}

void draw() {
  // 背景を黒に
  background(0);
  
  // 座標系の原点をウィンドウの中央に移動
  translate(width/2, height/2);
  
  // 現在のコロニーの回転を更新
  colonyRotation += omega * dt * timeScale * 5; // 視覚化のため少し速くしています
  
  // スペースコロニーの輪郭を描画
  noFill();
  stroke(0, 255, 0);
  ellipse(0, 0, radius*2, radius*2);
  
  // 回転マーカーを描画
  pushMatrix();
  rotate(colonyRotation);
  
  fill(100, 200, 255, 150);
  for (PVector marker : markers) {
    ellipse(marker.x, marker.y, 30, 30);
    // マーカー間を結ぶ線
    stroke(100, 200, 255, 100);
    line(0, 0, marker.x, marker.y);
  }
  
  // 壁の質感を追加(オプション)
  noFill();
  stroke(100, 200, 255, 50);
  for (int i = 0; i < 20; i++) {
    ellipse(0, 0, radius * 2 * (0.9 + i * 0.005), radius * 2 * (0.9 + i * 0.005));
  }
  popMatrix();
  
  // 物理シミュレーション
  if (ballLaunched) {
    // 複数回更新して精度を上げる
    for (int i = 0; i < 5; i++) {
      updateBallPhysics();
    }
    
    // ボールの軌跡を記録
    trajectory.add(new PVector(ballX, ballY));
    
    // 軌跡が長すぎる場合は古いポイントを削除
    if (trajectory.size() > 2000) {
      trajectory.remove(0);
    }
  }
  
  // 軌跡を描画
  stroke(255, 100, 100);
  noFill();
  beginShape();
  for (PVector p : trajectory) {
    vertex(p.x, p.y);
  }
  endShape();
  
  // ボールを描画
  fill(255, 200, 0);
  noStroke();
  ellipse(ballX, ballY, ballRadius*2, ballRadius*2);
  
  // 見かけ上の重力の計算
  updateApparentGravity();
  
  // 情報テキスト表示
  displayInfoText();
  
  // 見かけ上の重力をバーで表示
  displayGravityBar();
}

void updateBallPhysics() {
  // スケール変換(画面座標 → 実座標)
  float x = ballX * realRadius / radius;
  float y = ballY * realRadius / radius;
  float vx = ballVX * realRadius / radius;
  float vy = ballVY * realRadius / radius;
  
  // 遠心力加速度(見かけの重力)
  float r = sqrt(x*x + y*y);
  float ax_centrifugal = 0;
  float ay_centrifugal = 0;
  
  if (r > 0.01) {  // ゼロ除算防止
    ax_centrifugal = omega*omega * x;
    ay_centrifugal = omega*omega * y;
  }
  
  // コリオリ力加速度
  float ax_coriolis = -2 * omega * vy;
  float ay_coriolis = 2 * omega * vx;
  
  // 加速度の合計
  float ax = ax_centrifugal + ax_coriolis;
  float ay = ay_centrifugal + ay_coriolis;
  
  // 速度と位置の更新
  vx += ax * dt * timeScale;
  vy += ay * dt * timeScale;
  x += vx * dt * timeScale;
  y += vy * dt * timeScale;
  
  // 壁との衝突判定・反射
  float distFromCenter = sqrt(x*x + y*y);
  if (distFromCenter > realRadius - 0.1) {  // ボールが壁に当たったら
    // 法線方向ベクトル
    float nx = x / distFromCenter;
    float ny = y / distFromCenter;
    
    // 速度の法線成分
    float vn = vx * nx + vy * ny;
    
    // 反射後の速度計算(反発係数0.8)
    vx = vx - (1 + 0.99) * vn * nx;
    vy = vy - (1 + 0.99) * vn * ny;
    
    // 位置の調整(壁の内側に戻す)
    float correctionFactor = (realRadius - 0.1) / distFromCenter;
    x *= correctionFactor;
    y *= correctionFactor;
  }
  
  // スケール変換(実座標 → 画面座標)
  ballX = x * radius / realRadius;
  ballY = y * radius / realRadius;
  ballVX = vx * radius / realRadius;
  ballVY = vy * radius / realRadius;
}

void updateApparentGravity() {
  // ボールの実座標でのポジション
  float x = ballX * realRadius / radius;
  float y = ballY * realRadius / radius;
  
  // 遠心力によるみかけの重力の大きさを計算
  float r = sqrt(x*x + y*y);
  apparentGravity = omega * omega * r;
}

void displayGravityBar() {
  // 画面右側に重力バーを表示
  float barX = width/2 - 120;
  float barY = -height/2 + 70;
  float barHeight = 20;
  float barMaxWidth = 100;
  
  // 地球の重力に対する相対値(1.0が地球と同じ)
  float relativeGravity = apparentGravity / g;
  
  // バーの枠を表示
  stroke(200);
  noFill();
  rect(barX, barY, barMaxWidth, barHeight);
  
  // バーを表示(相対重力に応じて色を変える)
  if (relativeGravity < 0.8) {
    fill(100, 200, 100);  // 弱い重力は緑色
  } else if (relativeGravity < 1.2) {
    fill(200, 200, 100);  // 地球に近い重力は黄色
  } else {
    fill(200, 100, 100);  // 強い重力は赤色
  }
  
  // バーの長さは相対重力に比例(最大2G相当)
  float barWidth = min(barMaxWidth, barMaxWidth * relativeGravity / 2.0);
  rect(barX, barY, barWidth, barHeight);
}

void displayInfoText() {
  fill(255);
  textAlign(LEFT);
  
  // 画面左上に情報表示
  text("Rotate Speed: " + nf(2*PI/omega, 1, 2) + " sec", -width/2 + 20, -height/2 + 30);
  text("Virtual Gravity: " + nf(apparentGravity, 1, 2) + " m/s²", -width/2 + 20, -height/2 + 50);
  text("Earth's G: ratio " + nf(apparentGravity/g, 1, 2) + "G", -width/2 + 20, -height/2 + 70);
  text("click shoot | R key reset", -width/2 + 20, -height/2 + 90);
}

void resetBall() {
  // ボールを中心近くに配置
  ballX = radius * 0.5;  // 右半分に配置
  ballY = 0;
  
  // 初期速度をゼロに
  ballVX = 0;
  ballVY = 0;
  
  // 軌跡をクリア
  trajectory.clear();
  
  // 発射フラグをリセット
  ballLaunched = false;
  
  // 見かけ上の重力を更新
  updateApparentGravity();
}

void mousePressed() {
  if (!ballLaunched) {
    // ボールを発射
    // マウス位置への初速度を設定
    PVector direction = new PVector(mouseX - width/2 - ballX, mouseY - height/2 - ballY);
    direction.normalize();
    
    // 初速度の大きさ(画面スケールで100ピクセル/秒)
    float speed = 200;
    ballVX = direction.x * speed;
    ballVY = direction.y * speed;
    
    ballLaunched = true;
  }
}

void keyPressed() {
  if (key == 'r' || key == 'R') {
    resetBall();
  }
}
0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?