mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Get event system working; add collision events
This commit is contained in:
parent
a0b000d3df
commit
062b2d6c8f
@ -23,8 +23,12 @@ set(SRC_FILES
|
|||||||
"src/resources/mesh.cpp"
|
"src/resources/mesh.cpp"
|
||||||
"src/resources/texture.cpp"
|
"src/resources/texture.cpp"
|
||||||
|
|
||||||
|
"src/event_system.cpp"
|
||||||
|
|
||||||
"src/scene.cpp"
|
"src/scene.cpp"
|
||||||
|
|
||||||
"src/gfx_device_vulkan.cpp"
|
"src/gfx_device_vulkan.cpp"
|
||||||
|
"src/gfx_device_null.cpp"
|
||||||
|
|
||||||
"src/util/files.cpp"
|
"src/util/files.cpp"
|
||||||
"src/util/model_loader.cpp"
|
"src/util/model_loader.cpp"
|
||||||
@ -51,6 +55,8 @@ set(INCLUDE_FILES
|
|||||||
"include/resources/mesh.hpp"
|
"include/resources/mesh.hpp"
|
||||||
"include/resources/texture.hpp"
|
"include/resources/texture.hpp"
|
||||||
|
|
||||||
|
"include/event_system.hpp"
|
||||||
|
|
||||||
"include/engine_api.h"
|
"include/engine_api.h"
|
||||||
|
|
||||||
"include/util/files.hpp"
|
"include/util/files.hpp"
|
||||||
|
2
TODO
2
TODO
@ -1,5 +1,7 @@
|
|||||||
----- TO DO LIST -----
|
----- TO DO LIST -----
|
||||||
|
|
||||||
|
TODO now: the collision system doesn't use the "isTrigger" bool properly.
|
||||||
|
|
||||||
Add support for shadows and other complex lighting. Also add post-processing.
|
Add support for shadows and other complex lighting. Also add post-processing.
|
||||||
|
|
||||||
The engine needs an event/message system, this will be helpful for collision
|
The engine needs an event/message system, this will be helpful for collision
|
||||||
|
2
debug.sh
2
debug.sh
@ -3,4 +3,4 @@ set -e
|
|||||||
cd Debug
|
cd Debug
|
||||||
cmake --build .
|
cmake --build .
|
||||||
cd test
|
cd test
|
||||||
./enginetest
|
./enginetest $@
|
||||||
|
@ -20,13 +20,14 @@ namespace engine {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStatic;
|
bool isStatic = true;
|
||||||
AABB aabb;
|
bool isTrigger = false; // entity receives an event on collision enter and exit
|
||||||
|
AABB aabb{};
|
||||||
|
|
||||||
glm::vec3 getLastCollisionNormal() { return {0.0f, 1.0f, 0.0f}; }
|
bool getIsColliding() { return isColliding; }
|
||||||
glm::vec3 getLastCollisionPoint() { return {}; }
|
|
||||||
bool getIsColliding() { return true; }
|
private:
|
||||||
bool getJustUncollided() { return false; }
|
bool isColliding = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
119
include/event_system.hpp
Normal file
119
include/event_system.hpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
|
||||||
|
enum class EventSubscriberKind {
|
||||||
|
ENTITY,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event handler base-class
|
||||||
|
template <typename T>
|
||||||
|
class EventHandler {
|
||||||
|
public:
|
||||||
|
virtual void onEvent(T data) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event queue interface to allow for different type queues to be in the map
|
||||||
|
class IEventQueue {
|
||||||
|
public:
|
||||||
|
virtual void dispatchEvents() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class EventQueue : public IEventQueue {
|
||||||
|
// holds events of type T and subscribers to those events
|
||||||
|
|
||||||
|
public:
|
||||||
|
void subscribe(EventSubscriberKind kind, uint32_t id, EventHandler<T>* handler)
|
||||||
|
{
|
||||||
|
// For the time being, ignore kind (TODO)
|
||||||
|
(void)kind;
|
||||||
|
assert(m_subscribers.contains(id) == false && "subscribing to an event with ID that's already in use!");
|
||||||
|
m_subscribers.emplace(id, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void queueEvent(EventSubscriberKind kind, uint32_t id, T event)
|
||||||
|
{
|
||||||
|
// For the time being, ignore kind (TODO)
|
||||||
|
(void)kind;
|
||||||
|
assert(m_subscribers.contains(id) && "Attempt to submit event to non-existing subscriber!");
|
||||||
|
EventHandler<T>* handler = m_subscribers.at(id);
|
||||||
|
m_eventQueue.emplace(handler, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchEvents() override
|
||||||
|
{
|
||||||
|
while (m_eventQueue.empty() == false) {
|
||||||
|
auto [handler, event] = m_eventQueue.front();
|
||||||
|
handler->onEvent(event);
|
||||||
|
m_eventQueue.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<uint32_t, EventHandler<T>*> m_subscribers;
|
||||||
|
|
||||||
|
struct QueuedEvent {
|
||||||
|
EventHandler<T>* handler;
|
||||||
|
T event;
|
||||||
|
};
|
||||||
|
std::queue<QueuedEvent> m_eventQueue{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventSystem {
|
||||||
|
|
||||||
|
public:
|
||||||
|
EventSystem();
|
||||||
|
EventSystem(const EventSystem&) = delete;
|
||||||
|
EventSystem& operator=(const EventSystem&) = delete;
|
||||||
|
~EventSystem();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void registerEventType()
|
||||||
|
{
|
||||||
|
size_t hash = typeid(T).hash_code();
|
||||||
|
assert(m_eventQueues.contains(hash) == false && "Registering an event queue more than once!");
|
||||||
|
m_eventQueues.emplace(hash, std::make_unique<EventQueue<T>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void subscribeToEventType(EventSubscriberKind kind, uint32_t id, EventHandler<T>* handler)
|
||||||
|
{
|
||||||
|
size_t hash = typeid(T).hash_code();
|
||||||
|
assert(m_eventQueues.contains(hash) && "Subscribing to event type that isn't registered!");
|
||||||
|
EventQueue<T>* queue = dynamic_cast<EventQueue<T>*>(m_eventQueues.at(hash).get());
|
||||||
|
assert(queue != nullptr && "This cast should work?!! wot");
|
||||||
|
queue->subscribe(kind, id, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void queueEvent(EventSubscriberKind kind, uint32_t subscriberID, T event)
|
||||||
|
{
|
||||||
|
size_t hash = typeid(T).hash_code();
|
||||||
|
assert(m_eventQueues.contains(hash) && "Subscribing to event type that isn't registered!");
|
||||||
|
EventQueue<T>* queue = dynamic_cast<EventQueue<T>*>(m_eventQueues.at(hash).get());
|
||||||
|
assert(queue != nullptr && "This cast should work?!! wot");
|
||||||
|
queue->queueEvent(kind, subscriberID, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchEvents()
|
||||||
|
{
|
||||||
|
for (auto& [hash, queue] : m_eventQueues) {
|
||||||
|
queue->dispatchEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<size_t, std::unique_ptr<IEventQueue>> m_eventQueues{};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
|
|
||||||
#include "ecs_system.hpp"
|
#include "ecs_system.hpp"
|
||||||
|
#include "event_system.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -25,6 +26,8 @@ namespace engine {
|
|||||||
|
|
||||||
Application* app() { return m_app; }
|
Application* app() { return m_app; }
|
||||||
|
|
||||||
|
EventSystem* events() { return m_eventSystem.get(); }
|
||||||
|
|
||||||
/* ecs stuff */
|
/* ecs stuff */
|
||||||
|
|
||||||
uint32_t createEntity(const std::string& tag, uint32_t parent = 0);
|
uint32_t createEntity(const std::string& tag, uint32_t parent = 0);
|
||||||
@ -130,6 +133,8 @@ namespace engine {
|
|||||||
return castedPtr;
|
return castedPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<EventSystem> m_eventSystem{};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,30 @@ namespace engine {
|
|||||||
|
|
||||||
void onComponentInsert(uint32_t entity) override;
|
void onComponentInsert(uint32_t entity) override;
|
||||||
|
|
||||||
|
struct CollisionEvent {
|
||||||
|
bool isCollisionEnter; // false == collision exit
|
||||||
|
uint32_t collidedEntity; // the entity that this entity collided with
|
||||||
|
glm::vec3 normal; // the normal of the surface this entity collided with; ignored on collision exit
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// dyanmic arrays to avoid realloc on every frame
|
// dynamic arrays to avoid realloc on every frame
|
||||||
struct CollisionInfo {
|
|
||||||
uint32_t entity;
|
// entity, aabb, isTrigger
|
||||||
AABB aabb;
|
std::vector<std::tuple<uint32_t, AABB, bool>> m_staticAABBs{};
|
||||||
// output
|
std::vector<std::tuple<uint32_t, AABB, bool>> m_dynamicAABBs{};
|
||||||
bool isMaybeColliding; // broad phase
|
|
||||||
bool isColliding; // narrow phase
|
struct PossibleCollision {
|
||||||
|
uint32_t staticEntity;
|
||||||
|
AABB staticAABB;
|
||||||
|
bool staticTrigger;
|
||||||
|
uint32_t dynamicEntity;
|
||||||
|
AABB dynamicAABB;
|
||||||
|
bool dynamicTrigger;
|
||||||
};
|
};
|
||||||
std::vector<CollisionInfo> m_staticInfos{};
|
std::vector<PossibleCollision> m_possibleCollisions{};
|
||||||
std::vector<CollisionInfo> m_dynamicInfos{};
|
std::vector<std::pair<uint32_t, CollisionEvent>> m_collisionInfos{}; // target entity, event info
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,4 +3,4 @@ set -e
|
|||||||
cd Release
|
cd Release
|
||||||
cmake --build .
|
cmake --build .
|
||||||
cd test
|
cd test
|
||||||
./enginetest
|
./enginetest $@
|
||||||
|
15
src/event_system.cpp
Normal file
15
src/event_system.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "event_system.hpp"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
|
||||||
|
EventSystem::EventSystem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EventSystem::~EventSystem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
127
src/gfx_device_null.cpp
Normal file
127
src/gfx_device_null.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// The implementation of the graphics layer using Vulkan 1.3.
|
||||||
|
|
||||||
|
#ifdef ENGINE_BUILD_NULL
|
||||||
|
|
||||||
|
#include "gfx_device.hpp"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <array>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <queue>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
|
||||||
|
struct GFXDevice::Impl {
|
||||||
|
int FRAMECOUNT = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window, bool vsync)
|
||||||
|
{
|
||||||
|
(void)appName;
|
||||||
|
(void)appVersion;
|
||||||
|
(void)window;
|
||||||
|
(void)vsync;
|
||||||
|
|
||||||
|
pimpl = std::make_unique<Impl>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GFXDevice::~GFXDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::getViewportSize(uint32_t *w, uint32_t *h)
|
||||||
|
{
|
||||||
|
*w = 1024;
|
||||||
|
*h = 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize, const gfx::Texture* texture)
|
||||||
|
{
|
||||||
|
(void)pipeline;
|
||||||
|
(void)vertexBuffer;
|
||||||
|
(void)indexBuffer;
|
||||||
|
(void)count;
|
||||||
|
(void)pushConstantData;
|
||||||
|
(void)pushConstantSize;
|
||||||
|
(void)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::renderFrame()
|
||||||
|
{
|
||||||
|
pimpl->FRAMECOUNT++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Pipeline* GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath, const gfx::VertexFormat& vertexFormat, uint64_t uniformBufferSize, bool alphaBlending, bool backfaceCulling)
|
||||||
|
{
|
||||||
|
(void)vertShaderPath;
|
||||||
|
(void)fragShaderPath;
|
||||||
|
(void)vertexFormat;
|
||||||
|
(void)uniformBufferSize;
|
||||||
|
(void)alphaBlending;
|
||||||
|
(void)backfaceCulling;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::destroyPipeline(const gfx::Pipeline* pipeline)
|
||||||
|
{
|
||||||
|
(void)pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::updateUniformBuffer(const gfx::Pipeline* pipeline, const void* data, size_t size, uint32_t offset)
|
||||||
|
{
|
||||||
|
(void)pipeline;
|
||||||
|
(void)data;
|
||||||
|
(void)size;
|
||||||
|
(void)offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Buffer* GFXDevice::createBuffer(gfx::BufferType type, uint64_t size, const void* data)
|
||||||
|
{
|
||||||
|
(void)type;
|
||||||
|
(void)size;
|
||||||
|
(void)data;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::destroyBuffer(const gfx::Buffer* buffer)
|
||||||
|
{
|
||||||
|
(void)buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Texture* GFXDevice::createTexture(
|
||||||
|
const void* imageData,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
gfx::TextureFilter minFilter,
|
||||||
|
gfx::TextureFilter magFilter,
|
||||||
|
gfx::MipmapSetting mipmapSetting,
|
||||||
|
bool useAnisotropy)
|
||||||
|
{
|
||||||
|
(void)imageData;
|
||||||
|
(void)width;
|
||||||
|
(void)height;
|
||||||
|
(void)minFilter;
|
||||||
|
(void)magFilter;
|
||||||
|
(void)mipmapSetting;
|
||||||
|
(void)useAnisotropy;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::destroyTexture(const gfx::Texture* texture)
|
||||||
|
{
|
||||||
|
(void)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GFXDevice::waitIdle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -492,7 +492,7 @@ namespace engine {
|
|||||||
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
|
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
|
||||||
|
|
||||||
VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;
|
VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;
|
||||||
counts %= VK_SAMPLE_COUNT_8_BIT; // restricts it to 8
|
counts %= VK_SAMPLE_COUNT_4_BIT; // restricts it to 2 or 1 (0b11)
|
||||||
if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; }
|
if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; }
|
||||||
if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; }
|
if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; }
|
||||||
if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; }
|
if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; }
|
||||||
@ -657,6 +657,14 @@ namespace engine {
|
|||||||
|
|
||||||
// create the render pass
|
// create the render pass
|
||||||
if (swapchain->renderpass == VK_NULL_HANDLE) {
|
if (swapchain->renderpass == VK_NULL_HANDLE) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* render pass layout:
|
||||||
|
* 0: color attachment with msaa samples,
|
||||||
|
* 1: depth attachment with msaa samples, used for fragment shading
|
||||||
|
* 2: present src (resolve) attachment with 1 sample, used for swapchain present
|
||||||
|
*/
|
||||||
|
|
||||||
VkAttachmentDescription colorAttachment{};
|
VkAttachmentDescription colorAttachment{};
|
||||||
colorAttachment.format = swapchain->surfaceFormat.format;
|
colorAttachment.format = swapchain->surfaceFormat.format;
|
||||||
colorAttachment.samples = swapchain->msaaSamples;
|
colorAttachment.samples = swapchain->msaaSamples;
|
||||||
@ -1579,7 +1587,7 @@ namespace engine {
|
|||||||
renderPassInfo.renderArea.extent = pimpl->swapchain.extent;
|
renderPassInfo.renderArea.extent = pimpl->swapchain.extent;
|
||||||
|
|
||||||
std::array<VkClearValue, 2> clearValues{};
|
std::array<VkClearValue, 2> clearValues{};
|
||||||
clearValues[0].color = { {0.1f, 0.1f, 0.1f, 1.0f} };
|
clearValues[0].color = { {1.0f, 1.0f, 1.0f, 1.0f} };
|
||||||
clearValues[1].depthStencil = { 1.0f, 0 };
|
clearValues[1].depthStencil = { 1.0f, 0 };
|
||||||
renderPassInfo.clearValueCount = (uint32_t)clearValues.size();
|
renderPassInfo.clearValueCount = (uint32_t)clearValues.size();
|
||||||
renderPassInfo.pClearValues = clearValues.data();
|
renderPassInfo.pClearValues = clearValues.data();
|
||||||
|
@ -12,6 +12,11 @@ namespace engine {
|
|||||||
Scene::Scene(Application* app)
|
Scene::Scene(Application* app)
|
||||||
: m_app(app)
|
: m_app(app)
|
||||||
{
|
{
|
||||||
|
// event system
|
||||||
|
m_eventSystem = std::make_unique<EventSystem>();
|
||||||
|
|
||||||
|
// ecs configuration:
|
||||||
|
|
||||||
registerComponent<TransformComponent>();
|
registerComponent<TransformComponent>();
|
||||||
registerComponent<RenderableComponent>();
|
registerComponent<RenderableComponent>();
|
||||||
registerComponent<ColliderComponent>();
|
registerComponent<ColliderComponent>();
|
||||||
@ -64,6 +69,7 @@ namespace engine {
|
|||||||
system->onUpdate(ts);
|
system->onUpdate(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_eventSystem->dispatchEvents(); // clears event queue
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,17 @@ namespace engine {
|
|||||||
PhysicsSystem::PhysicsSystem(Scene* scene)
|
PhysicsSystem::PhysicsSystem(Scene* scene)
|
||||||
: System(scene, { typeid(TransformComponent).hash_code(), typeid(ColliderComponent).hash_code() })
|
: System(scene, { typeid(TransformComponent).hash_code(), typeid(ColliderComponent).hash_code() })
|
||||||
{
|
{
|
||||||
|
m_scene->events()->registerEventType<CollisionEvent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::onComponentInsert(uint32_t entity)
|
void PhysicsSystem::onComponentInsert(uint32_t entity)
|
||||||
{
|
{
|
||||||
(void)entity;
|
(void)entity;
|
||||||
m_staticInfos.reserve(m_entities.size());
|
const size_t size = m_entities.size();
|
||||||
m_dynamicInfos.reserve(m_entities.size());
|
m_staticAABBs.reserve(size);
|
||||||
|
m_dynamicAABBs.reserve(size);
|
||||||
|
m_possibleCollisions.reserve(size);
|
||||||
|
m_collisionInfos.reserve(size);
|
||||||
TRACE("added entity {} to collider system", entity);
|
TRACE("added entity {} to collider system", entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,12 +53,12 @@ namespace engine {
|
|||||||
{
|
{
|
||||||
(void)ts;
|
(void)ts;
|
||||||
|
|
||||||
m_staticInfos.clear();
|
m_staticAABBs.clear();
|
||||||
m_dynamicInfos.clear();
|
m_dynamicAABBs.clear();
|
||||||
|
m_possibleCollisions.clear();
|
||||||
|
m_collisionInfos.clear();
|
||||||
|
|
||||||
TRACE("Getting collider entities:");
|
|
||||||
for (uint32_t entity : m_entities) {
|
for (uint32_t entity : m_entities) {
|
||||||
TRACE(" has entity: {}", entity);
|
|
||||||
const auto t = m_scene->getComponent<TransformComponent>(entity);
|
const auto t = m_scene->getComponent<TransformComponent>(entity);
|
||||||
const auto c = m_scene->getComponent<ColliderComponent>(entity);
|
const auto c = m_scene->getComponent<ColliderComponent>(entity);
|
||||||
|
|
||||||
@ -63,43 +67,51 @@ namespace engine {
|
|||||||
AABB globalBoundingBox;
|
AABB globalBoundingBox;
|
||||||
globalBoundingBox.pos1 = globalPosition + localBoundingBox.pos1;
|
globalBoundingBox.pos1 = globalPosition + localBoundingBox.pos1;
|
||||||
globalBoundingBox.pos2 = globalPosition + localBoundingBox.pos2;
|
globalBoundingBox.pos2 = globalPosition + localBoundingBox.pos2;
|
||||||
TRACE(" global bounding box:");
|
|
||||||
TRACE(" pos1: {} {} {}", globalBoundingBox.pos1.x, globalBoundingBox.pos1.y, globalBoundingBox.pos1.z);
|
|
||||||
TRACE(" pos2: {} {} {}", globalBoundingBox.pos2.x, globalBoundingBox.pos2.y, globalBoundingBox.pos2.z);
|
|
||||||
|
|
||||||
CollisionInfo info{
|
|
||||||
.entity = entity,
|
|
||||||
.aabb = globalBoundingBox,
|
|
||||||
.isMaybeColliding = false,
|
|
||||||
.isColliding = false
|
|
||||||
};
|
|
||||||
if (c->isStatic) {
|
if (c->isStatic) {
|
||||||
m_staticInfos.push_back(info);
|
m_staticAABBs.emplace_back(std::make_tuple(entity, globalBoundingBox, c->isTrigger));
|
||||||
} else {
|
} else {
|
||||||
m_dynamicInfos.push_back(info);
|
m_dynamicAABBs.emplace_back(std::make_tuple(entity, globalBoundingBox, c->isTrigger));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BROAD PHASE */
|
/* BROAD PHASE */
|
||||||
|
|
||||||
TRACE("Starting broad phase collision test");
|
|
||||||
|
|
||||||
struct PossibleCollision {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check every static collider against every dynamic collider, and every dynamic collider against every other one
|
// Check every static collider against every dynamic collider, and every dynamic collider against every other one
|
||||||
// This technique is inefficient for many entities.
|
// This technique is inefficient for many entities.
|
||||||
for (size_t i = 0; i < m_staticInfos.size(); i++) {
|
for (auto [staticEntity, staticAABB, staticTrigger] : m_staticAABBs) {
|
||||||
for (size_t j = 0; j < m_dynamicInfos.size(); j++) {
|
for (auto [dynamicEntity, dynamicAABB, dynamicTrigger] : m_dynamicAABBs) {
|
||||||
if (checkCollisionFast(m_staticInfos[i].aabb, m_dynamicInfos[j].aabb)) {
|
if (checkCollisionFast(staticAABB, dynamicAABB)) {
|
||||||
m_staticInfos[i].isMaybeColliding = true;
|
if (staticTrigger || dynamicTrigger) { // only check collisions involved with triggers
|
||||||
m_dynamicInfos[i].isMaybeColliding = true;
|
m_possibleCollisions.emplace_back(
|
||||||
TRACE("Collision detected between {} and {}", m_staticInfos[i].entity, m_dynamicInfos[j].entity);
|
staticEntity, staticAABB, staticTrigger,
|
||||||
|
dynamicEntity, dynamicAABB, dynamicTrigger
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get collision details and submit events
|
||||||
|
for (auto possibleCollision : m_possibleCollisions) {
|
||||||
|
if (possibleCollision.staticTrigger) {
|
||||||
|
CollisionEvent info{};
|
||||||
|
info.isCollisionEnter = true;
|
||||||
|
info.collidedEntity = possibleCollision.dynamicEntity;
|
||||||
|
m_collisionInfos.emplace_back(possibleCollision.staticEntity, info);
|
||||||
|
}
|
||||||
|
if (possibleCollision.dynamicTrigger) {
|
||||||
|
CollisionEvent info{};
|
||||||
|
info.isCollisionEnter = true;
|
||||||
|
info.collidedEntity = possibleCollision.staticEntity;
|
||||||
|
m_collisionInfos.emplace_back(possibleCollision.dynamicEntity, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto [entity, info] : m_collisionInfos) {
|
||||||
|
m_scene->events()->queueEvent(EventSubscriberKind::ENTITY, entity, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,3 +173,9 @@ void CameraControllerSystem::onUpdate(float ts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CameraControllerSystem::onEvent(engine::PhysicsSystem::CollisionEvent info)
|
||||||
|
{
|
||||||
|
(void)info;
|
||||||
|
INFO("COLLISION EVENT!");
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ecs_system.hpp"
|
#include "ecs_system.hpp"
|
||||||
|
#include "event_system.hpp"
|
||||||
|
|
||||||
|
#include "systems/collisions.hpp"
|
||||||
|
|
||||||
struct CameraControllerComponent {
|
struct CameraControllerComponent {
|
||||||
float m_cameraSensitivity = 0.007f;
|
float m_cameraSensitivity = 0.007f;
|
||||||
@ -17,10 +20,14 @@ struct CameraControllerComponent {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CameraControllerSystem : public engine::System {
|
class CameraControllerSystem : public engine::System, public engine::EventHandler<engine::PhysicsSystem::CollisionEvent> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CameraControllerSystem(engine::Scene* scene);
|
CameraControllerSystem(engine::Scene* scene);
|
||||||
|
|
||||||
|
// engine::System overrides
|
||||||
void onUpdate(float ts) override;
|
void onUpdate(float ts) override;
|
||||||
|
|
||||||
|
// engine::EventHandler overrides
|
||||||
|
void onEvent(engine::PhysicsSystem::CollisionEvent info) override;
|
||||||
};
|
};
|
||||||
|
@ -38,11 +38,11 @@ static void configureInputs(engine::InputManager* inputManager)
|
|||||||
inputManager->addInputAxis("looky", engine::inputs::MouseAxis::Y);
|
inputManager->addInputAxis("looky", engine::inputs::MouseAxis::Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void playGame()
|
void playGame(bool enableFrameLimiter)
|
||||||
{
|
{
|
||||||
engine::Application app(PROJECT_NAME, PROJECT_VERSION);
|
engine::Application app(PROJECT_NAME, PROJECT_VERSION);
|
||||||
|
|
||||||
app.setFrameLimiter(false);
|
app.setFrameLimiter(enableFrameLimiter);
|
||||||
|
|
||||||
// configure window
|
// configure window
|
||||||
app.window()->setRelativeMouseMode(true);
|
app.window()->setRelativeMouseMode(true);
|
||||||
@ -60,8 +60,12 @@ void playGame()
|
|||||||
myScene->getComponent<engine::TransformComponent>(camera)->position.y = 8.0f;
|
myScene->getComponent<engine::TransformComponent>(camera)->position.y = 8.0f;
|
||||||
auto cameraCollider = myScene->addComponent<engine::ColliderComponent>(camera);
|
auto cameraCollider = myScene->addComponent<engine::ColliderComponent>(camera);
|
||||||
cameraCollider->isStatic = false;
|
cameraCollider->isStatic = false;
|
||||||
|
cameraCollider->isTrigger = true;
|
||||||
cameraCollider->aabb = { { -0.2f, -1.5f, -0.2f }, { 0.2f, 0.2f, 0.2f} }; // Origin is at eye level
|
cameraCollider->aabb = { { -0.2f, -1.5f, -0.2f }, { 0.2f, 0.2f, 0.2f} }; // Origin is at eye level
|
||||||
myScene->addComponent<CameraControllerComponent>(camera);
|
myScene->addComponent<CameraControllerComponent>(camera);
|
||||||
|
myScene->events()->subscribeToEventType<engine::PhysicsSystem::CollisionEvent>(
|
||||||
|
engine::EventSubscriberKind::ENTITY, camera, myScene->getSystem<CameraControllerSystem>()
|
||||||
|
);
|
||||||
|
|
||||||
myScene->getSystem<engine::RenderSystem>()->setCameraEntity(camera);
|
myScene->getSystem<engine::RenderSystem>()->setCameraEntity(camera);
|
||||||
}
|
}
|
||||||
@ -83,7 +87,7 @@ void playGame()
|
|||||||
);
|
);
|
||||||
|
|
||||||
/* skybox */
|
/* skybox */
|
||||||
{
|
if (0) {
|
||||||
uint32_t skybox = myScene->createEntity("skybox");
|
uint32_t skybox = myScene->createEntity("skybox");
|
||||||
auto skyboxRenderable = myScene->addComponent<engine::RenderableComponent>(skybox);
|
auto skyboxRenderable = myScene->addComponent<engine::RenderableComponent>(skybox);
|
||||||
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.skybox"));
|
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.skybox"));
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void playGame();
|
void playGame(bool enableFrameLimiter);
|
||||||
|
@ -7,15 +7,22 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
int main(int, char *[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
|
bool enableFrameLimiter = true;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
const std::string arg { argv[1] };
|
||||||
|
if (arg == "nofpslimit") enableFrameLimiter = false;
|
||||||
|
}
|
||||||
|
|
||||||
engine::setupLog(PROJECT_NAME);
|
engine::setupLog(PROJECT_NAME);
|
||||||
|
|
||||||
INFO("{} v{}", PROJECT_NAME, PROJECT_VERSION);
|
INFO("{} v{}", PROJECT_NAME, PROJECT_VERSION);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
playGame();
|
playGame(enableFrameLimiter);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user