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?

微分からプログラムへ:SDL2による落下運動のシミュレーション

Last updated at Posted at 2025-11-08

目的

自由落下の公式を理解した上で、C言語にて実装します。

自由落下の運動方程式と数値解法

基本パラメータ

  • $v$: 速度
  • $y$: 位置
  • $g$: 重力加速度

自由落下の運動方程式

$$
\frac{dv}{dt} = g, \quad \frac{dy}{dt} = v
$$

微分の定義から数値解法への導出

速度の更新式

微分の定義:
$$
\frac{dv}{dt} = \lim_{\Delta t \to 0} \frac{v(t+\Delta t) - v(t)}{\Delta t}
$$

近似式:
$$
g \approx \frac{v(t+\Delta t) - v(t)}{\Delta t}
$$

$$
g \cdot \Delta t \approx v(t+\Delta t) - v(t)
$$

よって、
$$
v(t+\Delta t) \approx v(t) + g \cdot \Delta t
$$
即ち、次の時刻の速度は、今の速度に重力加速度×△tを足したものとなります。

位置の更新式

微分の定義:
$$
\frac{dy}{dt} = \lim_{\Delta t \to 0} \frac{y(t+\Delta t) - y(t)}{\Delta t}
$$

近似式:
$$
v(t) \approx \frac{y(t+\Delta t) - y(t)}{\Delta t}
$$

$$
v(t) \cdot \Delta t \approx y(t+\Delta t) - y(t)
$$

よって、
$$
y(t+\Delta t) \approx y(t) + v(t) \cdot \Delta t
$$
即ち、次の時刻の位置は、今の位置に速度×△tを足したものなります。

これらの式をはC言語で以下の様に表せます。

v += g * dt;
y += v * dt;

C言語による実装

test@test-fujitsu:~/kaihatsu/butsuri$ gcc bouncing_ball.c -o bouncing_ball `sdl2-config --cflags --libs`
test@test-fujitsu:~/kaihatsu/butsuri$ ./bouncing_ball 
bouncing_ball.c
#include <SDL2/SDL.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    SDL_Init(SDL_INIT_VIDEO);

    //400×400ピクセルのウィンドウを画面中央へ配置
    SDL_Window* window = SDL_CreateWindow("Bouncing Ball",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        400, 400, 0);

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    double y = 0.0; // 球の 縦方向の位置(高さ)0 はウィンドウの上端、400 が下端(ウィンドウの高さ)
    double v = 0.0; // 球の 縦方向の速度(ピクセル/秒)
    double dt = 0.02; // 0.02秒 = 20ミリ秒ごとに物理計算する
    double g = 200.0;   // ピクセル/s^2
    double e = 0.8; // 反発係数 1.0 = 反発完全、0 = 跳ねない
    int ball_radius = 10; // 球の 半径(ピクセル) 描画や衝突判定に使う
    int height = 400; // ウィンドウの 高さ(ピクセル)

    int running = 1;
    SDL_Event event;

    while (running) {
        while (SDL_PollEvent(&event)) { // 「×」押下時終了の処理
            if (event.type == SDL_QUIT) running = 0;
        }

        // 更新
        v += g * dt;
        y += v * dt;

        // 跳ね返り
        // 「球の下端が地面(ウィンドウの底)より下に行ったら」という条件
        // 球の半径分を引くことで、球の中心ではなく球の下端で跳ね返るように調整
        if (y > height - ball_radius) {
            y = height - ball_radius;
            // -v … 速度の向きを逆にする
            // *e …衝突で失われる運動エネルギーを表す
            v = -v * e;
        }
 
        // 描画
        
        // 1コマ前で描画した正方形を塗り潰す
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // 描画色を設定 R=0 G=0 B=0 透明度=255(不透明)
        SDL_RenderClear(renderer); // 塗り潰す

        // 正方形を描画する
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // 赤 = 255
        // SDL_Rectは矩形用の構造体
        // x = 200 - ball_radius → ウィンドウ横中央に球の中心を合わせる
        // y = (int)y - ball_radius → 球の縦位置を描画用に調整
        // w = ball_radius*2 → 幅 = 直径
        // h = ball_radius*2 → 高さ = 直径
        SDL_Rect ball = {200 - ball_radius, (int)y - ball_radius, ball_radius*2, ball_radius*2};
        SDL_RenderFillRect(renderer, &ball);

        SDL_RenderPresent(renderer); // 描画した内容を画面に表示する

        SDL_Delay((int)(dt*1000));
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

output.gif

筆者の環境

  • OS: Ubuntu 22.04.5 LTS (Jammy Jellyfish)
    Linux test-fujitsu 6.8.0-87-generic x86_64 GNU/Linux

  • Cコンパイラ: GCC 11.4.0
    gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04.2)

  • SDL2ライブラリ: 2.0.20
    pkg-config --modversion sdl2 → 2.0.20

3c0c0d7cd60d3.jpg

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?