Skip to content

Siv3D August 2016 の新機能サンプル

Reputeless edited this page Aug 26, 2016 · 19 revisions

文章読み上げ

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		if (Input::KeyA.clicked)
		{
			Say(L"こんにちは。シブスリーティーの文章読み上げ機能です。");
		}
		else if (Input::KeyB.clicked)
		{
			Say(L"Today's lucky number is ", Random(100));
		}

		if (Speech::IsSpeaking())
		{
			const double t = Time::GetMillisec() * 0.002;

			Circle(Window::Center(), 40)
				.drawArc(t, 30_deg, 8)
				.drawArc(t + 120_deg, 30_deg, 8)
				.drawArc(t + 240_deg, 30_deg, 8);
		}
	}
}

3D 描画時のシャドウ

# include <Siv3D.hpp>

void Main()
{
	Graphics::SetBackground(Color(80, 160, 230));
	Graphics3D::SetAmbientLight(ColorF(0.3));

	const Texture textureGround(L"Example/grass.jpg", TextureDesc::For3D);
	const Mesh meshGround(MeshData::Plane(30, 30, { 6, 6 }));
	const Texture textureBox(L"Example/brick.jpg", TextureDesc::For3D);
	const Model model(L"Example/Well/Well.wavefrontobj");

	ShadowLight shadowLight;
	shadowLight.lookat.set(0, 0, 0);

	while (System::Update())
	{
		Graphics3D::FreeCamera();

		const double y = 30 + Sin(Time::GetMillisec() * 0.001) * 10;
		const double angle = Time::GetMillisec() * 0.0005;	
		const Vec3 lightPos = Cylindrical(25, angle, y);

		shadowLight.position.set(lightPos);
		Graphics3D::SetShadowLight(shadowLight);
		Graphics3D::SetLight(0, Light::Directional(lightPos.normalized()));

		meshGround.draw(textureGround);

		Sphere(0, 5, 0, 2).draw().drawShadow();

		model.draw(Mat4x4::Translate(5, 0, 0)).drawShadow(Mat4x4::Translate(5, 0, 0));

		for (auto i : step(6))
		{
			const Vec3 pos = Vec3(0, 0, 6) + Cylindrical(4, Radians(i*60), 0);

			Cylinder(pos, pos + Vec3(0, 4, 0), 0.2).draw(HSV(i*60, 0.6, 1.0)).drawShadow();
		}

		for (auto i : step(6))
		{
			Box(-5 + i * 2, 0.5, -5, 1).draw(textureBox).drawShadow();
		}
	}
}

視錐台

# include <Siv3D.hpp>

void Main()
{
	const Font font(20);

	Array<Box> boxes;

	for (auto i : step(100))
	{
		boxes.emplace_back(RandomVec3({ -30, 30 }, { -30, 30 }, { -30, 30 }), 3.0);
		boxes[i].rotation.rotateRollPitchYaw(Random(TwoPi), Random(TwoPi), Random(TwoPi));
	}

	while (System::Update())
	{
		Graphics3D::FreeCamera();

		for (auto& box : boxes)
		{
			box.rotation.rotateRollPitchYaw(0.01, 0.01, 0.01);
		}

		int32 count = 0;

		const ViewFrustum vf = Graphics3D::GetCamera().calcViewFrustum();

		for (const auto& box : boxes)
		{
			if (vf.intersects(box))
			{
				box.draw();

				++count;
			}
		}

		font(L"描画された Box: {}/{}"_fmt, count, boxes.size()).draw(10, 10, Palette::Orange);
	}
}

ScalableWindow

参考比較: https://github.com/Siv3D/Reference-JP/wiki/ドットお絵かき

# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
	ScalableWindow::Setup(640, 480);

	Graphics::SetBackground(Palette::White);

	const int32 dotSize = 40;

	Grid<int32> dots(Window::BaseWidth() / dotSize, Window::BaseHeight() / dotSize);

	while (System::Update())
	{
		{
			const auto transformer = ScalableWindow::CreateTransformer();

			for (auto p : step({ dots.width, dots.height }))
			{
				const Rect rect(p * dotSize, dotSize, dotSize);

				if (rect.leftClicked)
				{
					++dots[p.y][p.x] %= 4;
				}

				const Color color(240 - dots[p.y][p.x] * 70);

				rect.stretched(-1).draw(color);
			}
		}

		ScalableWindow::DrawBlackBars(HSV(40, 0.2, 0.9));
	}
}

正投影

# include <Siv3D.hpp>

void Main()
{
	Graphics3D::SetAmbientLight(ColorF(0.3));

	Camera camera(Vec3(0, 8, 0), Vec3(0, 0, 0), Vec3(0, 1, 0), -20, 20, -15, 15, 0.1, 200.0);

	Graphics3D::SetCamera(camera);

	while (System::Update())
	{
		Graphics3D::FreeCamera();

		for (auto p : step({ 21,21 }))
		{
			Box(-50 + p.x * 5, 1.5, 50 - p.y * 5, 3).draw(HSV(p.x * 10 + p.y * 3));
		}
	}
}

クリップボードの更新検知

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		if (Input::MouseR.clicked)
		{
			Clipboard::Clear();
		}

		if (Clipboard::HasChanged())
		{
			Println(L"HasChanged");
		}
	}
}

MeshData::Capsule()

# include <Siv3D.hpp>

void Main()
{
	Graphics::SetBackground(Color(80, 160, 230));
	Graphics3D::SetAmbientLight(ColorF(0.3));

	const Texture textureGround(L"Example/grass.jpg", TextureDesc::For3D);
	const Mesh meshGround(MeshData::Plane(30, 30, { 6, 6 }));

	const Mesh mesh(MeshData::Capsule(1, 1.5));

	while (System::Update())
	{
		Graphics3D::FreeCamera();

		meshGround.draw(textureGround);

		mesh.translated(0, 2, 0).draw().drawShadow();
	}
}

IME::SetCompositionWindowPos()

# include <Siv3D.hpp>

void Main()
{
	Graphics::SetBackground(Color(160, 200, 100));

	GUI gui(GUIStyle::Default);
	gui.setTitle(L"タイトル");
	gui.add(L"text", GUITextField::Create(6));

	while (System::Update())
	{
		IME::SetCompositionWindowPos(gui.getPos());
	}
}

Box2D と CameraBox2D と ScalableWindiow

  • サイズ可変のウィンドウ
  • W/A/S/D キーやマウス右ボタン、ホイールでカメラを移動
# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
	ScalableWindow::Setup();
	CameraBox2D camera(Vec2(0,0), 17.0);

	PhysicsWorld world;

	auto ground = world.createLineString(Vec2(0, 0), { Vec2(-20, 20), Vec2(-20, 10), Vec2(20, 0), Vec2(20, 20) }, none, none, PhysicsBodyType::Static);

	Array<PhysicsBody> bodies;

	bodies.push_back(world.createPolygon(Vec2(-8, 9), Geometry2D::CreateStar(1)));

	for (auto i : step(100))
	{
		bodies.push_back(world.createCircle(Vec2(0, 5 + i * 2), 0.5));
	}

	while (System::Update())
	{
		world.update();
		camera.update();
		{
			const auto t1 = camera.createTransformer();
			const auto t2 = ScalableWindow::CreateTransformer();

			ground.draw();

			for (const auto& body : bodies)
			{
				body.draw(Palette::Skyblue);
			}
		}
		camera.draw(Palette::Orange);
	}
}

サンプルゲーム

# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
	Window::Resize(1280, 720);
	Window::SetStyle(WindowStyle::Sizeable);
	Graphics::SetBackground(ColorF(0.3, 0.7, 1));
	Graphics3D::SetAmbientLight(ColorF(0.3));
	Graphics3D::SetFog(Fog::SquaredExponential(ColorF(0.3, 0.7, 1), 0.004));

	const PerlinNoise noise;
	Array<Vec2> points = { Vec2(500, -50), Vec2(-1, -50) };
	for (auto i : step(500))
	{
		points.emplace_back((i * 1) - 1, noise.octaveNoise(i*0.01, 4) * 24);
	}
	std::reverse(points.begin(), points.end());

	PhysicsWorld world;
	const auto geround = world.createLineString(Vec2(0, 0), points, PhysicsMaterial(0.0, 0.1, 0.6), none, PhysicsBodyType::Static);
	const auto car = world.createRect(Vec2(0, 1), RectF(-1, -0.1, 2, 3.3), PhysicsMaterial(0.04));
	auto wheel1 = world.createCircle(Vec2(-1, 0.35), 0.4, PhysicsMaterial(1.0, 0.1, 0.9));
	auto wheel2 = world.createCircle(Vec2(1, 0.4), 0.4, PhysicsMaterial(1.0, 0.1, 0.9));

	PhysicsWheelJoint spring1 = world.createWheelJoint(car, wheel1, wheel1.getPos(), { 0.0,1.0 }, WheelJointState(true, 20.0, 4.0));
	PhysicsWheelJoint spring2 = world.createWheelJoint(car, wheel2, wheel2.getPos(), { 0.0,1.0 }, WheelJointState(false, 20.0, 4.0));

	const Model model(L"Example/Well/Well.wavefrontobj");
	const Mesh groundMesh(MeshData::Polygon(Polygon(points), 200.0, { 0.1, 0.1 }, { 0, 0 }));
	TextureAsset::Register(L"Brick", L"Example/brick.jpg", TextureDesc::For3D);
	const Texture brick(L"Example/brick.jpg", TextureDesc::For3D);
	const Texture textureGround(L"Example/Ground.jpg", TextureDesc::For3D);
	const Texture textureParticle(L"Example/Particle.png", TextureDesc::For3D);

	const auto DrawWheel = [](const Vec2& pos, double angle) {
		Cylinder(0.4, 1.0, Quaternion::Yaw(angle).pitch(HalfPi)).asMesh().translated(pos.x, pos.y, 0)
			.draw(TextureAsset(L"Brick")).drawShadow();
	};

	Array<Particle> smokes;
	Graphics3D::SetDepthStateForward(DepthState::TestOnly);

	XInput xinput(0);
	xinput.setRightThumbDeadZone();

	Camera camera;
	Spherical s(15, 80_deg, -90_deg);
	double previousVY = 0.0;

	while (System::Update())
	{
		if (Abs(wheel1.getVelocity().x) > 0.1)
		{
			wheel1.applyForce({ Sign(wheel1.getVelocity().x) * -0.5,0 });
			wheel2.applyForce({ Sign(wheel2.getVelocity().x) * -0.5,0 });
		}
		else if (Abs(wheel1.getVelocity().x) > 0.01)
		{
			wheel1.applyForce({ Sign(wheel1.getVelocity().x) * -4,0 });
			wheel2.applyForce({ Sign(wheel2.getVelocity().x) * -4,0 });
		}

		if ((Input::KeyZ | xinput.buttonX).pressed)
		{
			spring1.setMotor(true, 30.0);
		}
		else if ((Input::KeyX | xinput.buttonA).pressed)
		{
			spring1.setMotor(true, -30.0);
		}
		else
		{
			spring1.setMotor(false);
		}

		s.phi -= xinput.rightThumbX * 0.02;
		s.theta = Clamp(s.theta - xinput.rightThumbY *0.02, 10_deg, 90_deg);

		world.update();

		const Vec3 carPos(car.getPos(), 0);
		camera.pos = Lerp(camera.pos, carPos + s, 0.1);
		camera.lookat = carPos;
		Graphics3D::SetCamera(camera);
		Graphics3D::SetShadowLight(ShadowLight(carPos + Vec3(10, 10, -10), carPos));

		const double currentVY = car.getVelocity().y;
		const double vi = Max(currentVY - previousVY, 0.0) / 1.0;
		previousVY = currentVY;
		xinput.setVibration(vi, vi + Abs(spring1.getMotorSpeed() * 0.003) + Abs(0.005 * car.getVelocity().x));

		if (vi > 0.005)
		{
			const Vec3 pos(carPos + Vec3(System::FrameCount() % 2 ? -0.5 : 1, -0.7, 0));
			smokes.push_back(Particle(pos, 1.5, ColorF(0.6)));
		}

		for (auto& smoke : smokes)
		{
			smoke.pos.moveBy(-0.02f, 0.04f, 0.02f, 0.0f);
			smoke.scaling *= 1.025f;
			smoke.color.w = Pow(Max((1.5f - smoke.pos.z) / 2.0f, 0.0f), 2.0f);
		}

		if (!smokes.empty() && smokes.front().pos.z > 1.5)
		{
			smokes.erase(smokes.begin());
		}

		groundMesh.rotated(HalfPi, 0, 0).draw(textureGround);
		DrawWheel(wheel1.getPos(), wheel1.getAngle());
		DrawWheel(wheel2.getPos(), wheel2.getAngle());

		model.draw(Mat4x4::Rotate(0, 0, car.getAngle()).translated(carPos))
			.drawShadow(Mat4x4::Rotate(0, 0, car.getAngle()).translated(carPos));

		Graphics3D::DrawParticlesForward(smokes, textureParticle);
	}
}

Siv3D について

  1. Siv3D の基本
  2. 図形を描く
  3. テクスチャを描く
  4. テキストを描く
  5. 文字列と数値の変換
  6. キーボード入力
  7. マウス入力
  8. サウンドの再生
  9. MIDI の再生
  10. ウィンドウと背景
  11. 図形のあたり判定
  12. 乱数
  13. ダイアログ
  14. ドラッグ & ドロップ
  15. アプリの状態
  16. テキストファイル
  17. INI, CSV, JSON
  18. バイナリファイル
  19. GUI
  20. アセット管理
  21. 画像編集
  22. Web カメラ
  23. マイク入力
  24. 経過時間の測定
  25. HSV カラー
  26. ファイルダウンロード
  27. 3D 描画
  28. 2D のレンダーステート
  29. 3D のレンダーステート
  30. パーティクル
  31. スクリーンショット
  32. アプリケーションの公開
  33. さらに学ぶには

表現テクニック集

入出力デバイス

開発のヒント

Clone this wiki locally