Begin collision/physics rewrite

This commit is contained in:
Bailey Harrison 2023-07-04 17:08:28 +01:00
parent 78ed78120b
commit 2db3cf8722
11 changed files with 6328 additions and 199 deletions

6244
cpplint.py vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,7 @@ struct AABB {
glm::vec3 pos2;
};
class PhysicsSystem;
struct ColliderComponent {
friend PhysicsSystem;
bool is_static = true;
bool is_trigger =
false; // entity receives an event on collision enter and exit

View File

@ -6,6 +6,7 @@
namespace engine {
struct CustomComponent {
std::function<void(void)> onInit; // void onInit(void);
std::function<void(float)> onUpdate; // void onUpdate(float ts);
};

View File

@ -1,12 +1,12 @@
#ifndef ENGINE_INCLUDE_COMPONENTS_TRANSFORM_H_
#define ENGINE_INCLUDE_COMPONENTS_TRANSFORM_H_
#include <string>
#include <glm/gtc/quaternion.hpp>
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <string>
namespace engine {
struct TransformComponent {

View File

@ -7,6 +7,8 @@
#include <stdexcept>
#include <typeinfo>
#include <glm/vec3.hpp>
#include "ecs_system.h"
#include "event_system.h"
@ -29,9 +31,9 @@ class Scene {
/* ecs stuff */
uint32_t CreateEntity(const std::string& tag, uint32_t parent = 0);
uint32_t CreateEntity(const std::string& tag, uint32_t parent = 0, const glm::vec3& pos = {});
uint32_t getEntity(const std::string& tag, uint32_t parent = 0);
uint32_t GetEntity(const std::string& tag, uint32_t parent = 0);
size_t GetComponentSignaturePosition(size_t hash);

View File

@ -33,6 +33,7 @@ static std::filesystem::path getResourcesPath() {
std::filesystem::path resourcesPath{};
#ifdef _MSC_VER
// get the path of the currently running process
CHAR exeDirBuf[MAX_PATH + 1];
GetModuleFileNameA(NULL, exeDirBuf, WIN_MAX_PATH + 1);
std::filesystem::path cwd = std::filesystem::path(exeDirBuf).parent_path();

View File

@ -31,7 +31,8 @@ Scene::Scene(Application* app) : app_(app) {
Scene::~Scene() {}
uint32_t Scene::CreateEntity(const std::string& tag, uint32_t parent) {
uint32_t Scene::CreateEntity(const std::string& tag, uint32_t parent,
const glm::vec3& pos) {
uint32_t id = next_entity_id_++;
signatures_.emplace(id, std::bitset<kMaxComponents>{});
@ -48,7 +49,7 @@ uint32_t Scene::CreateEntity(const std::string& tag, uint32_t parent) {
return id;
}
uint32_t Scene::getEntity(const std::string& tag, uint32_t parent) {
uint32_t Scene::GetEntity(const std::string& tag, uint32_t parent) {
return GetSystem<TransformSystem>()->GetChildEntity(parent, tag);
}

View File

@ -1,77 +1,73 @@
#include "util/files.h"
#include "stb_image.h"
#include <fstream>
#include <cstring>
#include "stb_image.h"
namespace engine::util {
std::unique_ptr<std::vector<char>> ReadTextFile(const std::string& path)
{
auto buffer = std::make_unique<std::vector<char>>();
std::unique_ptr<std::vector<char>> ReadTextFile(const std::string& path) {
std::ifstream file(path, std::ios::ate);
if (file.is_open() == false) {
throw std::runtime_error("Unable to open file " + path);
}
std::ifstream file(path, std::ios::ate);
auto buffer = std::make_unique<std::vector<char>>(file.tellg());
if (file.is_open() == false) {
throw std::runtime_error("Unable to open file " + path);
}
file.seekg(0);
// reserve enough space for the text file, but leave the size at 0
buffer->reserve(file.tellg());
int i = 0;
while (!file.eof()) {
char c{};
file.read(&c, 1); // reading 1 char at a time
buffer->data()[i] = c;
file.seekg(0);
++i;
}
while (!file.eof()) {
char c{};
file.read(&c, 1);
buffer->push_back(c);
}
file.close();
return buffer;
}
std::unique_ptr<std::vector<uint8_t>> ReadBinaryFile(const std::string& path)
{
std::ifstream file(path, std::ios::ate | std::ios::binary);
if (file.is_open() == false) {
throw std::runtime_error("Unable to open file " + path);
}
auto buffer = std::make_unique<std::vector<uint8_t>>(file.tellg());
file.seekg(0);
file.read((char*)buffer->data(), buffer->size());
file.close();
return buffer;
}
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path, int *width, int *height)
{
int x, y, n;
unsigned char *data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha);
if (data == nullptr) {
throw std::runtime_error("Unable to open file " + path);
}
const size_t size = (size_t)x * (size_t)y * 4;
auto buffer = std::make_unique<std::vector<uint8_t>>(size);
memcpy(buffer->data(), data, buffer->size());
*width = x;
*height = y;
stbi_image_free(data);
return buffer;
}
file.close();
return buffer;
}
std::unique_ptr<std::vector<uint8_t>> ReadBinaryFile(const std::string& path) {
std::ifstream file(path, std::ios::ate | std::ios::binary);
if (file.is_open() == false) {
throw std::runtime_error("Unable to open file " + path);
}
auto buffer = std::make_unique<std::vector<uint8_t>>(file.tellg());
file.seekg(0);
file.read((char*)buffer->data(), buffer->size());
file.close();
return buffer;
}
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
int* width, int* height) {
int x, y, n;
unsigned char* data =
stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha); // Image is 4 bpp
if (data == nullptr) {
throw std::runtime_error("Unable to open file " + path);
}
const size_t size = (size_t)x * (size_t)y * 4;
auto buffer = std::make_unique<std::vector<uint8_t>>(size);
memcpy(buffer->data(), data, buffer->size());
*width = x;
*height = y;
stbi_image_free(data);
return buffer;
}
} // namespace engine::util

View File

@ -6,7 +6,6 @@
#include <glm/trigonometric.hpp>
#include "application.h"
#include "components/collider.h"
#include "components/transform.h"
#include "input_manager.h"
#include "log.h"
@ -19,68 +18,24 @@ CameraControllerSystem::CameraControllerSystem(engine::Scene* scene)
typeid(CameraControllerComponent).hash_code()}) {}
void CameraControllerSystem::OnUpdate(float ts) {
if (t == nullptr || c == nullptr || col == nullptr) {
if (t == nullptr || c == nullptr) {
for (uint32_t entity : entities_) {
t = scene_->GetComponent<engine::TransformComponent>(entity);
col = scene_->GetComponent<engine::ColliderComponent>(entity);
c = scene_->GetComponent<CameraControllerComponent>(entity);
break;
}
if (t == nullptr) return;
if (c == nullptr) return;
if (col == nullptr) return;
}
const float dt = ts;
constexpr float G = 9.8f;
const float kMaxSlopeAngle = glm::cos(glm::radians(20.0f));
constexpr float kFloorSinkLevel =
0.05f; // how far into the floor to ground the player
glm::vec3 norm = c->last_collision_normal;
glm::vec3 dir =
glm::normalize(glm::rotateY(glm::vec3{1.0f, 0.0f, 0.0f}, c->yaw) +
glm::rotateY(glm::vec3{0.0f, 0.0f, 1.0f}, c->yaw));
const float slope = glm::dot(dir, norm);
bool is_sliding = false;
if (c->just_collided) {
if (slope > kMaxSlopeAngle) {
// slide across wall
is_sliding = true;
} else {
if (c->dy < 0.0f && c->is_grounded == false) {
// in the ground, push up a bit
float floorY = c->last_collision_point.y;
t->position.y = floorY + 1.5f - kFloorSinkLevel;
c->dy = 0.0f;
c->is_grounded = true;
}
}
}
if (c->just_collided == false && slope <= kMaxSlopeAngle) {
// just stopped colliding with a floor collider
c->is_grounded = false;
}
if (c->is_grounded == false) c->dy -= G * dt;
// jumping
constexpr float JUMPVEL =
(float)2.82231110971133017648; // std::sqrt(2 * G * JUMPHEIGHT);
if (scene_->app()->input_manager()->GetButton("jump") &&
c->is_grounded == true) {
c->dy = JUMPVEL;
}
if (scene_->app()->window()->GetButton(engine::inputs::MouseButton::M_LEFT)) {
c->dy += dt * c->kThrust;
}
// in metres per second
float speed = c->kWalkSpeed;
if (scene_->app()->input_manager()->GetButton("sprint")) speed *= 10.0f;
@ -104,20 +59,16 @@ void CameraControllerSystem::OnUpdate(float ts) {
// update position relative to camera direction in xz plane
const glm::vec3 d2x_rotated = glm::rotateY(glm::vec3{dx, 0.0f, 0.0f}, c->yaw);
const glm::vec3 d2z_rotated = glm::rotateY(glm::vec3{0.0f, 0.0f, dz}, c->yaw);
const glm::vec3 d2z_rotated =
glm::rotateY(glm::rotateX(glm::vec3{0.0f, 0.0f, dz}, c->pitch), c->yaw);
glm::vec3 h_vel = (d2x_rotated + d2z_rotated);
if (is_sliding) {
h_vel = glm::vec3{norm.z, 0.0f, -norm.x};
}
h_vel *= speed;
t->position += h_vel * dt;
t->position.y += c->dy * dt;
constexpr float kMaxDistanceFromOrigin = 10000.0f;
if (glm::length(t->position) > kMaxDistanceFromOrigin) {
t->position = {0.0f, 5.0f, 0.0f};
c->dy = 0.0f;
}
/* ROTATION STUFF */
@ -152,7 +103,6 @@ void CameraControllerSystem::OnUpdate(float ts) {
if (scene_->app()->window()->GetKeyPress(engine::inputs::Key::K_R)) {
t->position = {0.0f, 5.0f, 0.0f};
c->dy = 0.0f;
}
if (scene_->app()->input_manager()->GetButtonPress("fullscreen")) {
@ -162,14 +112,4 @@ void CameraControllerSystem::OnUpdate(float ts) {
if (scene_->app()->input_manager()->GetButtonPress("exit")) {
scene_->app()->window()->SetCloseFlag();
}
c->just_collided = false;
}
// called once per frame
void CameraControllerSystem::OnEvent(
engine::PhysicsSystem::CollisionEvent info) {
c->just_collided = info.is_collision_enter;
c->last_collision_normal = info.normal;
c->last_collision_point = info.point;
}
}

View File

@ -5,40 +5,23 @@
#include "components/transform.h"
#include "ecs_system.h"
#include "event_system.h"
#include "systems/collisions.h"
struct CameraControllerComponent {
static constexpr float kWalkSpeed = 4.0f;
static constexpr float kThrust = 25.0f;
static constexpr float kCameraSensitivity = 0.007f;
float yaw = 0.0f;
float pitch = 0.0f;
float dy = 0.0f;
glm::vec3 last_collision_normal{};
glm::vec3 last_collision_point{};
bool just_collided = false;
bool is_grounded = false;
};
class CameraControllerSystem
: public engine::System,
public engine::EventHandler<engine::PhysicsSystem::CollisionEvent> {
: public engine::System {
public:
CameraControllerSystem(engine::Scene* scene);
// engine::System overrides
void OnUpdate(float ts) override;
// engine::EventHandler overrides
void OnEvent(engine::PhysicsSystem::CollisionEvent info) override;
engine::TransformComponent* t = nullptr;
engine::ColliderComponent* col = nullptr;
CameraControllerComponent* c = nullptr;
};

View File

@ -49,13 +49,10 @@ void PlayGame(GameSettings settings) {
graphics_settings.vsync = true;
graphics_settings.wait_for_present = false;
graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff;
engine::Application app(PROJECT_NAME, PROJECT_VERSION, graphics_settings);
app.SetFrameLimiter(settings.enable_frame_limiter);
// configure window
app.window()->SetRelativeMouseMode(true);
ConfigureInputs(app.input_manager());
auto my_scene = app.scene_manager()->CreateEmptyScene();
@ -68,18 +65,13 @@ void PlayGame(GameSettings settings) {
auto camera = my_scene->CreateEntity("camera");
my_scene->GetComponent<engine::TransformComponent>(camera)->position = {
0.0f, 10.0f, 0.0f};
auto camer_collider =
auto camera_collider =
my_scene->AddComponent<engine::ColliderComponent>(camera);
camer_collider->is_static = false;
camer_collider->is_trigger = true;
camer_collider->aabb = {{-0.2f, -1.5f, -0.2f},
camera_collider->is_static = false;
camera_collider->is_trigger = false;
camera_collider->aabb = {{-0.2f, -1.5f, -0.2f},
{0.2f, 0.2f, 0.2f}}; // Origin is at eye level
my_scene->AddComponent<CameraControllerComponent>(camera);
my_scene->event_system()
->SubscribeToEventType<engine::PhysicsSystem::CollisionEvent>(
engine::EventSubscriberKind::kEntity, camera,
my_scene->GetSystem<CameraControllerSystem>());
auto render_system = my_scene->GetSystem<engine::RenderSystem>();
render_system->SetCameraEntity(camera);
}
@ -93,33 +85,6 @@ void PlayGame(GameSettings settings) {
&app.render_data_, app.GetResourcePath("textures/space2.png"),
engine::resources::Texture::Filtering::kAnisotropic);
#if 0
/* cube */
{
uint32_t cube = my_scene->CreateEntity("cube");
my_scene->GetComponent<engine::TransformComponent>(cube)->position =
glm::vec3{-0.5f + 5.0f, -0.5f + 5.0f, -0.5f + 5.0f};
auto cube_renderable =
my_scene->AddComponent<engine::RenderableComponent>(cube);
cube_renderable->material = std::make_shared<engine::resources::Material>(
app.GetResource<engine::resources::Shader>("builtin.standard"));
cube_renderable->material->texture_ = grass_texture;
// app.GetResource<engine::resources::Texture>("builtin.white");
cube_renderable->mesh = GenCuboidMesh(app.gfxdev(), 1.0f, 1.0f, 1.0f, 1);
auto cube_collider =
my_scene->AddComponent<engine::ColliderComponent>(cube);
cube_collider->is_static = true;
cube_collider->aabb = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};
}
engine::util::LoadMeshFromFile(
my_scene, app.GetResourcePath("models/astronaut/astronaut.dae"));
engine::util::LoadMeshFromFile(
my_scene, app.GetResourcePath("models/plane/plane.dae"));
#endif
/* skybox */
{
uint32_t skybox = my_scene->CreateEntity("skybox");
@ -165,7 +130,7 @@ void PlayGame(GameSettings settings) {
{
int width, height;
auto bitmap = app.GetResource<engine::resources::Font>("builtin.mono")
->GetTextBitmap("ABCDEFGHIJKLMNOPQRSTUVWXYZ12345", 768.0f,
->GetTextBitmap("ABCDEFGHIJKLMNOPQRSTUVWXYZ12345", 1080.0f,
width, height);
uint32_t textbox = my_scene->CreateEntity("textbox");
@ -177,11 +142,11 @@ void PlayGame(GameSettings settings) {
textbox_renderable->material->texture_ =
std::make_unique<engine::resources::Texture>(
&app.render_data_, bitmap->data(), width, height,
engine::resources::Texture::Filtering::kBilinear);
engine::resources::Texture::Filtering::kAnisotropic);
textbox_renderable->mesh = GenSphereMesh(app.gfxdev(), 1.0f, 5);
my_scene->GetComponent<engine::TransformComponent>(textbox)->scale.y =
(float)height / (float)width;
textbox_renderable->shown = false;
textbox_renderable->shown = true;
my_scene->AddComponent<engine::CustomComponent>(textbox)->onUpdate =
[&](float ts) {