Siv3D / OpenSiv3D

C++20 framework for creative coding 🎮🎨🎹 / Cross-platform support (Windows, macOS, Linux, and the Web)
https://siv3d.github.io/
MIT License
994 stars 136 forks source link
c-plus-plus cpp cpp20 cross-platform game game-developement game-engine gamedev

Siv3D

Siv3D logo

Siv3D (OpenSiv3D) is a C++20 framework for creative coding (2D/3D games, media art, visualizers, and simulators). Siv3D applications run on Windows, macOS, Linux, and the Web.

Features

* Some features are limited to specific platforms

How to Install Siv3D + Tutorial

v0.6.15 | released 3 July 2024 | Release Notes

Platform SDK Requirements
Windows Download SDK /
SDK をダウンロード
- Windows 10 / 11 (64-bit)
- Microsoft Visual C++ 2022 17.9
- Windows 10 SDK
- Intel / AMD CPU
macOS Download SDK /
SDK をダウンロード
- macOS Big Sur / Monterey / Ventura
- Xcode 12.5 or newer
- Intel CPU / Apple Silicon (Rosetta mode)*
- OpenGL 4.1 compatible hardware
Linux Compiling for Linux /
Linux 版のビルド
- GCC 9.3.0 (with Boost 1.71.0) / GCC 11.2 (with Boost 1.74.0)
- Intel / AMD CPU
- OpenGL 4.1 compatible hardware
Web (experimental**) Compiling for Web /
Web 版のビルド
Web browser with WebAssembly and WebGL2 support

* Native Apple Silicon support will be added in the future release. You can build and run Siv3D in Rosetta mode
** Some functionality may be missing or limited

Next Major Update

The next major update, Siv3D v0.8, is under development in the following repository.

Community

Miscellaneous

Supporting the Project

If you would like to support the project financially, visit my GitHub Sponsors page. Your support will accelerate the development of this exciting framework.

💗 https://github.com/sponsors/Reputeless

Examples

1. Hello, Siv3D!

Screenshot

# include <Siv3D.hpp>

void Main()
{
    // 背景の色を設定する | Set the background color
    Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

    // 画像ファイルからテクスチャを作成する | Create a texture from an image file
    const Texture texture{ U"example/windmill.png" };

    // 絵文字からテクスチャを作成する | Create a texture from an emoji
    const Texture emoji{ U"🦖"_emoji };

    // 太文字のフォントを作成する | Create a bold font with MSDF method
    const Font font{ FontMethod::MSDF, 48, Typeface::Bold };

    // テキストに含まれる絵文字のためのフォントを作成し、font に追加する | Create a font for emojis in text and add it to font as a fallback
    const Font emojiFont{ 48, Typeface::ColorEmoji };
    font.addFallback(emojiFont);

    // ボタンを押した回数 | Number of button presses
    int32 count = 0;

    // チェックボックスの状態 | Checkbox state
    bool checked = false;

    // プレイヤーの移動スピード | Player's movement speed
    double speed = 200.0;

    // プレイヤーの X 座標 | Player's X position
    double playerPosX = 400;

    // プレイヤーが右を向いているか | Whether player is facing right
    bool isPlayerFacingRight = true;

    while (System::Update())
    {
        // テクスチャを描く | Draw the texture
        texture.draw(20, 20);

        // テキストを描く | Draw text
        font(U"Hello, Siv3D!🎮").draw(64, Vec2{ 20, 340 }, ColorF{ 0.2, 0.4, 0.8 });

        // 指定した範囲内にテキストを描く | Draw text within a specified area
        font(U"Siv3D (シブスリーディー) は、ゲームやアプリを楽しく簡単な C++ コードで開発できるフレームワークです。")
            .draw(18, Rect{ 20, 430, 480, 200 }, Palette::Black);

        // 長方形を描く | Draw a rectangle
        Rect{ 540, 20, 80, 80 }.draw();

        // 角丸長方形を描く | Draw a rounded rectangle
        RoundRect{ 680, 20, 80, 200, 20 }.draw(ColorF{ 0.0, 0.4, 0.6 });

        // 円を描く | Draw a circle
        Circle{ 580, 180, 40 }.draw(Palette::Seagreen);

        // 矢印を描く | Draw an arrow
        Line{ 540, 330, 760, 260 }.drawArrow(8, SizeF{ 20, 20 }, ColorF{ 0.4 });

        // 半透明の円を描く | Draw a semi-transparent circle
        Circle{ Cursor::Pos(), 40 }.draw(ColorF{ 1.0, 0.0, 0.0, 0.5 });

        // ボタン | Button
        if (SimpleGUI::Button(U"count: {}"_fmt(count), Vec2{ 520, 370 }, 120, (checked == false)))
        {
            // カウントを増やす | Increase the count
            ++count;
        }

        // チェックボックス | Checkbox
        SimpleGUI::CheckBox(checked, U"Lock \U000F033E", Vec2{ 660, 370 }, 120);

        // スライダー | Slider
        SimpleGUI::Slider(U"speed: {:.1f}"_fmt(speed), speed, 100, 400, Vec2{ 520, 420 }, 140, 120);

        // 左キーが押されていたら | If left key is pressed
        if (KeyLeft.pressed())
        {
            // プレイヤーが左に移動する | Player moves left
            playerPosX = Max((playerPosX - speed * Scene::DeltaTime()), 60.0);
            isPlayerFacingRight = false;
        }

        // 右キーが押されていたら | If right key is pressed
        if (KeyRight.pressed())
        {
            // プレイヤーが右に移動する | Player moves right
            playerPosX = Min((playerPosX + speed * Scene::DeltaTime()), 740.0);
            isPlayerFacingRight = true;
        }

        // プレイヤーを描く | Draw the player
        emoji.scaled(0.75).mirrored(isPlayerFacingRight).drawAt(playerPosX, 540);
    }
}

2. Breakout

Screenshot

# include <Siv3D.hpp>

void Main()
{
    // 1 つのブロックのサイズ | Size of a single block
    constexpr Size BrickSize{ 40, 20 };

    // ボールの速さ(ピクセル / 秒) | Ball speed (pixels / second)
    constexpr double BallSpeedPerSec = 480.0;

    // ボールの速度 | Ball velocity
    Vec2 ballVelocity{ 0, -BallSpeedPerSec };

    // ボール | Ball
    Circle ball{ 400, 400, 8 };

    // ブロックの配列 | Array of bricks
    Array<Rect> bricks;

    for (int32 y = 0; y < 5; ++y)
    {
        for (int32 x = 0; x < (Scene::Width() / BrickSize.x); ++x)
        {
            bricks << Rect{ (x * BrickSize.x), (60 + y * BrickSize.y), BrickSize };
        }
    }

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

        // ボールを移動させる | Move the ball
        ball.moveBy(ballVelocity * Scene::DeltaTime());

        // ブロックを順にチェックする | Check bricks in sequence
        for (auto it = bricks.begin(); it != bricks.end(); ++it)
        {
            // ブロックとボールが交差していたら | If block and ball intersect
            if (it->intersects(ball))
            {
                // ブロックの上辺、または底辺と交差していたら | If ball intersects with top or bottom of the block
                if (it->bottom().intersects(ball) || it->top().intersects(ball))
                {
                    // ボールの速度の Y 成分の符号を反転する | Reverse the sign of the Y component of the ball's velocity
                    ballVelocity.y *= -1;
                }
                else // ブロックの左辺または右辺と交差していたら
                {
                    // ボールの速度の X 成分の符号を反転する | Reverse the sign of the X component of the ball's velocity
                    ballVelocity.x *= -1;
                }

                // ブロックを配列から削除する(イテレータは無効になる) | Remove the block from the array (the iterator becomes invalid)
                bricks.erase(it);

                // これ以上チェックしない | Do not check any more
                break;
            }
        }

        // 天井にぶつかったら | If the ball hits the ceiling
        if ((ball.y < 0) && (ballVelocity.y < 0))
        {
            // ボールの速度の Y 成分の符号を反転する | Reverse the sign of the Y component of the ball's velocity
            ballVelocity.y *= -1;
        }

        // 左右の壁にぶつかったら | If the ball hits the left or right wall
        if (((ball.x < 0) && (ballVelocity.x < 0))
            || ((Scene::Width() < ball.x) && (0 < ballVelocity.x)))
        {
            // ボールの速度の X 成分の符号を反転する | Reverse the sign of the X component of the ball's velocity
            ballVelocity.x *= -1;
        }

        // パドルにあたったら | If the ball hits the left or right wall
        if ((0 < ballVelocity.y) && paddle.intersects(ball))
        {
            // パドルの中心からの距離に応じてはね返る方向(速度ベクトル)を変える | Change the direction (velocity vector) of the ball depending on the distance from the center of the paddle
            ballVelocity = Vec2{ (ball.x - paddle.center().x) * 10, -ballVelocity.y }.setLength(BallSpeedPerSec);
        }

        // すべてのブロックを描画する | Draw all the bricks
        for (const auto& brick : bricks)
        {
            // ブロックの Y 座標に応じて色を変える | Change the color of the brick depending on the Y coordinate
            brick.stretched(-1).draw(HSV{ brick.y - 40 });
        }

        // マウスカーソルを非表示にする | Hide the mouse cursor
        Cursor::RequestStyle(CursorStyle::Hidden);

        // ボールを描く | Draw the ball
        ball.draw();

        // パドルを描く | Draw the paddle
        paddle.rounded(3).draw();
    }
}

3. Hello, 3D world!

Screenshot

# include <Siv3D.hpp>

void Main()
{
    // Resize the window and scene to 1280x720
    Window::Resize(1280, 720);

    // Background color (remove SRGB curve for a linear workflow)
    const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();

    // Texture for UV check (mipmapped. treat as SRGB texture in a linear workflow)
    const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };

    // Multisample RenderTexture for a linear workflow
    const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };

    // 3D debug camera (free camera)
    // Vertical FOV: 30°, Eye position: (10, 16, -32)
    // Move: [W][S][A][D][E][X], View: [arrow keys]
    DebugCamera3D camera{ renderTexture.size(), 30_deg, Vec3{ 10, 16, -32 } };

    while (System::Update())
    {
        // Update a camera
        camera.update(2.0);

        // Set up a camera in the current 3D scene
        Graphics3D::SetCameraTransform(camera);

        // [3D rendering]
        {
            // Clear renderTexture with the background color,
            // then make renderTexture the render target for the current 3D scene
            const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };

            // Draw a floor
            Plane{ 64 }.draw(uvChecker);

            // Draw a box
            Box{ -8,2,0,4 }.draw(ColorF{ 0.8, 0.6, 0.4 }.removeSRGBCurve());

            // Draw a sphere
            Sphere{ 0,2,0,2 }.draw(ColorF{ 0.4, 0.8, 0.6 }.removeSRGBCurve());

            // Draw a cylinder
            Cylinder{ 8, 2, 0, 2, 4 }.draw(ColorF{ 0.6, 0.4, 0.8 }.removeSRGBCurve());
        }

        // [2D rendering]
        {
            // Flush 3D rendering commands before multisample resolve
            Graphics3D::Flush();

            // Multisample resolve
            renderTexture.resolve();

            // Transfer renderTexture to the current 2D scene (default scene)
            Shader::LinearToScreen(renderTexture);
        }
    }
}