Last active
November 25, 2016 14:45
-
-
Save voidproc/501693a9702f1ff1dd35dfb8b661c11c to your computer and use it in GitHub Desktop.
Application Launcher with Leap Motion + Siv3D
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
#define NOMINMAX | |
#define STRICT | |
#include <windows.h> | |
#include <Siv3D.hpp> | |
#include <HamFramework.hpp> | |
#include <Siv3DAddon/LeapMotion.hpp> | |
// Leap Motion で アプリケーションランチャー | |
// | |
// ジェスチャーでアプリケーションを実行します。 | |
// | |
// 本アプリにおけるジェスチャー: | |
// 1. ジェスチャーを開始(手を開く動作) | |
// 2. 手を10cm以上移動 | |
// 3. ジェスチャーを終了(手を握る動作) | |
// | |
// 手を移動する角度(8方向)により実行するコマンドを選択します。 | |
// | |
// | |
// ※アプリケーションが非アクティブになっても Leap Motion での検出を続ける場合は | |
// LeapMotion.hpp の LeapMotionDevice::init() に以下の行を追加 | |
// m_controller.setPolicyFlags( Leap::Controller::PolicyFlag::POLICY_BACKGROUND_FRAMES); | |
struct GestureMarker : public IEffect | |
{ | |
GestureMarker(const Vec2& pos) | |
: pos(pos) | |
{ | |
} | |
bool update(double t) | |
{ | |
Circle(pos, 4.0 + t/0.3 * 200.0).drawFrame(30.0 * (1.1 - t/0.3), 0.0, Color(Palette::Yellow, 255 - 200 * (1.1 - t/0.3))); | |
return t < 0.3; | |
} | |
Vec2 pos; | |
}; | |
struct ExecGestureCommand : public IEffect | |
{ | |
bool update(double t) | |
{ | |
Window::BaseClientRect().draw(Color(Palette::Lime, 128 * (1.1 - t/0.3))); | |
return t < 0.3; | |
} | |
}; | |
double startAngle(const int index, const int div = 8) | |
{ | |
return Pi - (TwoPi / div / 2 + TwoPi / div * (index - 1)); | |
} | |
void drawCircleMenu(const int index, const int div = 8) | |
{ | |
const double ang = startAngle(index, div); | |
Circle(Window::BaseCenter(), 220.0) | |
.drawFrame(100.0, 0.0, Color(80, 128)) | |
.drawArc(Pi - ang, TwoPi / div, 100.0, 0.0, Palette::White); | |
} | |
struct Command | |
{ | |
String path; | |
}; | |
class CommandList | |
{ | |
public: | |
CommandList() | |
{ | |
cmd_.resize(N); | |
cmd_[0].path = L"calc"; | |
cmd_[1].path = L"mspaint"; | |
cmd_[2].path = L"notepad"; | |
cmd_[3].path = L"cmd"; | |
cmd_[4].path = L"wmplayer"; | |
cmd_[5].path = L"iexplore"; | |
cmd_[6].path = L"explorer"; | |
cmd_[7].path = L"excel"; | |
} | |
bool execute(const int i) | |
{ | |
::ShellExecute(nullptr, nullptr, cmd_[i].path.c_str(), nullptr, nullptr, SW_SHOWNORMAL); | |
return true; | |
} | |
const FilePath& path(const int i) | |
{ | |
return cmd_[i].path; | |
} | |
private: | |
const int N = 8; | |
Array<Command> cmd_; | |
}; | |
void Main() | |
{ | |
ScalableWindow::Setup(600, 600); | |
Window::Resize(300, 300); | |
FontAsset::Register(L"menu", 36, Typeface::Bold); | |
Effect effect; | |
LeapMotion::RegisterAddon(); | |
String state = L""; | |
Vec2 gestureBase; //ジェスチャ開始位置 | |
int beginGestureWait = 0; //ジェスチャ開始までの待ち時間用 | |
CommandList commands; | |
while (System::Update()) | |
{ | |
{ | |
const auto transformer = ScalableWindow::CreateTransformer(); | |
// 手が検出されない場合はジェスチャの状態をリセットする | |
if (LeapMotion::Hands().empty()) | |
{ | |
state = L""; | |
// BG | |
Window::BaseClientRect().draw(Color(128)); | |
} | |
else | |
{ | |
// 手が検出された場合は、1本目の手のジェスチャを監視 | |
for (const auto& hand : LeapMotion::Hands()) | |
{ | |
const Vec2 pos = hand.stabilizedPos.xy(); | |
if (state == L"begin") | |
{ | |
// BG | |
Window::BaseClientRect().draw(Color(128, 80 * ((System::FrameCount() / 2) % 2))); | |
// ジェスチャ開始位置と現在の手との距離・角度 | |
const Circular d = pos - gestureBase; | |
// ジェスチャの有効範囲に入っているか? | |
if (d.r > 100) | |
{ | |
const int DIV = 8; | |
int index = ((int)(4.5 - d.theta / (TwoPi / DIV)) % 8); // 0..DIV-1 | |
drawCircleMenu(index, DIV); | |
FontAsset(L"menu")(commands.path(index)).drawCenter(Window::BaseCenter()); | |
// ジェスチャコマンド実行 | |
if (hand.grabStrength > 0.8) | |
{ | |
effect.add<ExecGestureCommand>(); | |
commands.execute(index); | |
state = L""; | |
beginGestureWait = 0; | |
} | |
} | |
// ジェスチャ中止 | |
if (hand.grabStrength > 0.8) | |
{ | |
state = L""; | |
} | |
// ジェスチャの中心 | |
Circle(Window::BaseCenter().movedBy(gestureBase.x, +300 - gestureBase.y), 30.0).drawFrame(4.0, 0.0, Color(Palette::Yellow, 100)); | |
} | |
// ジェスチャを開始 | |
if (state == L"") | |
{ | |
if (hand.grabStrength < 0.1) | |
{ | |
if (++beginGestureWait > 16) | |
{ | |
state = L"begin"; | |
gestureBase = pos; | |
effect.add<GestureMarker>(Vec2(Window::BaseCenter().x + pos.x, Window::BaseCenter().y + 300 - pos.y)); | |
} | |
} | |
else | |
{ | |
beginGestureWait = 0; | |
} | |
} | |
// 手 | |
Circle(Window::BaseCenter().x + pos.x, Window::BaseCenter().y + 300 - pos.y, 20.0).draw(Color(255, 100)); | |
break; | |
} | |
} | |
effect.update(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment