--- /dev/null
+head_elevation 1.65;
+camera
+{
+ near_clip 0.05;
+ far_clip 20.0;
+};
+shadow
+{
+ radius 15.0;
+};
--- /dev/null
+palm_shape
+{
+ box
+ {
+ extent 0.04 0.1 0.14;
+ };
+ technique_name "checker.tech";
+};
+
+trigger_shape
+{
+ box
+ {
+ extent 0.05 0.12 0.16;
+ };
+};
+trigger_body
+{
+ report_collisions true;
+ corporeal false;
+};
+trigger_offset 0.045 0.0 0.0;
--- /dev/null
+palm_shape
+{
+ box
+ {
+ extent 0.04 0.1 0.14;
+ };
+ technique_name "checker.tech";
+};
+
+trigger_shape
+{
+ box
+ {
+ extent 0.05 0.12 0.16;
+ };
+};
+trigger_body
+{
+ report_collisions true;
+ corporeal false;
+};
+trigger_offset -0.045 0.0 0.0;
--- /dev/null
+device VR_CONTROLLER;
+binding "grab_left"
+{
+ button { button 33; };
+};
add("pointer", pointer);
add("pick", pick);
}
+
+
+VRControls::VRControls()
+{
+ add("grab_left", grab_left);
+ add("grab_right", grab_right);
+}
Controls();
};
+
+struct VRControls: public Msp::Input::ControlScheme
+{
+ Msp::Input::BinaryControl grab_left;
+ Msp::Input::BinaryControl grab_right;
+
+ VRControls();
+};
+
#endif
--- /dev/null
+#include "hand.h"
+#include <msp/game/transform.h>
+#include "toy.h"
+
+using namespace Msp;
+
+Hand::Hand(Game::Handle<Game::Entity> e, const Setup &s):
+ Entity(e, Game::TransformValues()),
+ setup(s),
+ palm_shape(this, setup.palm_shape),
+ palm_body(this, setup.palm_body),
+ palm_motion(this),
+ trigger_entity(this, Game::TransformValues(s.trigger_offset)),
+ trigger_shape(trigger_entity, setup.trigger_shape),
+ trigger_body(trigger_entity, setup.trigger_body)
+{
+ palm_body->set_kinematic(true);
+}
--- /dev/null
+#ifndef HAND_H_
+#define HAND_H_
+
+#include <msp/game/entity.h>
+#include <msp/game/motion.h>
+#include <msp/game/rigidbody.h>
+#include <msp/game/shape.h>
+#include <msp/game/weld.h>
+#include "playground/setups.h"
+
+class Toy;
+
+class Hand: public Msp::Game::Entity
+{
+public:
+ using Setup = HandSetup;
+
+private:
+ const Setup &setup;
+
+ Msp::Game::Owned<Msp::Game::Shape> palm_shape;
+ Msp::Game::Owned<Msp::Game::RigidBody> palm_body;
+ Msp::Game::Owned<Msp::Game::Motion> palm_motion;
+
+ Msp::Game::Owned<Msp::Game::Entity> trigger_entity;
+ Msp::Game::Owned<Msp::Game::Shape> trigger_shape;
+ Msp::Game::Owned<Msp::Game::RigidBody> trigger_body;
+
+public:
+ Hand(Msp::Game::Handle<Msp::Game::Entity>, const Setup &);
+
+ Msp::Game::Handle<Msp::Game::Shape> get_trigger_shape() const { return trigger_shape; }
+};
+
+#endif
--- /dev/null
+#include "handpicker.h"
+#include <msp/gameview/trackedelement.h>
+#include "controls.h"
+#include "hand.h"
+#include "toy.h"
+
+using namespace Msp;
+
+HandPicker::HandPicker(Game::Stage &s):
+ System(s),
+ event_observer(stage.get_event_bus()),
+ left_setup(stage.get_resources().get<HandSetup>("left.hand.setup")),
+ right_setup(stage.get_resources().get<HandSetup>("right.hand.setup"))
+{
+ event_observer.observe<Game::Events::ComponentCreated>([this](auto &e){ component_created(e); });
+ event_observer.observe<Game::Events::EntityDestroyed>([this](auto &e){ entity_destroyed(e); });
+ event_observer.observe<Game::Events::Collision>([this](auto &e){ collision(e); });
+}
+
+HandPicker::~HandPicker() = default;
+
+void HandPicker::set_controls(VRControls *c)
+{
+ controls = c;
+}
+
+void HandPicker::component_created(const Game::Events::ComponentCreated &event)
+{
+ if(auto tracked = dynamic_handle_cast<GameView::TrackedElement>(event.component))
+ {
+ if(tracked->get_role()==GameView::TrackedElement::LEFT_HAND)
+ left_hand.hand = Game::Owned<Hand>(tracked->get_entity(), left_setup);
+ else if(tracked->get_role()==GameView::TrackedElement::RIGHT_HAND)
+ right_hand.hand = Game::Owned<Hand>(tracked->get_entity(), right_setup);
+ }
+}
+
+void HandPicker::entity_destroyed(const Game::Events::EntityDestroyed &event)
+{
+ if(left_hand.hand && event.entity==left_hand.hand->get_parent())
+ left_hand.hand = nullptr;
+ else if(right_hand.hand && event.entity==right_hand.hand->get_parent())
+ right_hand.hand = nullptr;
+}
+
+void HandPicker::collision(const Game::Events::Collision &event)
+{
+ if(event.shape1==left_hand.hand->get_trigger_shape())
+ maybe_grab(left_hand, event.shape2->get_entity());
+ else if(event.shape1==right_hand.hand->get_trigger_shape())
+ maybe_grab(right_hand, event.shape2->get_entity());
+ else if(event.shape2==left_hand.hand->get_trigger_shape())
+ maybe_grab(left_hand, event.shape1->get_entity());
+ else if(event.shape2==right_hand.hand->get_trigger_shape())
+ maybe_grab(right_hand, event.shape1->get_entity());
+}
+
+void HandPicker::maybe_grab(TrackedHand &hand, Game::Handle<Game::Entity> target)
+{
+ if(hand.held_toy || !hand.grab_activated)
+ return;
+
+ auto toy = dynamic_handle_cast<Toy>(target);
+ if(!toy)
+ return;
+
+ defer([&hand, toy](){
+ hand.held_toy = toy;
+ hand.joint = Game::Owned<Game::Weld>(hand.hand, toy->get_rigid_body());
+ });
+}
+
+void HandPicker::release(TrackedHand &hand)
+{
+ defer([&hand](){
+ hand.joint = nullptr;
+ hand.held_toy = nullptr;
+ });
+}
+
+void HandPicker::tick(Time::TimeDelta)
+{
+ if(!controls)
+ return;
+
+ if(controls->grab_left.was_released())
+ release(left_hand);
+ else
+ left_hand.grab_activated = controls->grab_left.was_activated();
+
+ if(controls->grab_right.was_released())
+ release(right_hand);
+ else
+ right_hand.grab_activated = controls->grab_right.was_activated();
+
+ controls->reset_edges();
+}
--- /dev/null
+#ifndef HANDPICKER_H_
+#define HANDPICKER_H_
+
+#include <msp/game/joint.h>
+#include <msp/game/owned.h>
+#include <msp/game/system.h>
+#include "playground/setups.h"
+
+class Hand;
+class Toy;
+struct VRControls;
+
+class HandPicker: public Msp::Game::System
+{
+private:
+ struct TrackedHand
+ {
+ Msp::Game::Owned<Hand> hand;
+ Msp::Game::Handle<Toy> held_toy;
+ Msp::Game::Owned<Msp::Game::Joint> joint;
+ bool grab_activated = false;
+ };
+
+ Msp::Game::EventObserver event_observer;
+ const HandSetup &left_setup;
+ const HandSetup &right_setup;
+ VRControls *controls = nullptr;
+ TrackedHand left_hand;
+ TrackedHand right_hand;
+
+public:
+ HandPicker(Msp::Game::Stage &);
+ ~HandPicker();
+
+ void set_controls(VRControls *);
+
+private:
+ void component_created(const Msp::Game::Events::ComponentCreated &);
+ void entity_destroyed(const Msp::Game::Events::EntityDestroyed &);
+ void collision(const Msp::Game::Events::Collision &);
+ void maybe_grab(TrackedHand &, Msp::Game::Handle<Msp::Game::Entity>);
+ void release(TrackedHand &);
+
+public:
+ void tick(Msp::Time::TimeDelta) override;
+};
+
+#endif
--- /dev/null
+#include "player.h"
+
+using namespace Msp;
+
+Player::Player(Game::Handle<Game::Entity> p, const Setup &s, const Game::TransformValues &tv):
+ Entity(p, tv),
+ setup(s),
+ anchor(this),
+ shadow(this, setup.shadow),
+ head(this, Game::TransformValues({ 0.0f, 0.0f, setup.head_elevation },
+ Geometry::make_quat(40.0f*Geometry::degrees, { 0.0f, -1.0f, 0.0f })*
+ Geometry::make_quat(-90.0f*Geometry::degrees, { 0.0f, 0.0f, 1.0f }))),
+ camera(head, setup.camera)
+{ }
--- /dev/null
+#ifndef PLAYER_H_
+#define PLAYER_H_
+
+#include <msp/game/camera.h>
+#include <msp/game/entity.h>
+#include <msp/game/shadowtarget.h>
+#include <msp/game/trackinganchor.h>
+#include <msp/game/transform.h>
+#include "playground/setups.h"
+
+class Player: public Msp::Game::Entity
+{
+public:
+ using Setup = PlayerSetup;
+
+private:
+ const Setup &setup;
+ Msp::Game::Owned<Msp::Game::TrackingAnchor> anchor;
+ Msp::Game::Owned<Msp::Game::ShadowTarget> shadow;
+ Msp::Game::Owned<Msp::Game::Entity> head;
+ Msp::Game::Owned<Msp::Game::Camera> camera;
+
+public:
+ Player(Msp::Game::Handle<Msp::Game::Entity>, const Setup &, const Msp::Game::TransformValues & = {});
+};
+
+#endif
#include "playground.h"
#include <random>
+#include <msp/core/getopt.h>
#include <msp/game/physicssystem.h>
#include <msp/game/root.h>
#include <msp/game/stageplan.h>
#include "controls.h"
#include "fixture.h"
+#include "handpicker.h"
#include "mousepicker.h"
+#include "player.h"
#include "playground/setups.h"
#include "toy.h"
using namespace std;
using namespace Msp;
-Playground::Playground(int, char **):
+PlaygroundOptions::PlaygroundOptions(int argc, char **argv)
+{
+ GetOpt getopt;
+ getopt.add_option("vr", options.vr, GetOpt::NO_ARG).set_help("Enable virtual reality");
+ getopt(argc, argv);
+}
+
+Playground::Playground(int argc, char **argv):
+ PlaygroundOptions(argc, argv),
+ Application(options.vr ? VIRTUAL_REALITY : NO_FEATURES),
event_observer(director.get_event_bus()),
stage(director.create_stage("playground")),
- cam_entity(stage.get_root(), Game::TransformValues({ 0.0f, -1.5f, 1.5f }, Geometry::make_quat(45.0f*Geometry::degrees, { 1.0f, 0.0f, 0.0f }))),
- camera(cam_entity, resources.get<Game::CameraSetup>("playground.camera.setup")),
- shadow_setup{ 15.0f },
- shadow_target(cam_entity, shadow_setup),
+ player(stage.get_root(), resources.get<PlayerSetup>("default.player.setup"),
+ Game::TransformValues(get_player_position(options.vr), Geometry::make_quat(90.0f*Geometry::degrees, { 0.0f, 0.0f, 1.0f }))),
sun_entity(stage.get_root(), Game::TransformValues({}, Geometry::make_quat(30.0f*Geometry::degrees, { 1.0f, -0.5f, 0.0f }))),
sun(sun_entity, resources.get<Game::LightSetup>("sun.light.setup"))
{
event_observer.observe<GameView::Events::LocalPlayerArrived>([this](auto &e){ player_arrived(e); });
Game::PhysicsSystem &physics = stage.add_system<Game::PhysicsSystem>();
- mouse_picker = &stage.add_system<MousePicker>(physics);
+ if(options.vr)
+ hand_picker = &stage.add_system<HandPicker>();
+ else
+ mouse_picker = &stage.add_system<MousePicker>(physics);
stage.apply_plan(resources.get<Game::StagePlan>("playground.stage"));
vector<ToySetup *> toy_setups = resources.get_all<ToySetup>();
toys.emplace_back(stage.get_root(), setup, Game::TransformValues(pos, Geometry::Quaternion<float>::one()));
}
- player_input.set_control_scheme_type<Controls>();
+ if(options.vr)
+ player_input.set_control_scheme_type<VRControls>();
+ else
+ player_input.set_control_scheme_type<Controls>();
director.activate_stage(stage);
}
+LinAl::Vector<float, 3> Playground::get_player_position(bool vr)
+{
+ if(vr)
+ return { 0.0f, 0.0f, 0.0f };
+ else
+ return { 0.0f, -1.5f, 0.0f };
+}
+
void Playground::player_arrived(const GameView::Events::LocalPlayerArrived &e)
{
- mouse_picker->set_controls(dynamic_cast<Controls *>(&e.controls));
+ if(mouse_picker)
+ mouse_picker->set_controls(dynamic_cast<Controls *>(&e.controls));
+ if(hand_picker)
+ hand_picker->set_controls(dynamic_cast<VRControls *>(&e.controls));
}
PlaygroundResources::PlaygroundResources()
{
add_type<FixtureSetup>().suffix(".fixt.setup");
+ add_type<HandSetup>().suffix(".hand.setup");
+ add_type<PlayerSetup>().suffix(".player.setup");
add_type<ToySetup>().suffix(".toy.setup");
}
#ifndef PLAYGROUND_H_
#define PLAYGROUND_H_
-#include <msp/game/camera.h>
#include <msp/game/light.h>
#include <msp/game/owned.h>
#include <msp/game/resources.h>
-#include <msp/game/shadowtarget.h>
#include <msp/game/stage.h>
#include <msp/gameview/application.h>
#include <msp/gameview/resources.h>
+class HandPicker;
class MousePicker;
+class Player;
class Toy;
class PlaygroundResources: public Msp::Game::ApplicationResources, public Msp::GameView::Resources
PlaygroundResources();
};
-class Playground: public Msp::GameView::Application<Playground, PlaygroundResources>
+struct PlaygroundOptions
+{
+ struct Options
+ {
+ bool vr = false;
+ };
+
+ Options options;
+
+ PlaygroundOptions(int, char **);
+};
+
+class Playground: public PlaygroundOptions, public Msp::GameView::Application<Playground, PlaygroundResources>
{
private:
Msp::Game::EventObserver event_observer;
Msp::Game::Stage &stage;
MousePicker *mouse_picker = nullptr;
- Msp::Game::Owned<Msp::Game::Entity> cam_entity;
- Msp::Game::Owned<Msp::Game::Camera> camera;
- Msp::Game::ShadowTargetSetup shadow_setup;
- Msp::Game::Owned<Msp::Game::ShadowTarget> shadow_target;
+ HandPicker *hand_picker = nullptr;
+ Msp::Game::Owned<Player> player;
Msp::Game::Owned<Msp::Game::Entity> sun_entity;
Msp::Game::Owned<Msp::Game::Light> sun;
std::vector<Msp::Game::Owned<Toy>> toys;
Playground(int, char **);
private:
+ static Msp::LinAl::Vector<float, 3> get_player_position(bool);
+
void player_arrived(const Msp::GameView::Events::LocalPlayerArrived &);
};
field shape Shape;
field body RigidBody;
};
+
+entity Hand
+{
+ field palm_shape Shape;
+ field palm_body RigidBody;
+ field trigger_shape Shape;
+ field trigger_body RigidBody;
+ field trigger_offset vector3;
+};
+
+entity Player
+{
+ field camera Camera;
+ field head_elevation float;
+ field shadow ShadowTarget;
+};