shooter/engine/World.cpp

126 lines
4.2 KiB
C++
Raw Normal View History

2021-09-13 15:53:43 +03:00
//
// Created by Иван Ильин on 13.01.2021.
//
#include "World.h"
#include "utils/Log.h"
#include "Plane.h"
#include "ResourceManager.h"
2021-10-22 19:42:32 +03:00
#include <sstream>
#include <cmath>
2021-09-13 15:53:43 +03:00
using namespace std;
2021-10-28 16:58:02 +03:00
void World::addBody(std::shared_ptr<RigidBody> body) {
_objects.emplace(body->name(), body);
Log::log("World::addBody(): inserted body '" + body->name().str() + "' with " + std::to_string(_objects[body->name()]->triangles().size()) + " tris.");
2021-09-13 15:53:43 +03:00
}
2021-10-17 20:52:21 +03:00
void World::loadBody(const ObjectNameTag& tag, const string &filename, const Vec3D& scale) {
2021-10-28 16:58:02 +03:00
_objects.emplace(tag, std::make_shared<RigidBody>(Mesh(tag, filename, scale)));
2021-10-17 10:21:10 +03:00
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + tag.str() + "' with " + std::to_string(_objects[tag]->triangles().size()) + " tris.");
2021-09-13 15:53:43 +03:00
}
2021-10-22 19:42:32 +03:00
IntersectionInformation World::rayCast(const Vec3D& from, const Vec3D& to, const std::string& skipTags) {
2021-09-13 15:53:43 +03:00
2021-10-22 19:42:32 +03:00
// make vector of tags, that we are going to escape
vector <string> tagsToSkip;
stringstream s(skipTags);
std::string t;
while (s >> t) tagsToSkip.push_back(t);
bool intersected = false;
2021-10-28 16:58:02 +03:00
Vec3D point{};
Triangle triangle;
2021-10-17 10:21:10 +03:00
std::string bodyName;
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
2021-10-22 19:42:32 +03:00
std::shared_ptr<RigidBody> intersectedBody = nullptr;
2021-09-13 15:53:43 +03:00
2021-10-17 10:21:10 +03:00
for(auto& [name, body] : _objects) {
2021-10-22 19:42:32 +03:00
2021-10-28 16:58:02 +03:00
// TODO: check this stuff:
2021-10-22 19:42:32 +03:00
//for (auto& escapeTag : tagsToSkip)
// if(name.str().find(escapeTag) != std::string::npos)
// continue;
2021-10-28 16:58:02 +03:00
if(name.str().find("Player") != std::string::npos || name.str().find("weapon") != std::string::npos) {
2021-09-13 15:53:43 +03:00
continue;
2021-10-28 16:58:02 +03:00
}
2021-09-13 15:53:43 +03:00
2021-10-17 10:21:10 +03:00
for(auto& tri : body->triangles()) {
Triangle tri_translated(tri[0] + body->position().makePoint4D(), tri[1] + body->position().makePoint4D(), tri[2] + body->position().makePoint4D());
2021-09-13 15:53:43 +03:00
Plane plane(tri_translated);
auto intersection = plane.intersection(from, to);
double distance = (intersection.first - from).sqrAbs();
if(intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) {
minDistance = distance;
2021-10-28 16:58:02 +03:00
point = intersection.first;
triangle = tri_translated;
2021-10-17 10:21:10 +03:00
bodyName = name.str();
2021-10-22 19:42:32 +03:00
intersected = true;
intersectedBody = body;
2021-09-13 15:53:43 +03:00
}
}
}
2021-10-28 16:58:02 +03:00
return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody, intersected};
2021-09-13 15:53:43 +03:00
}
2021-10-17 20:52:21 +03:00
void World::loadMap(const std::string& filename, const Vec3D& scale) {
auto objs = ResourceManager::loadObjects(filename);
2021-10-28 16:58:02 +03:00
for(auto & i : objs) {
std::shared_ptr<RigidBody> obj = std::make_shared<RigidBody>(*i);
addBody(obj);
obj->scale(scale);
2021-09-13 15:53:43 +03:00
}
}
2021-10-17 10:21:10 +03:00
void World::removeBody(const ObjectNameTag& tag) {
2021-10-28 16:58:02 +03:00
if(_objects.erase(tag) > 0) {
2021-10-17 10:21:10 +03:00
Log::log("World::removeBody(): removed body '" + tag.str() + "'");
2021-10-28 16:58:02 +03:00
} else {
2021-10-17 10:21:10 +03:00
Log::log("World::removeBody(): cannot remove body '" + tag.str() + "': body does not exist.");
2021-10-28 16:58:02 +03:00
}
}
2021-10-17 10:21:10 +03:00
void World::checkCollision(const ObjectNameTag& tag) {
if (_objects[tag]->isCollision()) {
2021-10-17 10:21:10 +03:00
_objects[tag]->setInCollision(false);
2021-10-09 14:38:24 +03:00
for (auto it = _objects.begin(); it != _objects.end();) {
auto obj = it->second;
2021-10-17 10:21:10 +03:00
ObjectNameTag name = it->first;
2021-10-09 14:38:24 +03:00
it++;
2021-10-17 10:21:10 +03:00
if(name != tag) {
std::pair<bool, Simplex> gjk = _objects[tag]->checkGJKCollision(obj);
if (gjk.first) {
2021-10-09 14:38:24 +03:00
if (obj->isCollider()) {
2021-10-17 10:21:10 +03:00
CollisionPoint epa = _objects[tag]->EPA(gjk.second, obj);
_objects[tag]->solveCollision(epa);
}
2021-10-28 16:58:02 +03:00
if (_objects[tag]->collisionCallBack() != nullptr) {
2021-10-17 10:21:10 +03:00
_objects[tag]->collisionCallBack()(name, obj);
2021-10-28 16:58:02 +03:00
}
}
}
}
}
}
void World::update() {
for (auto &m : _objects) {
m.second->updatePhysicsState();
checkCollision(m.first);
}
}
2021-10-17 10:21:10 +03:00
std::shared_ptr<RigidBody> World::body(const ObjectNameTag& tag) {
2021-10-28 16:58:02 +03:00
if(_objects.count(tag) == 0) {
return nullptr;
2021-10-28 16:58:02 +03:00
}
2021-10-17 10:21:10 +03:00
return _objects.find(tag)->second;
2021-09-13 15:53:43 +03:00
}