Open8

Siv3D v0.6.7 新規追加・更新サンプル

Ryo SuzukiRyo Suzuki

OpenAI API (Chat, Image) を扱う機能

準備: 環境変数 MY_OPENAI_API_KEY に、自身で発行した OpenAI API キー sk-???... を設定します(適用には PC の再起動が必要)

Chat(同期、非同期)

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	const String API_KEY = EnvironmentVariable::Get(U"MY_OPENAI_API_KEY");

	Print << U"(1) 単一のメッセージに回答";
	Print << OpenAI::Chat::Complete(API_KEY, U"日本で一番高い山は?");

	Print << U"(2) 会話に回答";
	Print << OpenAI::Chat::Complete(API_KEY, {
		{ U"system", U"回答はできる限り簡潔にして、末尾に!を付けてください。" },
		{ U"user", U"白い食べ物は?" },
		{ U"assistant", U"豆腐!" },
		{ U"user", U"では黒いのは?" } });

	auto task3 = OpenAI::Chat::CompleteAsync(API_KEY, U"JPEG 画像ファイルの拡張子は?");

	auto task4 = OpenAI::Chat::CompleteAsync(API_KEY, {
		{ U"user", U"PNG の P って何?" },
		{ U"assistant", U"Perfect です。" },
		{ U"user", U"本当ですか?" } });

	while (System::Update())
	{
		if (task3.isReady()
			&& task3.getResponse().isOK())
		{
			Print << U"(3) 非同期で単一のメッセージに回答";
			Print << OpenAI::Chat::GetContent(task3.getAsJSON());
		}

		if (task4.isReady()
			&& task4.getResponse().isOK())
		{
			Print << U"(4) 非同期で会話に回答";
			Print << OpenAI::Chat::GetContent(task4.getAsJSON());
		}
	}
}

Image(同期)

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	Window::Resize(512, 512);

	const String API_KEY = EnvironmentVariable::Get(U"MY_OPENAI_API_KEY");

	const Texture texture{ OpenAI::Image::Create(API_KEY,
		U"There are tall mountains in the distance. The sky is clear.",
		OpenAI::ImageSize512) };

	while (System::Update())
	{
		texture.draw();
	}
}

Image(非同期)

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	const String API_KEY = EnvironmentVariable::Get(U"MY_OPENAI_API_KEY");

	Array<Texture> textures;

	auto task = OpenAI::Image::CreateAsync(API_KEY, U"Mount Fuji has erupted, and volcanic ash is falling on Tokyo.", 4, OpenAI::ImageSize256);

	while (System::Update())
	{
		if (task.isReady())
		{
			for (const auto& image : task.get())
			{
				textures << Texture{ image };
			}
		}

		for (size_t i = 0; i < textures.size(); ++i)
		{
			const double x = (i % 2) * 256.0;
			const double y = (i / 2) * 256.0;
			textures[i].draw(x, y);
		}
	}
}

アプリケーションの例

Ryo SuzukiRyo Suzuki

OSC 通信

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	const int16 port = 9000;

	OSCReceiver receiver{ IPv4Address::Localhost(), port };

	OSCSender sender{ IPv4Address::Localhost(), port };

	while (System::Update())
	{
		if (SimpleGUI::Button(U"Send", Vec2{ 600, 20 }))
		{
			OSCMessage messsage;
			messsage.beginBundle()
				.beginMessage(U"/siv3d")
				.addInt32(Scene::FrameCount())
				.addString(U"Hello")
				.addBool(true)
				.endMessage()
				.endBundle();

			sender.send(messsage);
		}

		while (receiver.hasMessages())
		{
			const auto message = receiver.pop();

			Print << message.addressPattern;

			for (const auto& argument : message.arguments)
			{
				switch (argument.tag)
				{
				case OSCTypeTag::False:
				case OSCTypeTag::True:
					Print << argument.getBool();
					break;
				case OSCTypeTag::Char:
					Print << argument.getChar();
					break;
				case OSCTypeTag::Int32:
					Print << argument.getInt32();
					break;
				case OSCTypeTag::Int64:
					Print << argument.getInt64();
					break;
				case OSCTypeTag::Float:
					Print << argument.getFloat();
					break;
				case OSCTypeTag::Double:
					Print << argument.getDouble();
					break;
				case OSCTypeTag::MIDIMessage:
					Print << argument.getMIDIMessage();
					break;
				case OSCTypeTag::TimeTag:
					Print << argument.getTimeTag();
					break;
				case OSCTypeTag::RGBAColor:
					Print << argument.getColor();
					break;
				case OSCTypeTag::String:
				case OSCTypeTag::Symbol:
					Print << argument.getString();
					break;
				case OSCTypeTag::Blob:
					Print << argument.getBlob().asArray();
					break;
				case OSCTypeTag::Nil:
					Print << U"Nil";
					break;
				case OSCTypeTag::Infinitum:
					Print << U"Infinitum";
					break;
				case OSCTypeTag::ArrayBegin:
					Print << U"[";
					break;
				case OSCTypeTag::ArrayEnd:
					Print << U"]";
					break;
				}
			}
		}
	}
}
Ryo SuzukiRyo Suzuki

円を割線で切り取った形を描く関数

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	while (System::Update())
	{
		Circle{ 150, 200, 100 }
			.drawSegment(0_deg, 60, ColorF{ 0.9 });

		Circle{ 400, 200, 100 }
			.drawSegment(30_deg, 60, ColorF{ 0.9 });

		Circle{ 650, 200, 100 }
			.drawSegment(60_deg, 60, ColorF{ 0.9 });


		Circle{ 150, 400, 100 }
			.drawSegment(120_deg, 60, ColorF{ 0.25 });

		Circle{ 400, 400, 100 }
			.drawSegmentFromAngles(60_deg, 240_deg, ColorF{ 0.25 });

		Circle{ 650, 400, 100 }
			.drawSegmentFromAngles(90_deg, 120_deg, ColorF{ 0.25 });
	}
}

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Draw(const Circle& circle, double angle, double height)
{
	circle.drawFrame(6);

	circle.drawSegment(angle, height, ColorF{ 0.2, 0.4, 0.8 });

	double arcAngleHalf = std::acos(1.0 - (height / circle.r));

	Line{ circle.getPointByAngle(angle), Arg::angle = (angle + 180_deg), height }
		.draw(LineStyle::SquareDot, 6);
}

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Circle circle{ 400, 300, 200 };

	double angle = 0_deg;

	double height = (circle.r * 0.5);

	while (System::Update())
	{
		SimpleGUI::Slider(U"angle: {:.1f}°"_fmt(Math::ToDegrees(angle)), angle, -2_pi, 2_pi, Vec2{ 20, 20 }, 150, 200);

		SimpleGUI::Slider(U"height: {:.1f}"_fmt(height), height, 0, 400, Vec2{ 400, 20 }, 160, 200);

		Draw(circle, angle, height);
	}
}
Ryo SuzukiRyo Suzuki

長方形を斜め方向のグラデーションで描く関数

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
	
	while (System::Update())
	{
		Rect{ 100, 100, 600, 180 }
			.draw(Arg::topLeft(0.3, 0.6, 0.9), Arg::bottomRight(1.0));

		Rect{ 100, 300, 600, 180 }
			.draw(Arg::topRight(0.3, 0.1, 0.3), Arg::bottomLeft(0.8, 0.4, 0.6));
	}
}
Ryo SuzukiRyo Suzuki

SimpleMenuBar の項目へのチェック

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

	const Array<std::pair<String, Array<String>>> menus
	{
		{ U"ゲーム", { U"新規", U"スコア", U"終了" }},
		{ U"設定", { U"オプション A", U"オプション B", U"オプション C" }},
		{ U"ヘルプ", { U"\U000F0625遊び方", U"\U000F14F7リリースノート", U"\U000F05E6ライセンス" }},
	};

	SimpleMenuBar menuBar{ menus };

	while (System::Update())
	{
		if (const auto item = menuBar.update())
		{
			// 「終了」が押されたら
			if (item == MenuBarItemIndex{ 0, 2 })
			{
				return;
			}

			// 「ライセンス」が押されたら
			if (item == MenuBarItemIndex{ 2, 2 })
			{
				LicenseManager::ShowInBrowser();
			}

			if (item->menuIndex == 1)
			{
				// チェック状態を反転する
				menuBar.setItemChecked(*item, (not menuBar.getItemChecked(*item)));
			}
		}

		menuBar.draw();
	}
}
Ryo SuzukiRyo Suzuki

JSON のバリデーション

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	const JSON json1 = UR"({
    "name": "Albert",
    "age": 42,
    "object": {}
})"_json;

	const JSON json2 = UR"({
    "name": "Albert",
    "age": 42,
    "object": {
        "string": "aaaa"
    }
})"_json;

	const JSON json3 = UR"({
    "name": "Albert",
    "age": 999,
    "object": {
        "string": "bbbb"
    }
})"_json;

	const JSONValidator validator = UR"({
    "title": "A person",
    "properties": {
        "name": {
            "description": "Name",
            "type": "string"
        },
        "age": {
            "description": "Age of the person",
            "type": "number",
            "minimum": 2,
            "maximum": 200
        },
        "object": {
            "type": "object",
            "properties": {
                "string": {
                    "type": "string"
                }
            },
            "required": [
                "string"
            ]
        }
    },
    "required": [
        "name",
        "age",
        "object"
    ],
    "type": "object"
})"_jsonValidator;

	{
		JSONValidator::ValidationError error;

		if (validator.validate(json1, error))
		{
			Print << U"OK";
		}
		else
		{
			Print << error;
		}
	}

	{
		JSONValidator::ValidationError error;

		if (validator.validate(json2, error))
		{
			Print << U"OK";
		}
		else
		{
			Print << error;
		}
	}

	{
		JSONValidator::ValidationError error;

		if (validator.validate(json3, error))
		{
			Print << U"OK";
		}
		else
		{
			Print << error;
		}
	}

	while (System::Update())
	{

	}
}
Ryo SuzukiRyo Suzuki

コマンドライン引数を直接取得する関数

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

void Main()
{
	int32 argc = System::GetArgc();

	char** argv = System::GetArgv();

	Print << argc;

	for (int32 i = 0; i < argc; ++i)
	{
		Print << Unicode::Widen(argv[i]);
	}

	while (System::Update())
	{

	}
}
Ryo SuzukiRyo Suzuki

アドオンの実行優先度、更新と描画の個別指定

# include <Siv3D.hpp> // OpenSiv3D v0.6.7

struct Addon1 : IAddon
{
	bool update() override
	{
		Print << U"Addon1::update()";
		return true;
	}

	void draw() const override
	{
		Print << U"Addon1::draw()";
	}
};

struct Addon2 : IAddon
{
	bool update() override
	{
		Print << U"Addon2::update()";
		return true;
	}

	void draw() const override
	{
		Print << U"Addon2::draw()";
	}
};

struct Addon3 : IAddon
{
	bool update() override
	{
		ClearPrint();
		Print << U"Addon3::update()";
		return true;
	}

	void draw() const override
	{
		Print << U"Addon3::draw()";
	}
};

void Main()
{
	Addon::Register<Addon1>(U"Addon1", 100, 300);
	Addon::Register<Addon2>(U"Addon2", 200, 200);
	Addon::Register<Addon3>(U"Addon3", 300, 100);

	while (System::Update())
	{

	}
}