Cannot respawn inside other players, unless all are blocked.
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
#include "Systems/SpawnerSystem.h"
|
||||
#include "Collision/Collision.h"
|
||||
|
||||
SpawnerSystem::SpawnerSystem(SystemParams params)
|
||||
SpawnerSystem::SpawnerSystem(SystemParams params)
|
||||
: System(params)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn);
|
||||
}
|
||||
|
||||
EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/)
|
||||
EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/, const std::string& dontCollideComponent)
|
||||
{
|
||||
// Spawn the entity in the parent's world if it exists, otherwise in the spawner's world
|
||||
World* world = parent.World;
|
||||
@@ -14,17 +15,41 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /
|
||||
world = spawner.World;
|
||||
}
|
||||
|
||||
// Load the entity file and parse it
|
||||
const std::string& entityFilePath = spawner["Spawner"]["EntityFile"];
|
||||
auto entityFile = ResourceManager::Load<EntityFile>(entityFilePath);
|
||||
if (entityFile == nullptr) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
EntityFileParser parser(entityFile);
|
||||
EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID));
|
||||
|
||||
//If the spawned entity is collideable, then we must not spawn it where it collides with something that
|
||||
//has a dontCollideComponent attached.
|
||||
bool spawnOnCollidable = dontCollideComponent.empty() || !spawnedEntity.HasComponent("Collidable");
|
||||
if (!spawnOnCollidable) {
|
||||
boost::optional<EntityAABB> optBox = Collision::EntityAbsoluteAABB(spawnedEntity);
|
||||
//If we can't calculate the box for some reason, then just spawn somewhere anyway.
|
||||
if (!optBox) {
|
||||
spawnOnCollidable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Find any SpawnPoints existing as children of spawner
|
||||
auto children = spawner.World->GetChildren(spawner.ID);
|
||||
std::vector<EntityWrapper> spawnPoints;
|
||||
for (auto kv = children.first; kv != children.second; ++kv) {
|
||||
const EntityID& child = kv->second;
|
||||
if (spawner.World->HasComponent(child, "SpawnPoint")) {
|
||||
spawnPoints.push_back(EntityWrapper(spawner.World, child));
|
||||
EntityWrapper spawnPoint = EntityWrapper(spawner.World, child);
|
||||
if (spawnOnCollidable || !spawnedEntityIsColliding(spawnedEntity, spawnPoint, dontCollideComponent)) {
|
||||
spawnPoints.push_back(spawnPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Choose a random SpawnPoint
|
||||
// If there are no children, or if they are all blocked, then the entity will be spawned at the spawner itself.
|
||||
EntityWrapper spawnPoint = spawner;
|
||||
if (!spawnPoints.empty()) {
|
||||
if (spawnPoints.size() > 1) {
|
||||
@@ -39,25 +64,61 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /
|
||||
}
|
||||
}
|
||||
|
||||
// Load the entity file and parse it
|
||||
const std::string& entityFilePath = spawner["Spawner"]["EntityFile"];
|
||||
auto entityFile = ResourceManager::Load<EntityFile>(entityFilePath);
|
||||
if (entityFile == nullptr) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
EntityFileParser parser(entityFile);
|
||||
EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID));
|
||||
|
||||
if (spawnPoint != parent) {
|
||||
// Set its position and orientation to that of the SpawnPoint
|
||||
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
|
||||
// TODO: Quaternions, bitch
|
||||
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint));
|
||||
transformEntityToSpawnPoint(spawnedEntity, spawnPoint);
|
||||
}
|
||||
|
||||
return spawnedEntity;
|
||||
}
|
||||
|
||||
void SpawnerSystem::transformEntityToSpawnPoint(EntityWrapper spawnedEntity, EntityWrapper spawnPoint)
|
||||
{
|
||||
// Set its position and orientation to that of the SpawnPoint
|
||||
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
|
||||
// TODO: Quaternions, bitch
|
||||
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint));
|
||||
}
|
||||
|
||||
bool SpawnerSystem::spawnedEntityIsColliding(EntityWrapper spawnedEntity, EntityWrapper spawnPoint, const std::string& dontCollideComponent)
|
||||
{
|
||||
transformEntityToSpawnPoint(spawnedEntity, spawnPoint);
|
||||
//Check if the spawned entity collides with anything, and if so, continue to the next spawnpoint.
|
||||
EntityAABB spawnedBox = *Collision::EntityAbsoluteAABB(spawnedEntity);
|
||||
const ComponentPool* otherSpawnedEntities = spawnPoint.World->GetComponents(dontCollideComponent);
|
||||
for (const auto& obj : *otherSpawnedEntities) {
|
||||
if (spawnedEntity.ID == obj.EntityID) {
|
||||
continue;
|
||||
}
|
||||
EntityWrapper otherEntity = EntityWrapper(spawnPoint.World, obj.EntityID);
|
||||
if (!otherEntity.HasComponent("Collidable")) {
|
||||
continue;
|
||||
}
|
||||
auto otherBox = Collision::EntityAbsoluteAABB(otherEntity);
|
||||
if (!otherBox) {
|
||||
continue;
|
||||
}
|
||||
if (Collision::AABBVsAABB(spawnedBox, *otherBox)) {
|
||||
if (!spawnedBox.Entity.HasComponent("Model")) {
|
||||
return true;
|
||||
}
|
||||
RawModel* model = nullptr;
|
||||
try {
|
||||
model = ResourceManager::Load<RawModel, true>(otherEntity["Model"]["Resource"]);
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
|
||||
if (model != nullptr && Collision::AABBvsTriangles(
|
||||
spawnedBox,
|
||||
model->Vertices(),
|
||||
model->m_Indices,
|
||||
Transform::ModelMatrix(otherEntity))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e)
|
||||
{
|
||||
EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent);
|
||||
|
||||
Reference in New Issue
Block a user