Cannot respawn inside other players, unless all are blocked.

This commit is contained in:
William Moberg
2016-02-17 14:54:59 +01:00
parent 969e7cb0d5
commit 23bb1a6405
5 changed files with 143 additions and 24 deletions
+9 -1
View File
@@ -78,13 +78,21 @@ bool AABBvsTriangles(const AABB& box,
bool& isOnGround, bool& isOnGround,
glm::vec3& outResolutionVector); glm::vec3& outResolutionVector);
//Detects collision, but does not resolve.
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
//Also outputs the minimum translation that box [a] would need in order to resolve collision. //Also outputs the minimum translation that box [a] would need in order to resolve collision.
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation);
// Calculates an absolute AABB from an entity AABB component // Calculates an absolute AABB from an entity AABB component or Model component.
// if takeModelBox is true, the AABB component will be ignored and box is calculated from Model.
// if takeModelBox is false, the AABB component will be prefered, if it exists.
boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false); boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false);
boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity); boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity);
//Returns the first entity hit by the input ray. entitiesPotentiallyHitSorted needs to be sorted //Returns the first entity hit by the input ray. entitiesPotentiallyHitSorted needs to be sorted
+6 -1
View File
@@ -15,11 +15,16 @@ class SpawnerSystem : public System
public: public:
SpawnerSystem(SystemParams params); SpawnerSystem(SystemParams params);
static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); // If dontCollideComponent is set, to e.g. "Player", then all the spawner
// will try to pick a spawn location so that the spawned entity doesn't
// collide with anything that has that component and is collidable.
static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid, const std::string& dontCollideComponent = "");
private: private:
EventRelay<SpawnerSystem, Events::SpawnerSpawn> m_OnSpawnerSpawn; EventRelay<SpawnerSystem, Events::SpawnerSpawn> m_OnSpawnerSpawn;
bool OnSpawnerSpawn(Events::SpawnerSpawn& e); bool OnSpawnerSpawn(Events::SpawnerSpawn& e);
static void transformEntityToSpawnPoint(EntityWrapper spawnedEntity, EntityWrapper spawnPoint);
static bool spawnedEntityIsColliding(EntityWrapper spawnedEntity, EntityWrapper spawnPoint, const std::string& dontCollideComponent);
}; };
#endif #endif
+49 -4
View File
@@ -366,7 +366,8 @@ bool AABBvsTriangle(const AABB& box,
float verticalStepHeight, float verticalStepHeight,
bool& isOnGround, bool& isOnGround,
glm::vec3& boxVelocity, glm::vec3& boxVelocity,
glm::vec3& outResolution) glm::vec3& outResolution,
bool resolveCollision)
{ {
//Check so we don't have a zero area triangle when calculating the normal. //Check so we don't have a zero area triangle when calculating the normal.
//Also, don't check a triangle facing away from the player. //Also, don't check a triangle facing away from the player.
@@ -426,7 +427,7 @@ bool AABBvsTriangle(const AABB& box,
//if projections don't overlap, return false. //if projections don't overlap, return false.
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) { if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) {
return false; return false;
} else { } else if (resolveCollision) {
//Overwrite the smallest resolution if this is smaller. //Overwrite the smallest resolution if this is smaller.
if (resolutionDist < resolveShortest.DistanceSq) { if (resolutionDist < resolveShortest.DistanceSq) {
resolveShortest.Vector = glm::vec3(0.f); resolveShortest.Vector = glm::vec3(0.f);
@@ -463,6 +464,11 @@ bool AABBvsTriangle(const AABB& box,
if (glm::abs(t) > 1) { if (glm::abs(t) > 1) {
return false; return false;
} }
if (!resolveCollision) {
return true;
}
glm::vec3 cornerResolution = (1+t) * diagonal; glm::vec3 cornerResolution = (1+t) * diagonal;
//Overwrite the smallest resolution if cornerResolution is smaller. //Overwrite the smallest resolution if cornerResolution is smaller.
float lenSq = glm::length2(cornerResolution); float lenSq = glm::length2(cornerResolution);
@@ -537,7 +543,8 @@ bool AABBvsTriangles(const AABB& box,
glm::vec3& boxVelocity, glm::vec3& boxVelocity,
float verticalStepHeight, float verticalStepHeight,
bool& isOnGround, bool& isOnGround,
glm::vec3& outResolutionVector) glm::vec3& outResolutionVector,
bool resolveCollision)
{ {
bool hit = false; bool hit = false;
@@ -553,7 +560,7 @@ bool AABBvsTriangles(const AABB& box,
}; };
glm::vec3 outVec; glm::vec3 outVec;
bool collideWithGround = isOnGround; bool collideWithGround = isOnGround;
if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec)) { if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec, resolveCollision)) {
hit = true; hit = true;
outResolutionVector += outVec; outResolutionVector += outVec;
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size()); newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
@@ -569,6 +576,44 @@ bool AABBvsTriangles(const AABB& box,
return hit; return hit;
} }
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& boxVelocity,
float verticalStepHeight,
bool& isOnGround,
glm::vec3& outResolutionVector)
{
return AABBvsTriangles(box,
modelVertices,
modelIndices,
modelMatrix,
boxVelocity,
verticalStepHeight,
isOnGround,
outResolutionVector,
true);
}
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix)
{
glm::vec3 vel, outres;
bool g;
return AABBvsTriangles(box,
modelVertices,
modelIndices,
modelMatrix,
vel,
0.f,
g,
outres,
false);
}
boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox) boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox)
{ {
AABB modelSpaceBox; AABB modelSpaceBox;
+2 -2
View File
@@ -3,7 +3,7 @@
//This should be set by the config anyway. //This should be set by the config anyway.
float PlayerSpawnSystem::m_RespawnTime = 15.0f; float PlayerSpawnSystem::m_RespawnTime = 15.0f;
PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params)
: System(params) : System(params)
, m_Timer(0.f) , m_Timer(0.f)
{ {
@@ -49,7 +49,7 @@ void PlayerSpawnSystem::Update(double dt)
} }
// Spawn the player! // Spawn the player!
EntityWrapper player = SpawnerSystem::Spawn(spawner); EntityWrapper player = SpawnerSystem::Spawn(spawner, EntityWrapper::Invalid, "Player");
// Set the player team affiliation // Set the player team affiliation
player["Team"]["Team"] = req.Team; player["Team"]["Team"] = req.Team;
+77 -16
View File
@@ -1,12 +1,13 @@
#include "Systems/SpawnerSystem.h" #include "Systems/SpawnerSystem.h"
#include "Collision/Collision.h"
SpawnerSystem::SpawnerSystem(SystemParams params) SpawnerSystem::SpawnerSystem(SystemParams params)
: System(params) : System(params)
{ {
EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); 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 // Spawn the entity in the parent's world if it exists, otherwise in the spawner's world
World* world = parent.World; World* world = parent.World;
@@ -14,17 +15,41 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /
world = spawner.World; 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 // Find any SpawnPoints existing as children of spawner
auto children = spawner.World->GetChildren(spawner.ID); auto children = spawner.World->GetChildren(spawner.ID);
std::vector<EntityWrapper> spawnPoints; std::vector<EntityWrapper> spawnPoints;
for (auto kv = children.first; kv != children.second; ++kv) { for (auto kv = children.first; kv != children.second; ++kv) {
const EntityID& child = kv->second; const EntityID& child = kv->second;
if (spawner.World->HasComponent(child, "SpawnPoint")) { 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 // 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; EntityWrapper spawnPoint = spawner;
if (!spawnPoints.empty()) { if (!spawnPoints.empty()) {
if (spawnPoints.size() > 1) { 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) { if (spawnPoint != parent) {
// Set its position and orientation to that of the SpawnPoint transformEntityToSpawnPoint(spawnedEntity, spawnPoint);
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
// TODO: Quaternions, bitch
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint));
} }
return spawnedEntity; 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) bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e)
{ {
EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent); EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent);