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
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>
{
public:
SmallPlayerController(
GLFWwindow* window
);
void tick(
double deltaTimeSeconds)
override;
private:
void handleInput();
void shootRaycastAndSpawn();
void spawnCubeAt(const glm::vec3& position);
GLFWwindow* window_ = nullptr;
bool fireWasDown_ = false;
};
An Actor is similar to an Engine::Entities::Entity. An actor is an Entity with a transform.
virtual void beginPlay()
Gets executed when the actor is spawned into the world.
void tick(double deltaTime) override
Executed every frame.
Asset::Ref< Asset::MeshPath, Mesh > MeshAssetRef
Identifies a named mesh-like asset inside an asset file.
Scene ownership data passed to actor and component constructors during spawning.
#include "SmallPlayerController.h"
#include <glm/gtc/matrix_transform.hpp>
SmallPlayerController::SmallPlayerController(
GLFWwindow* window
) : Actor(context), window_(window)
{
);
cubeMeshAssetPath.fsPath(),
"Cube"
);
allowTicking_ = true;
enableTick(true);
}
void SmallPlayerController::beginPlay()
{
Actor::beginPlay();
auto* scene = getOwningScene();
auto* assets = scene ? scene->getAssetManager() : nullptr;
if (!assets) {
return;
}
}
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()
{
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)) {
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;
}
if (!cubeMeshRef_.isLoaded()) {
return;
}
}
#define CREATE_ASSET_PATH(assetPath)
creates an asset path with verification that it exists at the specified location on disk
The mesh asset stores geometry data and.
static constexpr auto engineGeometry()
Path to engine geometry assets @lsp_source_path Engine/geometry.
Core::PhysicsEngine * getPhysicsEngine() const
Getter for the pointer to the physics engine.
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...
Result data for physics raycasts and sweep tests.
glm::vec3 normal
World-space surface normal at the impact point.
glm::vec3 point
World-space impact point.
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 takes Asset::MeshPath, so the ref is used for readiness and the mesh 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.
{
public:
explicit DemoScene(GLFWwindow* window) : window_(window) {}
{
}
private:
GLFWwindow* window_ = nullptr;
};
{
return new DemoScene(getWindow());
}
A scene is the overarching structure which can spawn, contain and destroy actors or entities.
virtual void loadContent()
T * spawnActor(const Ecs::Transform &spawnTransform, Args &&... args)
Spawns an actor from a specific class in somewhere into the scene.
VR Trigger Variant
For VR input, read the trigger value from Input::XrInputHandler. Use the same edge-detection pattern.
const bool triggerIsDown =
if (triggerIsDown && !triggerWasDown_) {
shootRaycastAndSpawn();
}
triggerWasDown_ = triggerIsDown;
Input::XrInputHandler * getXrInputHandler() const
Getter for the XR input handler.
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.
- Use Asset::MeshPath for named objects inside glTF files.
- Use Asset::Path for single-file assets such as audio clips and standalone textures.
- 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.