Siv3Dで図形生成ツールを作った
こちらは、Siv3D Advent Calendar 2015 の5日目の記事です。
自分はSiv3Dを使って図形生成ツールを作った(作ってる)ので、これに関して便利だと感じた事や躓いた事を書いていこうと思います。
こちらはツールのデモ(Youtubeへのリンク)です。
1. EasingControllerがとても便利
これが最近Siv3Dを使ってて一番嬉しかった機能です。
動きなどの補間を行いたい時、単純にタイマーと三角関数を組み合わせて実装するとこうなります。
#include <Siv3D.hpp>
void Main()
{
TimerMillisec timer;
const Vec2 pos1(100, 100);
const Vec2 pos2(500, 100);
const unsigned T = 500;
while (System::Update())
{
if (Input::KeyEnter.clicked)
{
timer.restart();
}
if (T < timer.elapsed())
{
timer.pause();
}
const double progress = 1.0*timer.elapsed() / T;
Circle(Lerp(pos1, pos2, Sin(progress*HalfPi)), 50).draw();
}
}
これに対してEasingControllerを使うとほとんどの処理を省略できます。
#include <Siv3D.hpp>
void Main()
{
EasingController<Vec2> switcher({ 100, 100 }, { 500, 100 }, Easing::Sine, 500);
while (System::Update())
{
if (Input::KeyEnter.clicked)
{
switcher.start();
}
Circle(switcher.easeIn(), 50).draw();
}
}
さらに、現時点でEasingControllerのテンプレート引数に使えるのはLerp関数が定義されている型のみですが、逆にLerp関数の定義さえあればどんな型に対しても使えるのがすごい所です。
#include <Siv3D.hpp>
/*
本当はライブラリの名前空間に勝手に定義するのはよくない(衝突の恐れがあるため)
今回はEasingControllerに行列型を使うために仕方なく…
*/
namespace s3d
{
namespace Math
{
inline Mat3x2 Lerp(const Mat3x2& t1, const Mat3x2& t2, double f)
{
const float _f = static_cast<float>(f);
return Mat3x2(
Lerp(t1._11, t2._11, _f),Lerp(t1._12, t2._12, _f),
Lerp(t1._21, t2._21, _f),Lerp(t1._22, t2._22, _f),
Lerp(t1._31, t2._31, _f),Lerp(t1._32, t2._32, _f));
}
}
}
void Main()
{
Window::Resize(1280, 720);
const Mat3x2 transform1 = Mat3x2::Identity().rotate(Radians(90)).scale(1.0).translate(500, 0);
const Mat3x2 transform2 = Mat3x2::Identity().rotate(Radians(0)).scale(3.0).translate(0, 0);
EasingController<Mat3x2> switcher(transform1, transform2, Easing::Sine, 200);
const Rect rect(0, 200, 800, 30);
const Circle circle(200, 100, 50);
while (System::Update())
{
if (Input::KeyEnter.clicked)
{
switcher.start();
}
Graphics2D::SetTransform(switcher.easeIn());
rect.draw();
circle.draw();
}
}
2. GUIはまだ厳しい
個人的には縦に並んだボタンとテキストエリアの幅とかを揃えられないのが少し残念です。
あと他にはテキストエリアの色などに関しても結構カプセル化がきついので、もうちょっとカスタマイズできるようになるとアプリに合わせて色々変えられて良いんじゃないかなと思います。
自分でGUIを実装するのも大変ですが、とりあえずこんな感じで描画範囲を決める関数があると多少は楽じゃないかなと思います。それでも大変ですが。
//wholeAreaをcolumns列rows行に分割してこれをグリッドとし、
//そのグリッドのindexで表される位置から右にwidth個分の範囲のブロックを返す
inline RectF GetScope(const RectF& wholeArea, int columns, int rows, const Point& index, int width)
{
const Vec2 block(wholeArea.w / columns, wholeArea.h / rows);
return RectF(wholeArea.pos + block*index, Vec2(block.x*width, block.y));
}
3. 階層的な座標変換
親-子-孫のような包含関係のあるオブジェクトの座標変換は、子の変換行列に親の変換行列を掛け合わせる形で実現できます。
#include <Siv3D.hpp>
class Grandchild
{
public:
void update()
{
if (Input::KeyZ.pressed)
{
m_transform = m_transform.rotate(Radians(-3.0));
}
if (Input::KeyX.pressed)
{
m_transform = m_transform.rotate(Radians(3.0));
}
}
void draw(const Mat3x2& transform)
{
Graphics2D::SetTransform(m_transform*transform);
m_rect.drawFrame();
}
private:
Mat3x2 m_transform = Mat3x2::Identity().scale(0.5).translate(0, 50);
Rect m_rect = Rect(20, 50).setCenter(0, 0);
};
class Child
{
public:
void update()
{
if (Input::KeyUp.pressed)
{
m_transform = m_transform.rotate(Radians(-3.0));
}
if (Input::KeyDown.pressed)
{
m_transform = m_transform.rotate(Radians(3.0));
}
m_child.update();
}
void draw(const Mat3x2& transform)
{
Graphics2D::SetTransform(m_transform*transform);
m_rect.drawFrame();
m_child.draw(m_transform*transform);
}
private:
Mat3x2 m_transform = Mat3x2::Identity().scale(0.5).translate(0, 50);
Rect m_rect = Rect(20, 50).setCenter(0, 0);
Grandchild m_child;
};
class Parent
{
public:
void update()
{
if (Input::KeyLeft.pressed)
{
m_transform = m_transform.rotate(Radians(-3.0));
}
if (Input::KeyRight.pressed)
{
m_transform = m_transform.rotate(Radians(3.0));
}
m_child.update();
}
void draw(const Mat3x2& transform)
{
Graphics2D::SetTransform(m_transform*transform);
m_rect.drawFrame();
m_child.draw(m_transform*transform);
}
private:
Mat3x2 m_transform = Mat3x2::Identity().translate(0,50);
Rect m_rect = Rect(20, 50).setCenter(0, 0);
Child m_child;
};
void Main()
{
Window::Resize(1280, 720);
Parent parent;
while (System::Update())
{
parent.update();
parent.draw(Mat3x2::Identity().scale(3).translate(640, 360));
}
}
明日は@GRGSIBERIAさんの記事です。よろしくお願いします。
Author And Source
この問題について(Siv3Dで図形生成ツールを作った), 我々は、より多くの情報をここで見つけました https://qiita.com/agehama_/items/0891d707c31da9a1e07d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .