Created
July 10, 2017 13:51
-
-
Save sknjpn/f1e975d295c8b2056b75d81bf7b6f5d2 to your computer and use it in GitHub Desktop.
OpenSiv3Dで書き直しました。磁石のシミュレータです。ご自由にお持ちください。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> // OpenSiv3D v0.1.5 | |
//方位磁針 | |
struct Compass | |
{ | |
Compass(const Vec2& _pos) : pos(_pos), ang(Vec2::Up()), v(0) {} | |
Vec2 pos; //位置座標 | |
Vec2 ang; //現在角度 | |
double v; //回転速度 | |
}; | |
//モノポール | |
struct Monopole | |
{ | |
Monopole(const Vec2& _pos, const bool& _isNPole, const double& _strength) : pos(_pos), isNPole(_isNPole), strength(_strength) {} | |
bool isNPole; //true:N極 false:S極 | |
Vec2 pos; //位置座標 | |
double strength; //磁力の強さ | |
}; | |
void Main() | |
{ | |
//画面の基本的な設定 | |
Graphics::SetBackground(Color(11, 22, 33)); | |
Window::SetTitle(L"Compass Simulator with OpenSiv3D"); | |
Window::Resize(1280, 720); | |
const double s = 0.25; //描画領域の補完速度、視点追従性が変わる | |
const Triangle needle(0, -3, 15, 0, 0, 3); //方位磁針の針 | |
const Font mFont(32, Typeface::Bold); //N、Sを描画するためのフォント | |
const Font gFont(16); //多用途フォント | |
RectF dRegion(Window::Size()); //仮想描画領域 | |
RectF sRegion(dRegion); //実描画領域 | |
//配列でコンパスとモノポールは管理する | |
Array<Compass> compass; | |
Array<Monopole> monopole; | |
const double d = 32.0; //方位磁針同士の間隔 | |
//偶数列のコンパスを配置 1.73 = root3 | |
for (double x = 0; x < 1024; x += 1.73*d) | |
for (double y = 0; y < 1024; y += d) | |
compass.emplace_back(Vec2(x, y)); | |
//奇数列のコンパスを配置 0.86 = root3/2 | |
for (double x = 0.86*d; x < 1024; x += 1.73*d) | |
for (double y = 0.5*d; y < 1024; y += d) | |
compass.emplace_back(Vec2(x, y)); | |
//モノポールの配置 | |
for (int i = 0; i < 10; i++) | |
monopole.emplace_back(RandomVec2(Window::ClientRect()), RandomBool(), 100); | |
Monopole* sMonopole = NULL; //選択中のモノポール | |
while (System::Update()) | |
{ | |
//t1のスコープを限定 | |
{ | |
//Transfomer2Dで視点移動を行う。 | |
const Transformer2D t1(Mat3x2::Translate(-sRegion.pos).scale(Window::Size().y / sRegion.size.y), true); | |
//描画領域をマウスホイールで操作する | |
dRegion = dRegion.scaledAt(Cursor::PosF(), 1 + Mouse::Wheel() / 10.0); | |
//描画領域のスムーズな変化 | |
sRegion.pos = sRegion.pos*(1 - s) + dRegion.pos*s; | |
sRegion.size = sRegion.size*(1 - s) + dRegion.size*s; | |
//Monopoleの操作 | |
if (MouseL.up()) sMonopole = NULL; | |
//Monopoleの選択 | |
for (auto& m : monopole) if (Circle(m.pos, 24).leftClicked()) sMonopole = &m; | |
if (sMonopole != NULL) sMonopole->pos = Cursor::PosF(); | |
//Compass更新 | |
for (auto& c : compass) | |
{ | |
c.ang.rotate(c.v); //回転速度の分だけ回転させる | |
c.v *= 0.99; //回転速度の減衰 | |
//Monopoleの影響を演算 | |
for (const auto& m : monopole) | |
{ | |
//N極とS極の場合で反転させる。力は距離の二乗に反比例 | |
const double force = (m.isNPole ? -1 : 1) * m.strength / ((m.pos - c.pos).lengthSq() + 16.0); // + 16.0は3次元的座標のずれを表現 | |
//力のモーメントは外積によって算出できる。 (m.pos-c.pos)がゼロベクトルの可能性に注意 | |
if (!(m.pos - c.pos).isZero()) c.v += c.ang.cross((m.pos - c.pos).normalized())*force; | |
} | |
} | |
//Compass描画 | |
for (const auto& c : compass) | |
{ | |
//容器の描画 | |
Circle(c.pos, 16).draw(Palette::Gray); | |
//赤い方の針の描画 | |
needle.rotatedAt(0, 0, atan2(c.ang.y, c.ang.x)).movedBy(c.pos).draw(Palette::Red); | |
//他方の針の描画 | |
needle.rotatedAt(0, 0, atan2(c.ang.y, c.ang.x) + 3.14).movedBy(c.pos).draw(Palette::White); | |
//金具の描画 | |
Circle(c.pos, 2).draw(Palette::Gray); | |
} | |
//Monopoleの描画 | |
for (const auto& m : monopole) | |
{ | |
//共通色の定義 | |
const Color color(m.isNPole ? Palette::Red : Palette::Blue); | |
//容器の描画 | |
Circle(m.pos, 24).draw(color); | |
//中心の文字を描画 | |
mFont(m.isNPole ? L"N" : L"S").drawAt(m.pos, Palette::Black); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment