fogd-engine/src/player_controller.c
2024-09-27 16:08:21 +02:00

125 lines
4.8 KiB
C

#include "player_controller.h"
#include "core/render.h"
#include "core/input.h"
#include "utils/typeclass_helpers.h"
#include "utils/debug.h"
#include "raylib.h"
START_REFLECT(PlayerController);
REFLECT_TYPECLASS(PlayerController, Drop);
REFLECT_TYPECLASS(PlayerController, SceneNodeEntity);
END_REFLECT(PlayerController);
impl_Drop_for(PlayerController,
DestroyPlayerController
)
impl_SceneNodeEntity_for(PlayerController,
PlayerControllerEnterTree,
PlayerControllerExitTree,
PlayerControllerTick
)
SceneNode *CreatePlayerController() {
PlayerController *self = new(PlayerController);
*self = (PlayerController) {
.node = NULL,
.transform = tc_null(Transformable),
.rotation = Vector3Zero(),
.fly_input = Vector3Zero(),
.speed = 10.f,
.brake = false
};
return CreateSceneNode(PlayerController_as_SceneNodeEntity(self));
}
void DestroyPlayerController(PlayerController *self) {
free(self);
}
void PlayerControllerEnterTree(PlayerController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable);
DisableCursor();
AddListener("pitch_up", ButtonInputListener(self, PlayerControllerInputPitchUp));
AddListener("pitch_down", ButtonInputListener(self, PlayerControllerInputPitchDown));
AddListener("roll_left", ButtonInputListener(self, PlayerControllerInputRollLeft));
AddListener("roll_right", ButtonInputListener(self, PlayerControllerInputRollRight));
AddListener("yaw_left", ButtonInputListener(self, PlayerControllerInputYawLeft));
AddListener("yaw_right", ButtonInputListener(self, PlayerControllerInputYawRight));
AddListener("stop", ButtonInputListener(self, PlayerControllerInputBrake));
}
void PlayerControllerExitTree(PlayerController *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
static
void PlayerControllerTickAngularAcceleration(PlayerController *self, double delta) {
self->rotation.x = MoveTowards(self->rotation.x, self->fly_input.x, delta * 4.f);
self->rotation.y = MoveTowards(self->rotation.y, self->fly_input.y, delta * 4.f);
self->rotation.z = MoveTowards(self->rotation.z, self->fly_input.z, delta * 4.f);
}
//! linear acceleration limited to the local Z axis
static
void PlayerControllerTickLinearAcceleration(PlayerController *self, double delta) {
float const target = self->brake ? 5.f : (self->rotation.y == 0.f ? 30.f : 10.f);
float const speed_diff = target - self->speed;
self->speed = self->speed + copysignf(fminf(fabsf(speed_diff), 15.f * delta), speed_diff);
}
//! Update linear transform based on velocities
static
void PlayerControllerTickTransform(PlayerController *self, double delta) {
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data);
Matrix global_matrix = TransformGetMatrix(global_transform);
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_RIGHT(global_matrix), self->rotation.y * 2.5f * delta), global_transform.rotation);
global_transform.rotation = QuaternionMultiply(QuaternionFromAxisAngle(MATRIX_UP(global_matrix), self->rotation.z * 1.f * delta), global_transform.rotation);
self->transform.tc->set_global_transform(self->transform.data, global_transform);
}
void PlayerControllerTick(PlayerController *self, double delta) {
PlayerControllerTickAngularAcceleration(self, delta);
PlayerControllerTickLinearAcceleration(self, delta);
PlayerControllerTickTransform(self, delta);
}
void PlayerControllerInputRollLeft(PlayerController *self, bool value) {
self->fly_input.x += value ? -1 : +1;
}
void PlayerControllerInputRollRight(PlayerController *self, bool value) {
self->fly_input.x += value ? +1 : -1;
}
void PlayerControllerInputPitchUp(PlayerController *self, bool value) {
self->fly_input.y += value ? -1 : +1;
}
void PlayerControllerInputPitchDown(PlayerController *self, bool value) {
self->fly_input.y += value ? +1 : -1;
}
void PlayerControllerInputYawRight(PlayerController *self, bool 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;
}