講師について¶
鈴木 遼 (すずき りょう)
![]() |
|
- C++ フレームワーク「Siv3D(シブスリーディー)」開発者。博士(工学)
- 著書に C++ 入門書「冒険で学ぶ はじめてのプログラミング」(技術評論社)
- 2013 年度 IPA 未踏、2022 年度 IPA 未踏アドバンスト
オープンソース活動¶
- Siv3D | ゲームやメディアアートのための C++20 フレームワーク
- siv::PerlinNoise | C++17 で実装された Perlin ノイズ
- Xoshiro-cpp | C++17 で実装された Xoshiro 疑似乱数生成器
- notebookjp | 低予算で高性能なノート PC の紹介サイト
イベントでの発表¶
- ゲーム開発者のための C++17~C++23, 近年の C++ 規格策定の動向 | CEDEC 2024
- ゲーム開発者のための C++11~C++20, 将来の C++ の展望 | CEDEC 2020
Siv3D について¶
- 2D/3D ゲームやアプリケーションを C++ コードで開発できるフレームワーク。
- 思いついたアイデアを最短のコードと時間で形にすることを目的に開発。
- Steam などで、ユーザによる Siv3D 製ゲームが公開されている。
2024 年に Steam で発表された Siv3D 製のゲーム
- 昨年の全国高等専門学校プログラミングコンテスト(高専プロコン)競技部門で、優勝・準優勝・3 位のすべてのチームが大会で Siv3D を使用。
- 大学におけるプログラミング授業や研究開発、ゲーム会社における研修、画像処理技術に関連するスタートアップ企業など、さまざまな場面で Siv3D の活用が広がる。
- バンダイナムコスタジオと共催のゲームジャム(ゲーム制作イベント)
- 特定の領域に絞れば、Siv3D で開発するのが最も生産性が高いと考えている。その領域を広げていくことに現在取り組んでいる。
共有できる知見¶
- C++ の最新技術を使ったプログラミング
- ユーザが成果を出せるライブラリやフレームワークを作ること
- オープンソースソフトウェアのユーザコミュニティを運営すること
- 60 人以上のコミッタ。全国 30 か所以上で Siv3D 勉強会を開催
- オープンソースソフトウェアでお金を集めること
- IPA 未踏、文科省や学内の研究費、助成金、寄付等で 3,000 万円以上を集める
最近 Siv3D で作ったもの¶
AI 絵しりとり¶
今日の #cppmix で発表した AI 絵しりとり!
— Ryo Suzuki (@Reputeless) June 14, 2024
描いた絵を AI が判定して、AI がわからなかったらゲームオーバー。#Siv3D pic.twitter.com/3IGEbZj9A4
コード
# include <Siv3D.hpp>
void Main()
{
// ウィンドウを 1280x720 にリサイズする
Window::Resize(1280, 720);
// 背景色を設定する
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// フォントを用意する
const Font font{ FontMethod::MSDF, 40, Typeface::Heavy };
const Font font2 = Font{ FontMethod::MSDF, 40, Typeface::Heavy, FontStyle::Italic }.setBufferThickness(4);
// 環境変数から API キーを取得する
const String API_KEY = EnvironmentVariable::Get(U"MY_OPENAI_API_KEY");
// キャンバスの位置とサイズ
constexpr Point CanvasOffset{ 100, 80 };
constexpr Size CanvasSize{ 512, 512 };
// ペイント用の画像
Image image{ CanvasSize, Palette::White };
// ペイント用の画像からテクスチャを作成する
DynamicTexture texture{ image };
// 非同期タスク
AsyncHTTPTask task;
// しりとりの履歴
Array<String> answers;
// 現在のしりとりの文字
char32 ch = Random(U'A', U'Z');
// 履歴のスクロール関連
int32 scrollState = 0;
Stopwatch scrollStopwatch;
Stopwatch scoreStopwatch{ 1.0s };
// スコア
int32 score = 0;
while (System::Update())
{
// 背景の市松模様を描画する
for (int32 y = 0; y < (720 / 40); ++y)
{
for (int32 x = 0; x < (1280 / 40); ++x)
{
if (IsEven(x + y))
{
Rect{ (x * 40), (y * 40), 40 }.draw(ColorF{ 0.6, 0.8, 0.7 } * 0.965);
}
}
}
// お絵描き
if (MouseL.pressed())
{
const Point from = (MouseL.down() ? Cursor::Pos() : Cursor::PreviousPos());
const Point to = Cursor::Pos();
Line{ from, to }.movedBy(-CanvasOffset).overwrite(image, 6, Color{ 0 });
texture.fill(image);
}
// 送信ボタンが押されたら
if (SimpleGUI::Button(U"判定", Vec2{ (CanvasOffset.x + 100), 620 }, 120,
(not task.isDownloading()))) // タスクの実行中でないときだけボタンを有効にする
{
// 画像に関するリクエストを作成する
OpenAI::Vision::Request request;
request.images << OpenAI::Vision::ImageData::Base64FromImage(image);
request.questions = U"What is depicted in this image? The answer starts with the letter {}."_fmt(ch);
request.questions += U"Write only the answer. Commas and periods are prohibited. If you don't know, output only a question mark.";
// タスクを作成する
task = OpenAI::Vision::CompleteAsync(API_KEY, request);
}
// クリアボタンが押されたら
if (SimpleGUI::Button(U"クリア", Vec2{ (CanvasOffset.x + CanvasSize.x - 120 - 100), 620 }, 120))
{
// 画像をクリアする
image.fill(Palette::White);
texture.fill(image);
}
// 画像を描画する
RoundRect{ CanvasOffset, CanvasSize, 10 }(texture).draw(ColorF{ 0.99, 0.98, 0.97 })
.drawFrame(3, 0, Arg::top(0.5, 0.5), Arg::bottom(0.5, 0.0))
.drawFrame(1, 10, ColorF{ 0.6, 0.4, 0.2 });
// しりとりの文字を表示する
Circle{ CanvasOffset.movedBy(30, 30), 70 }
.drawShadow(Vec2{ 2, 2 }, 12, 2, ColorF{ 0.2, 0.4, 0.3, 0.5 })
.draw(ColorF{ 0.8, 0.9, 1.0 })
.stretched(-1.5).drawFrame(1, ColorF{ 1.0 });
font(ch).drawAt(70, CanvasOffset.movedBy(30, 30), ColorF{ 0.11 });
// 非同期処理が完了し、正常なレスポンスである場合
if (task.isReady() && task.getResponse().isOK())
{
// 非同期処理の結果を取得する
const String answer = OpenAI::Vision::GetContent(task.getAsJSON()).uppercase();
// 結果の配列に追加する
answers << answer;
// 正解したら
if (answer != U"?")
{
// しりとりの文字を更新する
ch = answer.back();
++score;
scoreStopwatch.restart();
}
}
if ((not scrollStopwatch.isRunning())
&& (((scrollState == 0) ? 7 : 8) <= answers.size()))
{
scrollStopwatch.start();
scrollState = Min(scrollState + 1, 2);
}
// しりとりのスクロールアニメーション
if (scrollState == 1)
{
if (1.0s <= scrollStopwatch)
{
scrollStopwatch.pause();
scrollStopwatch.set(1s);
}
}
else if (scrollState == 2)
{
if (2.0s <= scrollStopwatch)
{
answers.pop_front();
scrollStopwatch.pause();
scrollStopwatch.set(1s);
}
}
// しりとりの履歴の表示
{
const double t = Min(scrollStopwatch.sF(), 2.0);
const double t1 = static_cast<int32>(t);
const double t2 = t - t1;
const double e = EaseInOutExpo(t2);
const double yOffset = ((t1 + e) * 80.0);
for (const auto& [i, answer] : Indexed(answers))
{
// 1 文字目
const Vec2 pos{ 700, (80 + i * 80 - yOffset) };
Circle{ pos, 32 }.draw(ColorF{ 0.8, 0.9, 1.0 });
font(answer.front()).drawAt(46, pos, ColorF{ 0.11 });
// 1 文字目以降
font(answer.substr(1)).draw(46, Vec2{ 736, (47.5 + i * 80 - yOffset) }, ColorF{ 0.11 });
}
// 次の文字
{
const Vec2 pos{ 700, (80 + answers.size() * 80 - yOffset) };
Circle{ pos, 32 }.draw(ColorF{ 0.8, 0.9, 1.0 });
font(ch).drawAt(46, pos, ColorF{ 0.11 });
// AI の応答を待つ間は回転する円を表示する
if (task.isDownloading())
{
Circle{ pos, 42 }.drawArc((Scene::Time() * 240_deg), 300_deg, 5, 2, ColorF{ 0.8, 0.9, 1.0 });
}
}
}
// スコアの表示
{
const double s = ((0.5 - Min(scoreStopwatch.sF(), 0.5)) * 2.0);
const double e = EaseInOutExpo(s);
const Vec2 center = font2(score).region(140, Arg::topRight(1185, 15)).center();
const Transformer2D transformer{ Mat3x2::Scale((1.0 + e * 0.4), center) };
font2(score).draw(TextStyle::OutlineShadow(0.2, ColorF{ 1.0 }, Vec2{ 2, 2 }, ColorF{ 0.0, 0.5 }), 140,
Arg::topRight(1185, 15), ColorF{ 1.0, 0.6, 0.1 });
}
}
}
漢字 Wordle¶
漢字 Wordle つくってみた / Kanji Wordle#Siv3D #OpenSiv3D pic.twitter.com/79rKBZj0iy
— Ryo Suzuki (@Reputeless) January 23, 2022
ゲーム UI の研究¶
日本地図を原神のマップ風に変換するプログラム¶
原神のマップに変換するプログラムを作った。#Siv3D #OpenSiv3D pic.twitter.com/1b7BONkgAu
— Ryo Suzuki (@Reputeless) June 30, 2022
ゼンレスゾーンゼロの UI の分解と再現¶
ゼンレスゾーンゼロの UI を Siv3D で再現(76 行)#ゼンゼロ pic.twitter.com/LKrwtavE4f
— Ryo Suzuki (@Reputeless) July 4, 2024
崩壊:スターレイルの UI の分解と再現¶
スターレイルの UI を Siv3D で再現。#崩壊スターレイル pic.twitter.com/1TFMDWaMNI
— Ryo Suzuki (@Reputeless) July 12, 2024