Compare commits

...

10 commits

Author SHA1 Message Date
Sara 1b7b915548 feat: removed grid 2024-10-04 11:13:53 +02:00
Sara 315ae2d3b4 feat: implemented city generator 2024-10-04 11:12:13 +02:00
Sara 0ca2972218 feat: started work on city generation 2024-10-01 10:25:43 +02:00
Sara b60cf6cb6c feat: added boost 2024-10-01 10:25:35 +02:00
Sara 4d28ff8829 feat: lowered yaw speed 2024-09-27 16:12:27 +02:00
Sara f79fda16e9 feat: added yaw keys 2024-09-27 16:08:21 +02:00
Sara a9bc57a175 feat: improved slerp amount argument for camera controller 2024-09-27 16:07:58 +02:00
Sara 30d8182f4d feat: added get child by typeid function with option to recurse 2024-09-27 10:34:43 +02:00
Sara b3f9d7222e chore: updated utils 2024-09-27 10:34:43 +02:00
Sara 2fbc198d7d feat: CameraNode fov is now configurable 2024-09-27 10:34:43 +02:00
21 changed files with 186 additions and 53 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
resources/building_a.glb Normal file

Binary file not shown.

BIN
resources/building_b.glb Normal file

Binary file not shown.

BIN
resources/building_c.glb Normal file

Binary file not shown.

BIN
resources/building_d.glb Normal file

Binary file not shown.

View file

@ -1,4 +1,5 @@
#include "camera_controller.h" #include "camera_controller.h"
#include "core/camera_node.h"
#include "utils/mirror.h" #include "utils/mirror.h"
START_REFLECT(CameraController); START_REFLECT(CameraController);
@ -18,10 +19,11 @@ SceneNode *CreateCameraController(Transformable target) {
CameraController *self = new(CameraController); CameraController *self = new(CameraController);
*self = (CameraController){ *self = (CameraController){
.transform = tc_null(Transformable), .transform = tc_null(Transformable),
.rotation_speed = 5.f, .rotation_speed = 2.f,
.max_speed_time = 4.f, .max_speed_time = 4.f,
.target = target, .target = target,
.time_rotated = 0.f .time_rotated = 0.f,
.camera = NULL,
}; };
SceneNode *node = CreateSceneNode(CameraController_as_SceneNodeEntity(self)); SceneNode *node = CreateSceneNode(CameraController_as_SceneNodeEntity(self));
return node; return node;
@ -34,6 +36,9 @@ void DestroyCameraController(CameraController *self) {
void CameraControllerEnterTree(CameraController *self) { void CameraControllerEnterTree(CameraController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable); self->transform = TC_CAST(self->node->parent->entity, Transformable);
self->global = self->transform.tc->get_global_transform(self->transform.data); self->global = self->transform.tc->get_global_transform(self->transform.data);
SceneNode *camera_node = SceneNodeGetChildByTypeid(self->node->parent, GET_TYPEID(CameraNode), true);
self->camera = camera_node->entity.data;
self->camera->fov = 100;
} }
void CameraControllerExitTree(CameraController *self) {} void CameraControllerExitTree(CameraController *self) {}
@ -49,11 +54,10 @@ void CameraControllerTick(CameraController *self, double delta) {
// ... and maximum frame step size // ... and maximum frame step size
float const step = self->rotation_speed * time_mul * delta; float const step = self->rotation_speed * time_mul * delta;
if(angle > 0.f) if(angle > 0.f)
target.rotation = QuaternionSlerp(current.rotation, target.rotation, fminf(fminf(step, angle) / angle, 0.99f)); target.rotation = QuaternionSlerp(current.rotation, target.rotation, step);
if(step > angle && self->time_rotated > delta) if(step > angle && self->time_rotated > delta)
self->time_rotated -= 3.f * delta; self->time_rotated -= delta;
else if(step > angle) else
self->time_rotated = 0.f; self->time_rotated += delta;
self->time_rotated += delta;
self->transform.tc->set_global_transform(self->transform.data, target); self->transform.tc->set_global_transform(self->transform.data, target);
} }

View file

@ -14,6 +14,7 @@ typedef struct CameraController {
float max_speed_time; float max_speed_time;
Transformable target; Transformable target;
float time_rotated; float time_rotated;
CameraNode *camera;
} CameraController; } CameraController;
extern SceneNode *CreateCameraController(Transformable target); extern SceneNode *CreateCameraController(Transformable target);

45
src/city_generator.c Normal file
View file

@ -0,0 +1,45 @@
#include "city_generator.h"
#include "core/mesh_render_entity.h"
#include "core/transform_node.h"
static struct {
size_t x, y;
} const CITY_SIZE = {20, 20};
#define MODELS_LENGTH 4
static ModelResource models[MODELS_LENGTH] = {
ResourceEmpty(Model),
ResourceEmpty(Model),
ResourceEmpty(Model),
ResourceEmpty(Model)
};
static void Internal_LoadModelsIfRequired() {
for(size_t i = 0; i < MODELS_LENGTH; ++i)
if(models[i].handle == NULL && GetModelResource(TextFormat("building_%c", 'a' + i), &models[i]))
LoadResource(models[i].handle);
}
static SceneNode *Internal_CreateBuilding(size_t x, size_t y) {
size_t building_index = (3 * (x + y + GetRandomValue(0, 50))) % MODELS_LENGTH; // semi-random number based on the x,y coordinate
SceneNode *mesh_render_node = CreateMeshRenderEntity(TextFormat("building_%c", 'a' + building_index));
SceneNode *transform_node = CreateTransformNode();
SceneNodeAddChild(transform_node, mesh_render_node);
Transformable transform = TC_CAST(transform_node->entity, Transformable);
Transform local = transform.tc->get_transform(transform.data);
local.translation.x = (float)(x * 40);
local.translation.z = (float)(y * 40);
transform.tc->set_transform(transform.data, local);
return transform_node;
}
SceneNode *GenerateCity() {
Internal_LoadModelsIfRequired();
SceneNode *root = CreateTransformNode();
for(size_t x = 0; x < CITY_SIZE.x; ++x) {
for(size_t y = 0; y < CITY_SIZE.y; ++y) {
SceneNodeAddChild(root, Internal_CreateBuilding(x, y));
}
}
return root;
}

8
src/city_generator.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef CITY_GENERATOR_H
#define CITY_GENERATOR_H
#include "core/scene.h"
extern SceneNode *GenerateCity();
#endif // !CITY_GENERATOR_H

View file

@ -20,6 +20,11 @@ impl_SceneNodeEntity_for(CameraNode,
SceneNode *CreateCameraNode() { SceneNode *CreateCameraNode() {
CameraNode *self = new(CameraNode); CameraNode *self = new(CameraNode);
*self = (CameraNode){
.fov = 60,
.node = NULL,
.transform = tc_null(Transformable)
};
return CreateSceneNode(CameraNode_as_SceneNodeEntity(self)); return CreateSceneNode(CameraNode_as_SceneNodeEntity(self));
} }
@ -51,7 +56,7 @@ Camera3D CameraNodeGetCamera(CameraNode *self) {
Vector3 forward = MATRIX_FORWARD(mat); Vector3 forward = MATRIX_FORWARD(mat);
// construct a new camera at the global transform location and facing the forward vector // construct a new camera at the global transform location and facing the forward vector
return (Camera3D){ return (Camera3D){
.fovy = 90, .fovy = self->fov,
.position = global_transform.translation, .position = global_transform.translation,
.projection = CAMERA_PERSPECTIVE, .projection = CAMERA_PERSPECTIVE,
.target = Vector3Add(global_transform.translation, forward), .target = Vector3Add(global_transform.translation, forward),

View file

@ -10,6 +10,7 @@
typedef struct CameraNode { typedef struct CameraNode {
SceneNode *node; SceneNode *node;
Transformable transform; Transformable transform;
float fov;
} CameraNode; } CameraNode;
//! Instantiate new camera node //! Instantiate new camera node

View file

@ -54,7 +54,6 @@ void RenderNextFrame() {
BeginMode3D(CameraNodeGetCamera(camera)); BeginMode3D(CameraNodeGetCamera(camera));
list_foreach(Renderable *,object, &g_render_objects) list_foreach(Renderable *,object, &g_render_objects)
object->tc->draw(object->data); object->tc->draw(object->data);
DrawGrid(500, 1.f); // TODO Remove this (or make it a scene node entity)
EndMode3D(); EndMode3D();
} }
DrawFPS(20, 20); DrawFPS(20, 20);

View file

@ -132,9 +132,9 @@ bool GetModelResource(char const *path, ModelResource *out) {
ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path); ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path);
*out = ResourceEmpty(Model); *out = ResourceEmpty(Model);
// assert some assumptions about the found resource // assert some assumptions about the found resource
ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path); ASSERT_RETURN(container != NULL, false, "GetModelResource: Resource %s not in index.", path);
ASSERT_RETURN(container->type == RESOURCE_MODEL, false, "GetTextureResource: Resource %s is not a Texture.", path); ASSERT_RETURN(container->type == RESOURCE_MODEL, false, "GetModelResource: Resource %s is not a Texture.", path);
++container->use_counter; ASSERT_RETURN(strcmp(container->name, path) == 0, false, "GetModelResource: Resource %s was loaded for path %s", container->name, path);
*out = (ModelResource) { *out = (ModelResource) {
.handle = container, .handle = container,
.resource = &container->model .resource = &container->model
@ -174,16 +174,20 @@ bool IsResourceLoaded(ResourceHandle handle) {
void LoadResource(ResourceHandle handle) { void LoadResource(ResourceHandle handle) {
ASSERT_RETURN(handle != NULL,, "LoadResource: Resource handle invalid"); ASSERT_RETURN(handle != NULL,, "LoadResource: Resource handle invalid");
g_load_functions[handle->type](handle); if(!handle->is_loaded) {
handle->is_loaded = true; g_load_functions[handle->type](handle);
handle->is_loaded = true;
}
++handle->use_counter; ++handle->use_counter;
} }
void ReleaseResource(ResourceHandle handle) { void ReleaseResource(ResourceHandle handle) {
ASSERT_RETURN(handle != NULL,, "ReleaseResource: Resource handle invalid"); ASSERT_RETURN(handle != NULL,, "ReleaseResource: Resource handle invalid");
ASSERT_RETURN_WARN(handle->is_loaded,, "ReleaseResource: Resource %s is not loaded.", handle->path); ASSERT_RETURN_WARN(handle->is_loaded,, "ReleaseResource: Resource %s is not loaded.", handle->path);
g_unload_functions[handle->type](handle); if(handle->use_counter == 1) {
handle->is_loaded = false; g_unload_functions[handle->type](handle);
handle->is_loaded = false;
}
--handle->use_counter; --handle->use_counter;
} }

View file

@ -170,8 +170,23 @@ SceneNode *SceneNodeGetChildByTypeclass(SceneNode *self, char const *typeclass,
SceneNodeEntity entity = (*child)->entity; SceneNodeEntity entity = (*child)->entity;
if(mirror_get_function(entity.data, entity.mirror, typeclass)) if(mirror_get_function(entity.data, entity.mirror, typeclass))
return *child; return *child;
if(recurse) if(recurse) {
SceneNodeGetChildByTypeclass(*child, typeclass, recurse); SceneNode *recursed = SceneNodeGetChildByTypeclass(*child, typeclass, recurse);
if(recursed != NULL) return recursed;
}
}
return NULL;
}
SceneNode *SceneNodeGetChildByTypeid(SceneNode *self, typeid id, bool recurse) {
list_foreach(SceneNode **,child, &self->children) {
SceneNodeEntity entity = (*child)->entity;
if(entity.mirror->get_typeid() == id)
return *child;
if(recurse) {
SceneNode *recursed = SceneNodeGetChildByTypeid(*child, id, recurse);
if(recursed != NULL) return recursed;
}
} }
return NULL; return NULL;
} }

View file

@ -41,10 +41,12 @@ extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child);
extern void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity); extern void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity);
//! Detach an entity from a scene node //! Detach an entity from a scene node
extern SceneNodeEntity SceneNodeDetachEntity(SceneNode *self); extern SceneNodeEntity SceneNodeDetachEntity(SceneNode *self);
//! Returns the first child node that implements a specific typeclass. //! Returns the first child node with an entity that implements a specific typeclass.
//! Optionally recurses through the entire branch //! Optionally recurses through the entire branch
extern SceneNode *SceneNodeGetChildByTypeclass(SceneNode *self, char const *typeclass, bool recurse); extern SceneNode *SceneNodeGetChildByTypeclass(SceneNode *self, char const *typeclass, bool recurse);
//! Returns the first child node with an entity that matches the given typeid.
//! Optionally recurses through the entire branch.
extern SceneNode *SceneNodeGetChildByTypeid(SceneNode *self, typeid id, bool recurse);
//! Instantiate a new scene with a root node. //! Instantiate a new scene with a root node.
extern Scene *CreateScene(SceneNode *root); extern Scene *CreateScene(SceneNode *root);
//! Destroy a node and it's scene tree. //! Destroy a node and it's scene tree.

View file

@ -1,6 +1,7 @@
#include "raylib.h" #include "raylib.h"
#include "player_controller.h" #include "player_controller.h"
#include "camera_controller.h" #include "camera_controller.h"
#include "city_generator.h"
#include "core/input.h" #include "core/input.h"
#include "core/camera_node.h" #include "core/camera_node.h"
#include "core/engine_global.h" #include "core/engine_global.h"
@ -48,6 +49,7 @@ Scene *CreateInitialScene() {
SceneNodeAddChild(root, model); SceneNodeAddChild(root, model);
SceneNodeAddChild(root, camera_scene); SceneNodeAddChild(root, camera_scene);
SceneNodeAddChild(camera_scene, CreateCameraController(TC_CAST(model->entity, Transformable))); SceneNodeAddChild(camera_scene, CreateCameraController(TC_CAST(model->entity, Transformable)));
SceneNodeAddChild(root, GenerateCity());
return CreateScene(root); return CreateScene(root);
} }
@ -56,7 +58,10 @@ void ConfigureInput() {
AddAction("pitch_down", INPUT_LISTENER_KEY, 0, KEY_W); AddAction("pitch_down", INPUT_LISTENER_KEY, 0, KEY_W);
AddAction("roll_left", INPUT_LISTENER_KEY, 0, KEY_A); AddAction("roll_left", INPUT_LISTENER_KEY, 0, KEY_A);
AddAction("roll_right", INPUT_LISTENER_KEY, 0, KEY_D); AddAction("roll_right", INPUT_LISTENER_KEY, 0, KEY_D);
AddAction("stop", INPUT_LISTENER_KEY, 0, KEY_SPACE); AddAction("yaw_right", INPUT_LISTENER_KEY, 0, KEY_E);
AddAction("yaw_left", INPUT_LISTENER_KEY, 0, KEY_Q);
AddAction("brake", INPUT_LISTENER_KEY, 0, KEY_SPACE);
AddAction("boost", INPUT_LISTENER_KEY, 0, KEY_LEFT_SHIFT);
} }
int main() { int main() {

View file

@ -1,7 +1,8 @@
#include "player_controller.h" #include "player_controller.h"
#include "core/render.h" #include "core/render.h"
#include "utils/debug.h"
#include "core/input.h" #include "core/input.h"
#include "utils/typeclass_helpers.h"
#include "utils/debug.h"
#include "raylib.h" #include "raylib.h"
START_REFLECT(PlayerController); START_REFLECT(PlayerController);
@ -19,10 +20,25 @@ impl_SceneNodeEntity_for(PlayerController,
PlayerControllerTick PlayerControllerTick
) )
static float const PLAYER_BASE_SPEED = 10.f;
static float const PLAYER_BASE_ACCELERATION = 10.f;
static float const PLAYER_BOOST_SPEED = 30.f;
static float const PLAYER_BOOST_ACCELERATION = 60.f;
static float const PLAYER_BRAKE_SPEED = 0.5f;
static float const PLAYER_BRAKE_DECELERATION = 10.f;
static float const PLAYER_FALL_SPEED = 10.f;
static float const PLAYER_FALL_ACCELERATION = 10.f;
SceneNode *CreatePlayerController() { SceneNode *CreatePlayerController() {
PlayerController *self = new(PlayerController); PlayerController *self = new(PlayerController);
self->rotation = self->fly_input = Vector2Zero(); *self = (PlayerController) {
self->stopped = false; .node = NULL,
.transform = tc_null(Transformable),
.rotation = Vector3Zero(),
.fly_input = Vector3Zero(),
.speed = 10.f,
.brake = false
};
return CreateSceneNode(PlayerController_as_SceneNodeEntity(self)); return CreateSceneNode(PlayerController_as_SceneNodeEntity(self));
} }
@ -33,32 +49,42 @@ void DestroyPlayerController(PlayerController *self) {
void PlayerControllerEnterTree(PlayerController *self) { void PlayerControllerEnterTree(PlayerController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable); self->transform = TC_CAST(self->node->parent->entity, Transformable);
DisableCursor(); DisableCursor();
AddListener("pitch_up", ButtonInputListener(self, PlayerControllerUpInput)); AddListener("pitch_up", ButtonInputListener(self, PlayerControllerInputPitchUp));
AddListener("pitch_down", ButtonInputListener(self, PlayerControllerDownInput)); AddListener("pitch_down", ButtonInputListener(self, PlayerControllerInputPitchDown));
AddListener("roll_left", ButtonInputListener(self, PlayerControllerLeftInput)); AddListener("roll_left", ButtonInputListener(self, PlayerControllerInputRollLeft));
AddListener("roll_right", ButtonInputListener(self, PlayerControllerRightInput)); AddListener("roll_right", ButtonInputListener(self, PlayerControllerInputRollRight));
AddListener("stop", ButtonInputListener(self, PlayerControllerStopInput)); AddListener("yaw_left", ButtonInputListener(self, PlayerControllerInputYawLeft));
AddListener("yaw_right", ButtonInputListener(self, PlayerControllerInputYawRight));
AddListener("brake", ButtonInputListener(self, PlayerControllerInputBrake));
AddListener("boost", ButtonInputListener(self, PlayerControllerInputBoost));
} }
void PlayerControllerExitTree(PlayerController *self) { void PlayerControllerExitTree(PlayerController *self) {
RemoveAllListeners(self); RemoveAllListeners(self);
} }
static
float MoveTowards(float from, float to, float delta) {
if(from == to) return to;
float const diff = to - from;
float const sign = signbit(diff) ? -1.f : 1.f;
return from + sign * fminf(delta, fabsf(diff));
}
//! angular acceleration limited to local X and Z axes //! angular acceleration limited to local X and Z axes
static static
void PlayerControllerTickAngularAcceleration(PlayerController *self, double delta) { void PlayerControllerTickAngularAcceleration(PlayerController *self, double delta) {
Vector2 diff = Vector2Subtract(self->fly_input, self->rotation); self->rotation.x = MoveTowards(self->rotation.x, self->fly_input.x, delta * 4.f);
float const length = Vector2Length(diff); self->rotation.y = MoveTowards(self->rotation.y, self->fly_input.y, delta * 4.f);
if(length != 0.f) self->rotation.z = MoveTowards(self->rotation.z, self->fly_input.z, delta * 4.f);
self->rotation = Vector2Add(self->rotation, Vector2Scale(diff, 1.0f/length * fminf(4.f * delta, length)));
} }
//! linear acceleration limited to the local Z axis //! linear acceleration limited to the local Z axis
static static
void PlayerControllerTickLinearAcceleration(PlayerController *self, double delta) { void PlayerControllerTickLinearAcceleration(PlayerController *self, double delta) {
float const target = self->stopped ? 10.f : (self->rotation.y == 0.f ? 30.f : 20.f); float const target = self->brake ? PLAYER_BRAKE_SPEED : (self->boost ? PLAYER_BOOST_SPEED : PLAYER_BASE_SPEED);
float const speed_diff = target - self->speed; float const acceleration = target < self->speed ? PLAYER_BRAKE_DECELERATION : (self->boost ? PLAYER_BOOST_ACCELERATION : PLAYER_BASE_ACCELERATION);
self->speed = self->speed + copysignf(fminf(fabsf(speed_diff), 10.f * delta), speed_diff); self->speed = MoveTowards(self->speed, target, delta * acceleration);
} }
//! Update linear transform based on velocities //! Update linear transform based on velocities
@ -66,9 +92,11 @@ static
void PlayerControllerTickTransform(PlayerController *self, double delta) { void PlayerControllerTickTransform(PlayerController *self, double delta) {
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data); Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
Matrix global_matrix = TransformGetMatrix(global_transform); Matrix global_matrix = TransformGetMatrix(global_transform);
float const rotate_speed = 1.f - 0.9f * self->speed / PLAYER_BOOST_SPEED;
global_transform.translation = Vector3Add(global_transform.translation, Vector3Scale(MATRIX_FORWARD(global_matrix), self->speed * delta)); global_transform.translation = Vector3Add(global_transform.translation, Vector3Scale(MATRIX_FORWARD(global_matrix), self->speed * delta));
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_FORWARD(global_matrix), self->rotation.x * 2.f * delta), global_transform.rotation); global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_FORWARD(global_matrix), self->rotation.x * 1.25f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), self->rotation.y * 2.5f * delta), global_transform.rotation); global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_RIGHT(global_matrix), self->rotation.y * rotate_speed * 3.75f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_UP(global_matrix), self->rotation.z * rotate_speed * 1.f * delta), global_transform.rotation);
self->transform.tc->set_global_transform(self->transform.data, global_transform); self->transform.tc->set_global_transform(self->transform.data, global_transform);
} }
@ -78,22 +106,34 @@ void PlayerControllerTick(PlayerController *self, double delta) {
PlayerControllerTickTransform(self, delta); PlayerControllerTickTransform(self, delta);
} }
void PlayerControllerLeftInput(PlayerController *self, bool value) { void PlayerControllerInputRollLeft(PlayerController *self, bool value) {
self->fly_input.x += value ? -1 : +1; self->fly_input.x += value ? -1 : +1;
} }
void PlayerControllerRightInput(PlayerController *self, bool value) { void PlayerControllerInputRollRight(PlayerController *self, bool value) {
self->fly_input.x += value ? +1 : -1; self->fly_input.x += value ? +1 : -1;
} }
void PlayerControllerUpInput(PlayerController *self, bool value) { void PlayerControllerInputPitchUp(PlayerController *self, bool value) {
self->fly_input.y += value ? -1 : +1; self->fly_input.y += value ? -1 : +1;
} }
void PlayerControllerDownInput(PlayerController *self, bool value) { void PlayerControllerInputPitchDown(PlayerController *self, bool value) {
self->fly_input.y += value ? +1 : -1; self->fly_input.y += value ? +1 : -1;
} }
void PlayerControllerStopInput(PlayerController *self, bool value) { void PlayerControllerInputYawRight(PlayerController *self, bool value) {
self->stopped = value; self->fly_input.z += value ? -1 : +1;
}
void PlayerControllerInputYawLeft(PlayerController *self, bool value) {
self->fly_input.z += value ? +1 : -1;
}
void PlayerControllerInputBrake(PlayerController *self, bool value) {
self->brake = value;
}
void PlayerControllerInputBoost(PlayerController *self, bool value) {
self->boost = value;
} }

View file

@ -12,10 +12,11 @@
typedef struct PlayerController { typedef struct PlayerController {
SceneNode *node; SceneNode *node;
Transformable transform; Transformable transform;
Vector2 fly_input; Vector3 fly_input;
Vector2 rotation; Vector3 rotation;
float speed; float speed;
bool stopped; bool brake;
bool boost;
} PlayerController; } PlayerController;
SceneNode *CreatePlayerController(); SceneNode *CreatePlayerController();
@ -25,11 +26,14 @@ extern void PlayerControllerEnterTree(PlayerController *self);
extern void PlayerControllerExitTree(PlayerController *self); extern void PlayerControllerExitTree(PlayerController *self);
extern void PlayerControllerTick(PlayerController *self, double delta); extern void PlayerControllerTick(PlayerController *self, double delta);
extern void PlayerControllerLeftInput(PlayerController *self, bool value); extern void PlayerControllerInputRollLeft(PlayerController *self, bool value);
extern void PlayerControllerRightInput(PlayerController *self, bool value); extern void PlayerControllerInputRollRight(PlayerController *self, bool value);
extern void PlayerControllerUpInput(PlayerController *self, bool value); extern void PlayerControllerInputPitchUp(PlayerController *self, bool value);
extern void PlayerControllerDownInput(PlayerController *self, bool value); extern void PlayerControllerInputPitchDown(PlayerController *self, bool value);
extern void PlayerControllerStopInput(PlayerController *self, bool value); extern void PlayerControllerInputYawRight(PlayerController *self, bool value);
extern void PlayerControllerInputYawLeft(PlayerController *self, bool value);
extern void PlayerControllerInputBrake(PlayerController *self, bool value);
extern void PlayerControllerInputBoost(PlayerController *self, bool value);
DECL_REFLECT(PlayerController); DECL_REFLECT(PlayerController);
decl_typeclass_impl(SceneNodeEntity, PlayerController); decl_typeclass_impl(SceneNodeEntity, PlayerController);

@ -1 +1 @@
Subproject commit faf0463e3791ee97dfc370282ecad4cd3b4ca475 Subproject commit bb201d5085cfb2e54ebad9a0bf22347a5251f7a2