Skip to content
master
Go to file
Code

Files

Permalink
Failed to load latest commit information.

README.md

OpenSiv3D

OpenSiv3D is a C++17/C++20 framework for creative coding.

Installation Guide & Documentation

SDK Downloads

Platform Version Date Requirements
Windows 0.4.3 11 April 2020 - Windows 7 SP1 / 8.1 / 10 (64-bit)
- Microsoft Visual C++ 2019 16.4
- Windows 10 SDK
macOS 0.4.3 11 April 2020 - macOS Mojave v10.14 or newer
- Xcode 11.3 or newer
- OpenGL 4.1 compatible graphics card
Linux 0.4.3* 11 April 2020 - Tested compilers: Clang 8.0.1 / GCC 9.1.0
- OpenGL 4.1 compatible graphics card
iOS TBA

* Some functionality may be missing or limited

Examples

Hello, Siv3D!

# include <Siv3D.hpp>

void Main()
{
    // Set background color to sky blue
    Scene::SetBackground(ColorF(0.8, 0.9, 1.0));

    // Create a new font
    const Font font(60);

    // Create a new texture that contains a cat emoji
    const Texture cat(Emoji(U"�?�"));

    // Coordinates of the cat
    Vec2 catPos(640, 450);

    while (System::Update())
    {
        // Put a message in the middle of the screen
        font(U"Hello, Siv3D!�?�").drawAt(Scene::Center(), Palette::Black);

        // Display the texture with animated size
        cat.resized(100 + Periodic::Sine0_1(1s) * 20).drawAt(catPos);

        // Draw a translucent red circle that follows the mouse cursor
        Circle(Cursor::Pos(), 40).draw(ColorF(1, 0, 0, 0.5));

        // When [A] key is down
        if (KeyA.down())
        {
            // Print `Hello!`
            Print << U"Hello!";
        }

        // When [Move the cat] button is pushed
        if (SimpleGUI::Button(U"Move the cat", Vec2(600, 20)))
        {
            // Move the cat's coordinates to a random position in the screen
            catPos = RandomVec2(Scene::Rect());
        }
    }
}

Breakout

# include <Siv3D.hpp>

void Main()
{
    // ブロック�?�サイズ
    constexpr Size blockSize(40, 20);

    // ブロック�?��?列
    Array<Rect> blocks;

    // 横 (Scene::Width() / blockSize.x) 個�?縦 5 個�?�ブロックを�?列�?�追加�?�る
    for (auto p : step(Size((Scene::Width() / blockSize.x), 5)))
    {
        blocks << Rect(p.x * blockSize.x, 60 + p.y * blockSize.y, blockSize);
    }

    // ボール�?�速�?�
    constexpr double speed = 480.0;

    // ボール�?�速度
    Vec2 ballVelocity(0, -speed);

    // ボール
    Circle ball(400, 400, 8);

    while (System::Update())
    {
        // パドル
        const Rect paddle(Arg::center(Cursor::Pos().x, 500), 60, 10);

        // ボールを移動
        ball.moveBy(ballVelocity * Scene::DeltaTime());

        // ブロックを順�?��?ェック
        for (auto it = blocks.begin(); it != blocks.end(); ++it)
        {
            // ボール�?�ブロック�?�交差�?��?��?��?�ら
            if (it->intersects(ball))
            {
                // ボール�?��?��??を�??転�?�る
                (it->bottom().intersects(ball) || it->top().intersects(ball) ? ballVelocity.y : ballVelocity.x) *= -1;

                // ブロックを�?列�?�ら削除(イテレータ�?�無効�?��?�る�?��?�注�?)
                blocks.erase(it);

                // �?�れ以上�?ェック�?��?��?�
                break;
            }
        }

        // 天井�?��?��?��?��?��?�ら�?��?�返る
        if (ball.y < 0 && ballVelocity.y < 0)
        {
            ballVelocity.y *= -1;
        }

        // 左�?��?��?�?��?��?��?��?��?�ら�?��?�返る
        if ((ball.x < 0 && ballVelocity.x < 0) || (Scene::Width() < ball.x && ballVelocity.x > 0))
        {
            ballVelocity.x *= -1;
        }

        // パドル�?��?��?��?��?�ら�?��?�返る
        if (ballVelocity.y > 0 && paddle.intersects(ball))
        {
            // パドル�?�中心�?�ら�?��?離�?�応�?��?��?��?�返る�?��??を変�?�る
            ballVelocity = Vec2((ball.x - paddle.center().x) * 10, -ballVelocity.y).setLength(speed);
        }

        // �?��?��?��?�ブロックを�??画�?�る
        for (const auto& block : blocks)
        {
            block.stretched(-1).draw(HSV(block.y - 40));
        }

        // ボールを�??�??
        ball.draw();

        // パドルを�??�??
        paddle.draw();
    }
}

Kaleidoscope sketch

# include <Siv3D.hpp>

void Main()
{
    // キャン�?ス�?�サイズ
    constexpr Size canvasSize(600, 600);

    // 分割数
    constexpr int32 N = 12;

    // 背景色
    constexpr Color backgroundColor(20, 40, 60);

    // ウィンドウをキャン�?ス�?�サイズ�?�
    Window::Resize(canvasSize);

    // 書�??込�?�用�?�画�?
    Image image(canvasSize, backgroundColor);

    // 画�?を表示�?�る�?��?�?�動的テクス�?ャ
    DynamicTexture texture(image);

    while (System::Update())
    {
        if (MouseL.pressed())
        {
            // 画�?��?�中心�?� (0, 0) �?��?�るよ�?��?�マウスカーソル�?�座標を移動
            const Vec2 begin = (MouseL.down() ? Cursor::PosF() : Cursor::PreviousPosF()) - Scene::Center();
            const Vec2 end = Cursor::PosF() - Scene::Center();

            for (auto i : step(N))
            {
                // 円座標�?�変�?�
                std::array<Circular, 2> cs = { begin, end };

                for (auto& c : cs)
                {
                    // 角度を�?�ら�?�
                    c.theta = IsEven(i) ? (-c.theta - 2_pi / N * (i - 1)) : (c.theta + 2_pi / N * i);
                }

                // �?�ら�?��?��?置をも�?��?��?画�?�?�線を書�??込む
                Line(cs[0], cs[1]).moveBy(Scene::Center())
                    .paint(image, 2, HSV(Scene::Time() * 60.0, 0.5, 1.0));
            }

            // 書�??込ん�?�画�?�?�テクス�?ャを更新
            texture.fillIfNotBusy(image);
        }
        else if (MouseR.down()) // �?�クリック�?�れ�?�ら
        {
            // 画�?を塗り�?��?��?�
            image.fill(backgroundColor);

            // 塗り�?��?��?��?�画�?�?�テクス�?ャを更新
            texture.fill(image);
        }

        // テクス�?ャを�??�??
        texture.draw();
    }
}

Piano

# include <Siv3D.hpp>

void Main()
{
    // 白�?��?�大�??�?�
    constexpr Size keySize(55, 400);

    // 楽器�?�種類
    constexpr GMInstrument instrument = GMInstrument::Piano1;

    // ウインドウをリサイズ
    Window::Resize(12 * keySize.x, keySize.y);

    // �?�盤�?�数
    constexpr int32 NumKeys = 20;

    // 音を作�?
    std::array<Audio, NumKeys> sounds;
    for (auto i : step(NumKeys))
    {
        sounds[i] = Audio(Wave(instrument, static_cast<uint8>(PianoKey::A3 + i), 0.5s));
    }

    // 対応�?�るキー
    constexpr std::array<Key, NumKeys> keys =
    {
        KeyTab, Key1, KeyQ,
        KeyW, Key3, KeyE, Key4, KeyR, KeyT, Key6, KeyY, Key7, KeyU, Key8, KeyI,
        KeyO, Key0, KeyP, KeyMinus, KeyGraveAccent,
    };

    // �??画�?置計算用�?�オフセット値
    constexpr std::array<int32, NumKeys> keyPositions =
    {
        0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22
    };

    while (System::Update())
    {
        // キー�?�押�?�れ�?�ら対応�?�る音を�?生
        for (auto i : step(NumKeys))
        {
            if (keys[i].down())
            {
                sounds[i].playOneShot(0.5);
            }
        }

        // 白�?�を�??画
        for (auto i : step(NumKeys))
        {
            // オフセット値�?��?�数
            if (IsEven(keyPositions[i]))
            {
                RectF(keyPositions[i] / 2 * keySize.x, 0, keySize.x, keySize.y)
                    .stretched(-1).draw(keys[i].pressed() ? Palette::Pink : Palette::White);
            }
        }

        // 黒�?�を�??画
        for (auto i : step(NumKeys))
        {
            // オフセット値�?�奇数
            if (IsOdd(keyPositions[i]))
            {
                RectF(keySize.x * 0.68 + keyPositions[i] / 2 * keySize.x, 0, keySize.x * 0.58, keySize.y * 0.62)
                    .draw(keys[i].pressed() ? Palette::Pink : Color(24));
            }
        }
    }
}

Pinball

# include <Siv3D.hpp>

// 外周�?�枠�?�頂点リストを作�?
Array<Vec2> CreateFrame(const Vec2& leftAnchor, const Vec2& rightAnchor)
{
    Array<Vec2> points = { leftAnchor, Vec2(-7, -2) };
    for (auto i : Range(-30, 30))
    {
        points << OffsetCircular(Vec2(0.0, -12.0), 7, i * 3_deg);
    }
    return points << Vec2(7, -2) << rightAnchor;
}

// 接触�?��?��?�る�?��?�応�?��?�色を決定
ColorF GetColor(const P2Body& body, const Array<P2BodyID>& list)
{
    return list.includes(body.id()) ? Palette::White : Palette::Orange;
}

void Main()
{
    // フレームレートを 60 �?�固定
    Graphics::SetTargetFrameRateHz(60);
    // フレームレート�?��?存�?��?��?��?物�?�シミュレーション�?�更新
    constexpr double timeDelta = 1.0 / 60.0;

    // 背景色を設定
    Scene::SetBackground(ColorF(0.2, 0.3, 0.4));

    // 物�?�演算用�?�ワールド
    P2World world(6.0);

    // 左�?�フリッパー�?�軸�?�座標
    constexpr Vec2 leftFlipperAnchor(-2.5, 1), rightFlipperAnchor(2.5, 1);

    // 固定�?�枠
    Array<P2Body> frames;
    // 外周
    frames << world.createStaticLineString(Vec2(0, 0), LineString(CreateFrame(leftFlipperAnchor, rightFlipperAnchor)));
    // 左上�?� (
    frames << world.createStaticLineString(Vec2(0, 0), LineString(Range(-25, -10).map([=](int32 i) { return OffsetCircular(Vec2(0.0, -12.0), 5.5, i * 3_deg).toVec2(); })));
    // �?�上�?� )
    frames << world.createStaticLineString(Vec2(0, 0), LineString(Range(10, 25).map([=](int32 i) { return OffsetCircular(Vec2(0.0, -12.0), 5.5, i * 3_deg).toVec2(); })));

    // �?ンパー
    Array<P2Body> bumpers;
    // �? x3
    bumpers << world.createStaticCircle(Vec2(0, -17), 0.5, P2Material(1.0, 1.0));
    bumpers << world.createStaticCircle(Vec2(-2, -15), 0.5, P2Material(1.0, 1.0));
    bumpers << world.createStaticCircle(Vec2(2, -15), 0.5, P2Material(1.0, 1.0));
    // â–² x2
    bumpers << world.createStaticTriangle(Vec2(0, 0), Triangle(-6, -5, -4, -1.5, -6, -3), P2Material(1.0, 0.8));
    bumpers << world.createStaticTriangle(Vec2(0, 0), Triangle(6, -5, 6, -3, 4, -1.5), P2Material(1.0, 0.8));

    // 左フリッパー
    P2Body leftFlipper = world.createDynamicRect(leftFlipperAnchor, RectF(0.0, 0.04, 2.1, 0.45), P2Material(0.1, 0.0));
    // 左フリッパー�?�ジョイント
    const P2PivotJoint leftJoint = world.createPivotJoint(frames[0], leftFlipper, leftFlipperAnchor).setLimits(-20_deg, 25_deg).setLimitEnabled(true);

    // �?�フリッパー
    P2Body rightFlipper = world.createDynamicRect(rightFlipperAnchor, RectF(-2.1, 0.04, 2.1, 0.45), P2Material(0.1, 0.0));
    // �?�フリッパー�?�ジョイント
    const P2PivotJoint rightJoint = world.createPivotJoint(frames[0], rightFlipper, rightFlipperAnchor).setLimits(-25_deg, 20_deg).setLimitEnabled(true);

    // スピナー +
    const P2Body spinner = world.createDynamicRect(Vec2(-5.8, -12), SizeF(2.0, 0.1), P2Material(0.1, 0.0)).addRect(SizeF(0.1, 2.0), P2Material(0.01, 0.0));
    // スピナー�?�ジョイント
    P2PivotJoint spinnerJoint = world.createPivotJoint(frames[0], spinner, Vec2(-5.8, -12)).setMaxMotorTorque(0.05).setMotorSpeed(0).setMotorEnabled(true);

    // 風車�?� |
    frames << world.createStaticLine(Vec2(0, 0), Line(-4, -6, -4, -4));
    // 風車�?�羽 �?
    const P2Body windmillWing = world.createDynamicRect(Vec2(-4, -6), SizeF(3.0, 0.2), P2Material(0.1, 0.8));
    // 風車�?�ジョイント
    const P2PivotJoint windmillJoint = world.createPivotJoint(frames.back(), windmillWing, Vec2(-4, -6)).setMotorSpeed(240_deg).setMaxMotorTorque(10000.0).setMotorEnabled(true);

    // 振り�?�?�軸
    const P2Body pendulumbase = world.createStaticDummy(Vec2(0, -19));
    // 振り�? �?
    P2Body pendulum = world.createDynamicCircle(Vec2(0, -12), 0.4, P2Material(0.1, 1.0));
    // 振り�?�?�ジョイント
    const P2DistanceJoint pendulumJoint = world.createDistanceJoint(pendulumbase, Vec2(0, -19), pendulum, Vec2(0, -12), 7);

    // エレベーター�?�上部 �?
    const P2Body elevatorA = world.createStaticCircle(Vec2(4, -10), 0.3);
    // エレベーター�?�床 �?
    const P2Body elevatorB = world.createRect(Vec2(4, -10), SizeF(2.0, 0.2));
    // エレベーター�?�ジョイント
    P2SliderJoint elevatorSliderJoint = world.createSliderJoint(elevatorA, elevatorB, Vec2(4, -10), Vec2(0, 1)).setLimits(0.5, 5.0).setLimitEnabled(true).setMaxMotorForce(10000).setMotorSpeed(-10);

    // ボール 〇
    const P2Body ball = world.createDynamicCircle(Vec2(-4, -12), 0.4, P2Material(0.05, 0.0));
    const P2BodyID ballID = ball.id();

    // エレベーター�?�アニメーション用ストップウォッ�?
    Stopwatch sliderStopwatch(true);

    // 2D カメラ
    const Camera2D camera(Vec2(0, -8), 24.0);

    while (System::Update())
    {
        /////////////////////////////////////////
        //
        // æ›´æ–°
        //

        // 振り�?�?�抵抗
        pendulum.applyForce(Vec2(pendulum.getVelocity().x < 0.0 ? 0.01 : -0.01, 0.0));

        if (sliderStopwatch > 4s)
        {
            // エレベーター�?�巻�??上�?�を�?�止
            elevatorSliderJoint.setMotorEnabled(false);
            sliderStopwatch.restart();
        }
        else if (sliderStopwatch > 2s)
        {
            // エレベーター�?�巻�??上�?�
            elevatorSliderJoint.setMotorEnabled(true);
        }

        // 左フリッパー�?��?作
        leftFlipper.applyTorque(KeyLeft.pressed() ? -80 : 40);

        // �?�フリッパー�?��?作
        rightFlipper.applyTorque(KeyRight.pressed() ? 80 : -40);

        // 物�?�演算ワールド�?�更新
        world.update(timeDelta, 24, 12);

        // ボール�?�接触�?��?��?�るボディ�?� ID を�?�得
        Array<P2BodyID> collidedIDs;
        for (auto [pair, collision] : world.getCollisions())
        {
            if (pair.a == ballID)
            {
                collidedIDs << pair.b;
            }
            else if (pair.b == ballID)
            {
                collidedIDs << pair.a;
            }
        }

        /////////////////////////////////////////
        //
        // �??画
        //

        // �??画用�?� Transformer2D
        const auto transformer = camera.createTransformer();

        // 枠�?��??画
        for (const auto& frame : frames)
        {
            frame.draw(Palette::Skyblue);
        }

        // スピナー�?��??画
        spinner.draw(GetColor(spinner, collidedIDs));

        // �?ンパー�?��??画
        for (const auto& bumper : bumpers)
        {
            bumper.draw(GetColor(bumper, collidedIDs));
        }

        // 風車�?��??画
        windmillWing.draw(GetColor(windmillWing, collidedIDs));

        // 振り�?�?��??画
        pendulum.draw(GetColor(pendulum, collidedIDs));

        // エレベーター�?��??画
        elevatorA.draw(GetColor(elevatorA, collidedIDs));
        elevatorB.draw(GetColor(elevatorB, collidedIDs));

        // ボール�?��??画
        ball.draw(Palette::White);

        // フリッパー�?��??画
        leftFlipper.draw(Palette::Orange);
        rightFlipper.draw(Palette::Orange);

        // ジョイント�?��?�視化
        leftJoint.draw(Palette::Red);
        rightJoint.draw(Palette::Red);
        spinnerJoint.draw(Palette::Red);
        windmillJoint.draw(Palette::Red);
        pendulumJoint.draw(Palette::Red);
        elevatorSliderJoint.draw(Palette::Red);
    }
}

Game of life

# include <Siv3D.hpp>

// 1 セル�?� 1 �?イト�?��?�るよ�?��?ビットフィールドを使用
struct Cell
{
    bool previous : 1;
    bool current : 1;
};

// フィールドをランダム�?�セル値�?�埋�?る関数
void RandomFill(Grid<Cell>& grid)
{
    grid.fill({ 0,0 });

    // 境界�?�セルを除�?��?�更新
    for (auto y : Range(1, grid.height() - 2))
    {
        for (auto x : Range(1, grid.width() - 2))
        {
            grid[y][x] = { 0, RandomBool(0.5) };
        }
    }
}

// フィールド�?�状態を更新�?�る関数
void Update(Grid<Cell>& grid)
{
    for (auto& cell : grid)
    {
        cell.previous = cell.current;
    }

    // 境界�?�セルを除�?��?�更新
    for (auto y : Range(1, grid.height() - 2))
    {
        for (auto x : Range(1, grid.width() - 2))
        {
            const int32 c = grid[y][x].previous;

            int32 n = 0;
            n += grid[y - 1][x - 1].previous;
            n += grid[y - 1][x].previous;
            n += grid[y - 1][x + 1].previous;
            n += grid[y][x - 1].previous;
            n += grid[y][x + 1].previous;
            n += grid[y + 1][x - 1].previous;
            n += grid[y + 1][x].previous;
            n += grid[y + 1][x + 1].previous;

            // セル�?�状態�?�更新
            grid[y][x].current = (c == 0 && n == 3) || (c == 1 && (n == 2 || n == 3));
        }
    }
}

// フィールド�?�状態を画�?化�?�る関数
void CopyToImage(const Grid<Cell>& grid, Image& image)
{
    for (auto y : step(image.height()))
    {
        for (auto x : step(image.width()))
        {
            image[y][x] = grid[y + 1][x + 1].current
                ? Color(0, 255, 0) : Palette::Black;
        }
    }
}

void Main()
{
    // フィールド�?�セル�?�数(横)
    constexpr int32 width = 60;

    // フィールド�?�セル�?�数(縦)
    constexpr int32 height = 60;

    // 計算を�?��?��?�境界部分も�?��?�?�サイズ�?�二次元�?列を確�?
    Grid<Cell> grid(width + 2, height + 2, { 0,0 });

    // フィールド�?�状態を�?�視化�?�る�?��?�?�画�?
    Image image(width, height, Palette::Black);

    // 動的テクス�?ャ
    DynamicTexture texture(image);

    Stopwatch s(true);

    // 自動�?生
    bool autoStep = false;

    // 更新頻度
    double speed = 0.5;

    // グリッド�?�表示
    bool showGrid = true;

    // 画�?�?�更新�?�必�?�?��?�る�?�
    bool updated = false;

    while (System::Update())
    {
        // フィールドをランダム�?�値�?�埋�?るボタン
        if (SimpleGUI::ButtonAt(U"Random", Vec2(700, 40), 170))
        {
            RandomFill(grid);
            updated = true;
        }

        // フィールド�?�セルを�?��?��?�ゼロ�?��?�るボタン
        if (SimpleGUI::ButtonAt(U"Clear", Vec2(700, 80), 170))
        {
            grid.fill({ 0, 0 });
            updated = true;
        }

        // 一時�?�止 / �?生ボタン
        if (SimpleGUI::ButtonAt(autoStep ? U"Pause" : U"Run â–¶", Vec2(700, 160), 170))
        {
            autoStep = !autoStep;
        }

        // 更新頻度変更スライダー
        SimpleGUI::SliderAt(U"Speed", speed, 1.0, 0.1, Vec2(700, 200), 70, 100);

        // 1 ステップ進�?るボタン�?�?��?��?�更新タイミング�?�確�?
        if (SimpleGUI::ButtonAt(U"Step", Vec2(700, 240), 170)
            || (autoStep && s.sF() >= (speed * speed)))
        {
            Update(grid);
            updated = true;
            s.restart();
        }

        // グリッド表示�?�有無を指定�?�る�?ェックボックス
        SimpleGUI::CheckBoxAt(showGrid, U"Grid", Vec2(700, 320), 170);

        // フィールド上�?��?�セル�?�編集
        if (Rect(0, 0, 599).mouseOver())
        {
            const Point target = Cursor::Pos() / 10 + Point(1, 1);

            if (MouseL.pressed())
            {
                grid[target].current = true;
                updated = true;
            }
            else if (MouseR.pressed())
            {
                grid[target].current = false;
                updated = true;
            }
        }

        // 画�?�?�更新
        if (updated)
        {
            CopyToImage(grid, image);
            texture.fill(image);
            updated = false;
        }

        // 画�?をフィルタ�?��?��?�拡大�?��?�表示
        {
            ScopedRenderStates2D sampler(SamplerState::ClampNearest);
            texture.scaled(10).draw();
        }

        // グリッド�?�表示
        if (showGrid)
        {
            for (auto i : step(61))
            {
                Rect(0, i * 10, 600, 1).draw(ColorF(0.4));
                Rect(i * 10, 0, 1, 600).draw(ColorF(0.4));
            }
        }

        if (Rect(0, 0, 599).mouseOver())
        {
            Cursor::RequestStyle(CursorStyle::Hidden);
            Rect(Cursor::Pos() / 10 * 10, 10).draw(Palette::Orange);
        }
    }
}

About

🦖 C++17/C++20 framework for creative coding

Topics

Resources

License

Sponsor this project

 
Learn more about GitHub Sponsors

Languages

You can’t perform that action at this time.