Skip to content

Commit a1c750f

Browse files
authored
Collision tag update (#25)
- Can now get entity collisions by tag - Fixed bug with setting tags in python script - Added rough ease functions (not ready to be used!)
1 parent 11ccacd commit a1c750f

File tree

13 files changed

+381
-40
lines changed

13 files changed

+381
-40
lines changed

_version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "0.43.0"
2+
"version": "0.44.0"
33
}

docs/python_api/physics.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@ None.
2020

2121
```python
2222
@staticmethod
23-
get_collided_nodes(node: seika.node.Node) -> list:
23+
get_collided_nodes(node: seika.node.Node, offset: seika.math.Vector2) -> list:
2424
```
2525

26-
Returns a `list` of nodes that collided with the passed in `node`.
26+
Returns a `list` of nodes that collided with the passed in `node`. Can configure the position of the collision by adjusting the `offset`.
27+
28+
```python
29+
@staticmethod
30+
get_collided_nodes_by_tag(node: seika.node.Node, tag: str, offset: seika.math.Vector2) -> list:
31+
```
32+
33+
Same as `get_collided_nodes` but filters results by tag.
2734

2835
```python
2936
@staticmethod
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include <set>
4+
#include <unordered_map>
5+
6+
#include "entity.h"
7+
8+
class EntityTagCache {
9+
public:
10+
void AddEntityTags(Entity entity, const std::vector<std::string> tags) {
11+
for (const std::string& tag : tags) {
12+
if (!HasTag(tag)) {
13+
entityTagCache.emplace(tag, std::set<Entity> {});
14+
}
15+
entityTagCache[tag].insert(entity);
16+
}
17+
}
18+
19+
void RemoveEntityTags(Entity entity, const std::vector<std::string> tags) {
20+
for (const std::string& tag : tags) {
21+
if (HasTag(tag)) {
22+
entityTagCache[tag].erase(entity);
23+
}
24+
}
25+
}
26+
27+
bool HasTag(const std::string& tag) {
28+
return entityTagCache.count(tag) > 0;
29+
}
30+
31+
std::set<Entity> GetTaggedEntities(const std::string& tag) {
32+
if (HasTag(tag)) {
33+
return entityTagCache[tag];
34+
}
35+
return {};
36+
}
37+
private:
38+
std::unordered_map<std::string, std::set<Entity>> entityTagCache = {};
39+
};

src/core/ecs/entity_component_orchestrator.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Entity EntityComponentOrchestrator::CreateEntity() {
1010
return entityManager->CreateEntity();
1111
}
1212

13+
// TODO: Make into hook
1314
void EntityComponentOrchestrator::NewEntity(SceneNode sceneNode) {
1415
if (componentManager->HasComponent<ScriptableClassComponent>(sceneNode.entity)) {
1516
ScriptEntitySystem *scriptEntitySystem = (ScriptEntitySystem*) entitySystemManager->GetEntitySystem<ScriptEntitySystem>();
@@ -22,6 +23,7 @@ void EntityComponentOrchestrator::NewEntityAddChild(Entity parent, Entity child)
2223
AddChildToEntityScene(childNode.parent, childNode.entity);
2324
NodeComponent nodeComponent = componentManager->GetComponent<NodeComponent>(childNode.entity);
2425
nodeNameToEntityMap.emplace(nodeComponent.name, childNode.entity);
26+
entitySystemManager->OnEntityTagsUpdatedSystemsHook(child, {}, nodeComponent.tags);
2527
CallStartOnScriptInstances(childNode);
2628
}
2729

@@ -52,7 +54,7 @@ void EntityComponentOrchestrator::DestroyEntity(SceneNode sceneNode) {
5254
nodeNameToEntityMap.erase(nodeComponent.name);
5355
entityManager->DestroyEntity(entityToRemove);
5456
componentManager->EntityDestroyed(entityToRemove);
55-
entitySystemManager->EntityDestroyed(entityToRemove);
57+
entitySystemManager->EntityDestroyed(entityToRemove, nodeComponent.tags);
5658
signalManager->RemoveEntitySignals(entityToRemove);
5759
}
5860
}
@@ -106,6 +108,7 @@ void EntityComponentOrchestrator::RegisterSceneNodeInstances(SceneNode sceneNode
106108
}
107109
NodeComponent nodeComponent = componentManager->GetComponent<NodeComponent>(sceneNode.entity);
108110
nodeNameToEntityMap.emplace(nodeComponent.name, sceneNode.entity);
111+
entitySystemManager->OnEntityTagsUpdatedSystemsHook(sceneNode.entity, {}, nodeComponent.tags);
109112

110113
for (SceneNode childSceneNode : sceneNode.children) {
111114
RegisterSceneNodeInstances(childSceneNode);

src/core/ecs/system/entity_system.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33

44
#include <set>
55

6-
#include "../entity/entity.h"
6+
#include "../entity/entity_tag_cache.h"
77
#include "../../global_dependencies.h"
88

99
const unsigned int MAX_SYSTEMS = 32;
1010

1111
class EntitySystem {
12-
protected:
13-
bool enabled = false;
1412
public:
15-
std::set<Entity> entities;
16-
1713
bool IsEnabled() {
1814
return enabled;
1915
}
@@ -28,6 +24,10 @@ class EntitySystem {
2824
enabled = false;
2925
}
3026

27+
bool HasEntity(Entity entity) const {
28+
return entities.count(entity) > 0;
29+
}
30+
3131
// Hooks
3232
virtual void OnRegisterEntity(Entity entity) {
3333
entities.insert(entity);
@@ -36,12 +36,28 @@ class EntitySystem {
3636
entities.erase(entity);
3737
}
3838

39-
virtual void OnEntityDestroyed(Entity entity) {}
39+
virtual void OnEntityDestroyed(Entity entity) {
40+
entities.erase(entity);
41+
}
4042

4143
// Subscribable hooks
4244
virtual void Process(float deltaTime) {}
4345
virtual void PhysicsProcess(float deltaTime) {}
4446
virtual void Render() {}
47+
48+
virtual void OnEntityTagsUpdated(Entity entity, const std::vector<std::string>& oldTags, const std::vector<std::string>& newTags) {
49+
entityTagCache.RemoveEntityTags(entity, oldTags);
50+
entityTagCache.AddEntityTags(entity, newTags);
51+
}
52+
53+
virtual void OnEntityTagsRemoved(Entity entity, const std::vector<std::string>& tags) {
54+
entityTagCache.RemoveEntityTags(entity, tags);
55+
}
56+
57+
protected:
58+
bool enabled = false;
59+
EntityTagCache entityTagCache;
60+
std::set<Entity> entities;
4561
};
4662

4763
#endif //ENTITY_SYSTEM_H

src/core/ecs/system/entity_system_manager.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ enum class EntitySystemHook : int {
1515
PROCESS = 2,
1616
PHYSICS_PROCESS = 4,
1717
RENDER = 8,
18-
ALL = PROCESS | PHYSICS_PROCESS | RENDER,
18+
ON_ENTITY_TAGS_UPDATE = 16,
19+
ALL = PROCESS | PHYSICS_PROCESS | RENDER | ON_ENTITY_TAGS_UPDATE,
1920
};
2021
GENERATE_ENUM_CLASS_OPERATORS(EntitySystemHook)
2122

@@ -28,6 +29,7 @@ class EntitySystemManager : public Singleton<EntitySystemManager> {
2829
std::vector<EntitySystem*> processSystems = {};
2930
std::vector<EntitySystem*> physicsProcessSystems = {};
3031
std::vector<EntitySystem*> renderSystems = {};
32+
std::vector<EntitySystem*> onEntityTagsUpdatedSystems = {};
3133

3234
void ProcessSystemHooks(EntitySystem* system, EntitySystemHook systemHooks) {
3335
if (systemHooks == EntitySystemHook::NONE) {
@@ -42,6 +44,9 @@ class EntitySystemManager : public Singleton<EntitySystemManager> {
4244
if ((systemHooks & EntitySystemHook::RENDER) == EntitySystemHook::RENDER) {
4345
renderSystems.emplace_back(system);
4446
}
47+
if ((systemHooks & EntitySystemHook::ON_ENTITY_TAGS_UPDATE) == EntitySystemHook::ON_ENTITY_TAGS_UPDATE) {
48+
onEntityTagsUpdatedSystems.emplace_back(system);
49+
}
4550
}
4651

4752
public:
@@ -125,11 +130,13 @@ class EntitySystemManager : public Singleton<EntitySystemManager> {
125130
}
126131
}
127132

128-
void EntityDestroyed(Entity entity) {
133+
void EntityDestroyed(Entity entity, const std::vector<std::string>& tags) {
129134
for (auto const& pair : systems) {
130135
auto const& system = pair.second;
131136
system->OnEntityDestroyed(entity);
132-
system->entities.erase(entity);
137+
}
138+
for (EntitySystem *tagSystem : onEntityTagsUpdatedSystems) {
139+
tagSystem->OnEntityTagsRemoved(entity, tags);
133140
}
134141
}
135142

@@ -168,4 +175,12 @@ class EntitySystemManager : public Singleton<EntitySystemManager> {
168175
system->Render();
169176
}
170177
}
178+
179+
void OnEntityTagsUpdatedSystemsHook(Entity entity, const std::vector<std::string>& oldTags, const std::vector<std::string>& newTags) {
180+
for (EntitySystem *tagSystem : onEntityTagsUpdatedSystems) {
181+
if (tagSystem->HasEntity(entity)) {
182+
tagSystem->OnEntityTagsUpdated(entity, oldTags, newTags);
183+
}
184+
}
185+
}
171186
};

src/core/ecs/system/systems/collision_entity_system.h

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class CollisionEntitySystem : public EntitySystem {
6161
ColliderComponent sourceColliderComponent = componentManager->GetComponent<ColliderComponent>(sourceEntity);
6262
return std::find(sourceColliderComponent.collisionExceptions.begin(), sourceColliderComponent.collisionExceptions.end(), targetEntity) != sourceColliderComponent.collisionExceptions.end();
6363
}
64+
6465
public:
6566
CollisionEntitySystem() {
6667
collisionContext = GD::GetContainer()->collisionContext;
@@ -82,31 +83,6 @@ class CollisionEntitySystem : public EntitySystem {
8283

8384
void OnEntityDestroyed(Entity entity) override {}
8485

85-
// void ProcessCollisions() {
86-
// collisionContext->ClearCollisionData();
87-
// // TODO: Come up with a better more efficient solution
88-
// for (Entity sourceEntity : entities) {
89-
// std::vector<Entity> collidedEntities;
90-
// for (Entity targetEntity : entities) {
91-
// if (!IsTargetCollisionEntityInExceptionList(sourceEntity, targetEntity)) {
92-
// Rect2 sourceCollisionRectangle = GetCollisionRectangle(sourceEntity);
93-
// Rect2 targetCollisionRectangle = GetCollisionRectangle(targetEntity);
94-
// if (CollisionResolver::DoesRectanglesCollide(sourceCollisionRectangle, targetCollisionRectangle)) {
95-
// collidedEntities.emplace_back(targetEntity);
96-
// // TODO: emit signal if Area2D like functionality for entering and exiting is required
97-
// }
98-
// }
99-
// }
100-
// if (collidedEntities.size() > 0) {
101-
// collisionContext->RegisterCollisionResult(
102-
// CollisionResult{
103-
// .sourceEntity = sourceEntity,
104-
// .collidedEntities = collidedEntities
105-
// });
106-
// }
107-
// }
108-
// }
109-
11086
void ProcessEntityCollisions(Entity sourceEntity, Vector2 offset = Vector2(0.0f, 0.0f)) {
11187
collisionContext->ClearCollisionData();
11288
std::vector<Entity> collidedEntities;
@@ -129,6 +105,28 @@ class CollisionEntitySystem : public EntitySystem {
129105
}
130106
}
131107

108+
void ProcessEntityCollisionsByTag(Entity sourceEntity, const std::string& tag, Vector2 offset = Vector2(0.0f, 0.0f)) {
109+
collisionContext->ClearCollisionData();
110+
std::vector<Entity> collidedEntities;
111+
for (Entity targetEntity : entityTagCache.GetTaggedEntities(tag)) {
112+
if (!IsTargetCollisionEntityInExceptionList(sourceEntity, targetEntity)) {
113+
Rect2 sourceCollisionRectangle = GetCollisionRectangle(sourceEntity) + offset;
114+
Rect2 targetCollisionRectangle = GetCollisionRectangle(targetEntity);
115+
if (CollisionResolver::DoesRectanglesCollide(sourceCollisionRectangle, targetCollisionRectangle)) {
116+
collidedEntities.emplace_back(targetEntity);
117+
// TODO: emit signal if Area2D like functionality for entering and exiting is required
118+
}
119+
}
120+
}
121+
if (collidedEntities.size() > 0) {
122+
collisionContext->RegisterCollisionResult(
123+
CollisionResult{
124+
.sourceEntity = sourceEntity,
125+
.collidedEntities = collidedEntities
126+
});
127+
}
128+
}
129+
132130
std::vector<Entity> GetEntitiesOnMouse(const Vector2 mousePosition) {
133131
std::vector<Entity> entitiesOnMouse;
134132
Rect2 mouseRectangle = Rect2(mousePosition, Vector2(1.0f, 1.0f));

src/core/ecs/system/systems/script_entity_system.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ScriptEntitySystem : public EntitySystem {
2828
void Disable() override {}
2929

3030
void OnEntityDestroyed(Entity entity) override {
31+
EntitySystem::OnEntityDestroyed(entity);
3132
assert(activeScriptContext != nullptr && "No active script context!");
3233
activeScriptContext->DeleteEntityInstance(entity);
3334
}

src/core/game.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void Game::InitializeECS() {
149149
scriptSystemSignature.set(entityComponentOrchestrator->GetComponentType<ScriptableClassComponent>(), true);
150150
entityComponentOrchestrator->SetSystemSignature<ScriptEntitySystem>(scriptSystemSignature);
151151

152-
EntitySystemHook collisionSystemHooks = projectProperties->areColliderVisible ? EntitySystemHook::RENDER : EntitySystemHook::NONE;
152+
EntitySystemHook collisionSystemHooks = projectProperties->areColliderVisible ? EntitySystemHook::RENDER | EntitySystemHook::ON_ENTITY_TAGS_UPDATE : EntitySystemHook::ON_ENTITY_TAGS_UPDATE;
153153
entityComponentOrchestrator->RegisterSystem<CollisionEntitySystem>(collisionSystemHooks);
154154
ComponentSignature collisionSystemSignature;
155155
collisionSystemSignature.set(entityComponentOrchestrator->GetComponentType<ColliderComponent>(), true);

src/core/scene/scene_manager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "../ecs/component/components/material_component.h"
2828
#include "../ecs/component/components/light3D_component.h"
2929

30+
// TODO: Separate SceneNodeJsonParser into its own file...
3031
class SceneNodeJsonParser {
3132
private:
3233
EntityManager *entityManager = nullptr;

0 commit comments

Comments
 (0)