Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
Small Player Controller Handbook

This page shows a small player controller that reads input, shoots a physics raycast, and spawns an actor from a key press.

The engine does not currently expose a desktop input manager. Use GLFW for desktop keys and Input::XrInputHandler for OpenXR controller values.

APIs Used

Task API
Desktop key state glfwGetKey(GLFWwindow*, GLFW_KEY_*)
VR trigger value Input::XrInputHandler::getTriggerValue(Input::Hand)
Physics engine Engine::EngineKern::getPhysicsEngine()
Raycast Engine::Core::PhysicsEngine::raycastClosest(origin, direction, maxDistance, hit)
Mesh asset reference Engine::Assets::MeshAssetRef
Spawn actor Engine::Entities::Scene::spawnActor<T>(transform, args...)

Controller Actor

Pass the mirror window into the controller when the scene spawns it. The actor polls keys in tick() and edge-detects key presses so actions run once per press.

#pragma once
#include <GLFW/glfw3.h>
class SmallPlayerController : public Engine::Entities::Actor
{
public:
SmallPlayerController(
const std::shared_ptr<Engine::Entities::SceneNode>& node,
GLFWwindow* window
);
void beginPlay() override;
void tick(double deltaTimeSeconds) override;
private:
void handleInput();
void shootRaycastAndSpawn();
void spawnCubeAt(const glm::vec3& position);
Asset::Path cubeMeshPath_;
GLFWwindow* window_ = nullptr;
bool fireWasDown_ = false;
};
An Actor is similar to an Engine::Entities::Entity. An actor is an Entity with a transform.
Definition Actor.h:20
virtual void beginPlay()
Gets executed when the actor is spawned into the world.
void tick(double deltaTime) override
Executed every frame.
A scene is the overarching structure which can spawn, contain and destroy actors or entities.
Definition Scene.h:56
Asset::Ref< Asset::Path, Mesh > MeshAssetRef
#include "SmallPlayerController.h"
#include <glm/gtc/matrix_transform.hpp>
SmallPlayerController::SmallPlayerController(
const std::shared_ptr<Engine::Entities::SceneNode>& node,
GLFWwindow* window
) : Actor(node, owningScene), window_(window)
{
constexpr static auto cubeMeshAssetPath = CREATE_ASSET_PATH(
Engine::Core::Path::engineGeometry() / "Defaults/cube_with_two_materials/two_material_cube.gltf"
);
cubeMeshPath_ = Asset::Path(
cubeMeshAssetPath,
"Cube"
);
allowTicking_ = true;
enableTick(true);
}
void SmallPlayerController::beginPlay()
{
Actor::beginPlay();
auto* scene = getOwningScene();
auto* assets = scene ? scene->getAssetManager() : nullptr;
if (!assets) {
return;
}
cubeMeshRef_ = assets->getAsset<Engine::Assets::Mesh>(cubeMeshPath_);
}
void SmallPlayerController::tick(double deltaTimeSeconds)
{
Actor::tick(deltaTimeSeconds);
handleInput();
}
void SmallPlayerController::handleInput()
{
if (!window_) {
return;
}
const bool fireIsDown = glfwGetKey(window_, GLFW_KEY_F) == GLFW_PRESS;
if (fireIsDown && !fireWasDown_) {
shootRaycastAndSpawn();
}
fireWasDown_ = fireIsDown;
}
void SmallPlayerController::shootRaycastAndSpawn()
{
auto* physics = engine ? engine->getPhysicsEngine() : nullptr;
if (!physics) {
return;
}
const glm::vec3 origin = getActorLocation();
const glm::vec3 direction = glm::normalize(
glm::vec3(getWorldTransform() * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f))
);
if (physics->raycastClosest(origin, direction, 100.0f, hit)) {
spawnCubeAt(hit.point + hit.normal * 0.5f);
return;
}
spawnCubeAt(origin + direction * 3.0f);
}
void SmallPlayerController::spawnCubeAt(const glm::vec3& position)
{
auto* scene = getOwningScene();
auto* assets = scene ? scene->getAssetManager() : nullptr;
if (!assets) {
return;
}
cubeMeshRef_ = assets->getAsset<Engine::Assets::Mesh>(cubeMeshPath_);
if (!cubeMeshRef_.isLoaded()) {
return;
}
Engine::Ecs::LocalTransform transform;
transform.setPosition(position);
scene->spawnActor<Engine::Entities::StaticMeshActor>(transform, cubeMeshPath_);
}
#define CREATE_ASSET_PATH(assetPath)
Definition Path.h:153
The mesh asset stores geometry data and.
Definition MeshAsset.h:20
static constexpr auto engineGeometry()
Path to engine geometry assets.
Definition Path.h:112
Core::PhysicsEngine * getPhysicsEngine() const
Getter for the pointer to the physics engine.
Definition Engine.h:275
static EngineManager & getInstance()
gets a reference to the engine manager
EngineKern * getEngineModule()
gets the pointer to the engine object
Wrapper for entt component creation which ensures types safety and attaches the correct component wit...

Engine::Assets::MeshAssetRef keeps a stable handle to the mesh record while the model loads asynchronously. getAsset<Engine::Assets::Mesh>() returns that ref and requests the backing model when needed. Use isLoaded() on the returned ref before spawning when the actor needs the mesh immediately. StaticMeshActor still takes Asset::Path, so the ref is used for readiness and the path is passed to the actor constructor.

Scene Setup

GameModule owns the GLFW window pointer. Pass it to the scene, then pass it to the player controller when spawning the actor.

class DemoScene : public Engine::Entities::Scene
{
public:
explicit DemoScene(GLFWwindow* window) : window_(window) {}
void loadContent() override
{
Engine::Ecs::LocalTransform playerTransform;
playerTransform.setPosition({ 0.0f, 1.6f, 4.0f });
spawnActor<SmallPlayerController>(playerTransform, window_);
}
private:
GLFWwindow* window_ = nullptr;
};
Engine::Entities::Scene* DemoGame::loadInitialScene()
{
return new DemoScene(getWindow());
}
virtual void loadContent()
T * spawnActor(const Ecs::Transform &spawnTransform, Args &&... args)
Spawns an actor from a specific class in somewhere into the scene.
Definition Scene.h:72

VR Trigger Variant

For VR input, read the trigger value from Input::XrInputHandler. Use the same edge-detection pattern.

auto* input = engine ? engine->getXrInputHandler() : nullptr;
const bool triggerIsDown =
input && input->getTriggerValue(Input::Hand::RIGHT) > 0.8f;
if (triggerIsDown && !triggerWasDown_) {
shootRaycastAndSpawn();
}
triggerWasDown_ = triggerIsDown;
Input::XrInputHandler * getXrInputHandler() const
Getter for the XR input handler.
Definition Engine.h:113
float getTriggerValue(Hand hand) const
Gets the trigger value for the specified hand (0.0 to 1.0)

Use Input::XrInputHandler::getHandPoseInfo(Input::Hand::RIGHT) when the ray should come from the controller aim pose instead of the player actor transform.

Notes

  • spawnActor<T>() calls beginPlay() before returning the actor pointer.
  • Set allowTicking_ = true before enableTick(true) for actors that need tick().
  • Request reusable assets in beginPlay() and store an Asset::Ref for readiness checks.
  • StaticMeshActor creates a CollidableMesh component for the mesh path.
  • The ray only hits objects registered in Bullet's dynamics world.
  • Use key edge detection for spawning. Polling GLFW_PRESS directly spawns one actor every frame while the key is held.