diff options
Diffstat (limited to 'engine-ocean/Game')
111 files changed, 7357 insertions, 0 deletions
diff --git a/engine-ocean/Game/Application.cpp b/engine-ocean/Game/Application.cpp new file mode 100644 index 0000000..8ebea3f --- /dev/null +++ b/engine-ocean/Game/Application.cpp @@ -0,0 +1,101 @@ +#include "Application.h" +#include "Game/menuscreen.h" + +Application::Application() +{ + game = std::make_shared<GameplayScreen>(m_input_map);//new GameplayScreen(m_input_map); + menu = std::make_shared<MenuScreen>(m_input_map); + activeScreen = game; + + createKeyInput(GLFW_KEY_M); + createKeyInput(GLFW_KEY_B); + createKeyInput(GLFW_KEY_R); + +} + + + +void Application::createKeyInput(int inputVal){ + Input input; + input.inputVal = inputVal; + m_input_map[inputVal] = input; +} + +void Application::inactivateOtherKeys(int keyVal){ + for (auto &keypair : m_input_map){ + if (keypair.second.inputVal != keyVal){ + m_input_map.at(keypair.first).isActive = false; + } + } +} + + + +void Application::update(double deltaTime){ + activeScreen->update(deltaTime); +} + +void Application::draw(){ + if (m_input_map.at(GLFW_KEY_M).isActive){ + activeScreen = menu; + } else { + activeScreen = game; + } + + activeScreen->draw(); +} + +void Application::keyEvent(int key, int action){ + switch(key){ + case GLFW_KEY_M: + if (action == GLFW_PRESS){ + inactivateOtherKeys(key); + m_input_map.at(key).isActive = true; + } + break; + case GLFW_KEY_B: + if (action == GLFW_PRESS){ + inactivateOtherKeys(key); + m_input_map.at(key).isActive = true; + } + break; + case GLFW_KEY_R: + if (action == GLFW_PRESS){ + inactivateOtherKeys(key); + m_input_map.at(key).isActive = true; + game = std::make_shared<GameplayScreen>(m_input_map);//new GameplayScreen(m_input_map); + menu = std::make_shared<MenuScreen>(m_input_map); + activeScreen = game; + } + break; + default: + break; + } + + activeScreen->keyEvent(key, action); + +} + +void Application::mousePosEvent(double xpos, double ypos){ + + activeScreen->mousePosEvent(xpos, ypos); + +} + +void Application::mouseButtonEvent(int button, int action){ + activeScreen->mouseButtonEvent(button, action); + +} + +void Application::scrollEvent(double distance){ + activeScreen->scrollEvent(distance); + +} + +void Application::framebufferResizeEvent(int width, int height){ + activeScreen->framebufferResizeEvent(width, height); +} + +void Application::windowResizeEvent(int width, int height){ + activeScreen->windowResizeEvent(width, height); +} diff --git a/engine-ocean/Game/Application.h b/engine-ocean/Game/Application.h new file mode 100644 index 0000000..da592ff --- /dev/null +++ b/engine-ocean/Game/Application.h @@ -0,0 +1,40 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +#include "Game/gameplayscreen.h" +#include "Game/screen.h" +#include "Graphics/global.h" + +#include <GLFW/glfw3.h> + + +class Application +{ +public: + Application(); + void update(double deltaTime); + void draw(); + void keyEvent(int key, int action); + void mousePosEvent(double xpos, double ypos); + void mouseButtonEvent(int button, int action); + void scrollEvent(double distance); + void windowResizeEvent(int width, int height); + void framebufferResizeEvent(int width, int height); + +private: + + void createKeyInput(int inputVal); + void inactivateOtherKeys(int keyVal); + +// Screen activeScreen; +// Screen *game; +// Screen *menu; + std::shared_ptr<Screen> activeScreen; + std::shared_ptr<Screen> game; + std::shared_ptr<Screen> menu; + + std::map<int, Input> m_input_map; +}; + + +#endif // APPLICATION_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp new file mode 100644 index 0000000..d39d118 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp @@ -0,0 +1,88 @@ +#include "boundingdynamicmesh.h" +#include "Graphics/modeltransform.h" +#include <vector> + +// without mesh obj data +BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos) : + m_mt(mt) +{ + m_isMesh = false; + m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale()); +} + +// with mesh obj data +BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos, + std::vector<glm::vec3> &obj_data) : + m_mt(mt), + m_obj_data(obj_data) +{ + m_isMesh = true; + m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale()*getMeshDimensions()*2.f); +} + + +glm::vec3 BoundingDynamicMesh::getCenterPos(){ + return m_mt->getPos(); +} + +void BoundingDynamicMesh::updateCenterPos(glm::vec3 new_pos){ + m_mt->setPos(new_pos); + m_bounding_cylinder->updateCollisionPos(new_pos); +} + + + +glm::vec3 BoundingDynamicMesh::getMeshDimensions(){ + float max_x = m_obj_data[0].x; + float min_x = m_obj_data[0].x; + float max_y = m_obj_data[0].y; + float min_y = m_obj_data[0].y; + float max_z = m_obj_data[0].z; + float min_z = m_obj_data[0].z; + + for (const glm::vec3 &v : m_obj_data){ + // check max + if (v.x > max_x){ + max_x = v.x; + } + if (v.y > max_y){ + max_y = v.y; + } + if (v.z > max_z){ + max_z = v.z; + } + + // check mins + if (v.x < min_x){ + min_x = v.x; + } + if (v.y < min_y){ + min_y = v.y; + } + if (v.z < min_z){ + min_z = v.z; + } + } + + float r_x = (max_x - min_x)/2.f; + float r_y = (max_y - min_y)/2.f; + float r_z = (max_z - min_z)/2.f; + + return glm::vec3(r_x, r_y, r_z); +} + +glm::vec3 BoundingDynamicMesh::getEllipsoidDimensions(){ + if (m_isMesh){ + return m_mt->getScale()*getMeshDimensions(); + } + + return m_mt->getScale()/2.f; +} + +Cylinder BoundingDynamicMesh::getCylinder(){ + return m_bounding_cylinder->getCylinder(); +} + + diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h new file mode 100644 index 0000000..5d24ac8 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h @@ -0,0 +1,32 @@ +#ifndef BOUNDINGDYNAMICMESH_H +#define BOUNDINGDYNAMICMESH_H +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include <memory> +#include <vector> + + +class BoundingDynamicMesh : public BoundingShape +{ +public: + BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos); + BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt, + const glm::vec3 &initial_pos, + std::vector<glm::vec3> &obj_data); + glm::vec3 getCenterPos(); + void updateCenterPos(glm::vec3 new_pos); + glm::vec3 getEllipsoidDimensions(); + Cylinder getCylinder(); + +private: + glm::vec3 getMeshDimensions(); + + bool m_isMesh = false; + std::shared_ptr<ModelTransform> m_mt; + std::vector<glm::vec3> m_obj_data; + std::shared_ptr<CylinderCollider> m_bounding_cylinder; +}; + +#endif // BOUNDINGDYNAMICMESH_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h new file mode 100644 index 0000000..8dce7c3 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h @@ -0,0 +1,21 @@ +#ifndef BOUNDINGELLIPSOID_H +#define BOUNDINGELLIPSOID_H +#include "glm/glm.hpp" +#include "BoundingShape.h" + +struct Ellipsoid{ + glm::vec3 R = glm::vec3(0.f); // holds Rx, Ry, Rz radii + glm::vec3 center_pos; +}; + +struct UnitSphere{ + glm::vec3 center_pos; +}; + +class BoundingEllipsoid : public BoundingShape +{ +public: + BoundingEllipsoid(); +}; + +#endif // BOUNDINGELLIPSOID_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp new file mode 100644 index 0000000..b3abba4 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp @@ -0,0 +1,6 @@ +#include "BoundingShape.h" + +BoundingShape::BoundingShape() +{ + +} diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h new file mode 100644 index 0000000..1303628 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h @@ -0,0 +1,15 @@ +#ifndef SHAPECOLLIDER_H +#define SHAPECOLLIDER_H + +struct CollisionShape{ + +}; + +class BoundingShape +{ +public: + BoundingShape(); + //virtual CollisionShape getCollisionShape() = 0; +}; + +#endif // SHAPECOLLIDER_H diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp new file mode 100644 index 0000000..519d9c7 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp @@ -0,0 +1,200 @@ +#include "boundingtriangle.h" +#include "Graphics/global.h" +#include "Graphics/modeltransform.h" +#include <iostream> +#include "glm/gtx/hash.hpp" + +// ONLY FOR ENVIRONMENTS +BoundingTriangle::BoundingTriangle(const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround) : + obj_mt(mt), + m_isGround(isGround) +{ + populateTriangleData(obj_data); + calculateBounds(obj_data); + //m_datasize = obj_data.size(); +} + +glm::vec3 BoundingTriangle::getRandomSurfacePos(){ + int randomIndex = std::floor(Global::graphics.generateRandomNumbers(0, m_triangles.size()-1)); + int randomVertex = std::floor(Global::graphics.generateRandomNumbers(0, 3)); + + Triangle randomTri = m_triangles[randomIndex]; + + if (glm::dot(glm::vec3(0,1,0), randomTri.normal) > 0.2f){ + switch(randomVertex){ + case 0: + return randomTri.vertexA; + break; + case 1: + return randomTri.vertexB; + break; + default: + return randomTri.vertexC; + break; + } + } else { + // do again until returning a surface triangle + getRandomSurfacePos(); + } +} + + +void BoundingTriangle::addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC){ + Triangle tri; + tri.vertexA = vertexA; + tri.vertexB = vertexB; + tri.vertexC = vertexC; + + tri.edge1 = vertexB - vertexA; // edge ab + tri.edge2 = vertexC - vertexA; // edge bc + tri.normal = glm::normalize(glm::cross(tri.edge1, tri.edge2)); + tri.bounds = calculateTriangleBounds(vertexA, vertexB, vertexC); + + // if triangle is a ground triangle + if (m_isGround){ + if (glm::dot(glm::vec3(0,1,0), tri.normal) > 0.2f){ + //std::cout << "area: " << getArea(vertexA, vertexB, vertexC) << std::endl; + tesselateTriangle(vertexA, vertexB, vertexC); + } + } + + m_triangles.push_back(tri); +} + +float BoundingTriangle::getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + glm::vec3 AB = B-A; + glm::vec3 AC = C-A; + return .5f*glm::length((glm::cross(AB,AC))); + +} + +glm::vec3 BoundingTriangle::getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + return .333f*(A + B + C); +} + +// tesselation into smaller triangles +void BoundingTriangle::tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){ + float min_area = 1.5f; + + // add centroid if area is small enough + if (getArea(A,B,C) <= min_area){ + m_surface_points.push_back(getCentroid(A, B, C)); + return; + } + + // otherwise divide triangle in 4 (tesselate) + + glm::vec3 ab_mid = .5f*(A+B); + glm::vec3 ac_mid = .5f*(A+C); + glm::vec3 bc_mid = .5f*(B+C); + m_surface_points.push_back(ab_mid); + m_surface_points.push_back(ac_mid); + m_surface_points.push_back(bc_mid); + + tesselateTriangle(ab_mid, ac_mid, A); + tesselateTriangle(bc_mid, ab_mid, B); + tesselateTriangle(bc_mid, ac_mid, C); + tesselateTriangle(ab_mid, ac_mid, bc_mid); +} + + +void BoundingTriangle::populateTriangleData(const std::vector<glm::vec3> &obj_data){ + for (int i=0; i<obj_data.size(); i += 3){ + // convert to worldspace + glm::mat4 modelMat = obj_mt->getModelMatrix(); + glm::vec3 v1 = modelMat*glm::vec4(obj_data[i],1.0); + glm::vec3 v2 = modelMat*glm::vec4(obj_data[i+1],1.0); + glm::vec3 v3 = modelMat*glm::vec4(obj_data[i+2],1.0); + + // make triangle + addTriangle(v1, v2, v3); + } + +// m_surface_points.reserve(m_unique_surface_points.size()); +// std::copy(m_unique_surface_points.begin(), m_unique_surface_points.end(), m_surface_points.begin()); +} + +Bounds3f BoundingTriangle::calculateTriangleBounds(const glm::vec3 &vertexA, + const glm::vec3 &vertexB, + const glm::vec3 &vertexC){ + Bounds3f bounds; + + float max_x, min_x = vertexA.x; + float max_y, min_y = vertexA.y; + float max_z, min_z = vertexA.z; + + if (vertexB.x > max_x) max_x = vertexB.x; + if (vertexB.y > max_y) max_y = vertexB.y; + if (vertexB.z > max_z) max_z = vertexB.z; + + if (vertexC.x > max_x) max_x = vertexC.x; + if (vertexC.y > max_y) max_y = vertexC.y; + if (vertexC.z > max_z) max_z = vertexC.z; + + if (vertexB.x < min_x) min_x = vertexB.x; + if (vertexB.y < min_y) min_y = vertexB.y; + if (vertexB.z < min_z) min_z = vertexB.z; + + if (vertexC.x < min_x) min_x = vertexC.x; + if (vertexC.y < min_y) min_y = vertexC.y; + if (vertexC.z < min_z) min_z = vertexC.z; + + + bounds.max = glm::vec3(max_x, max_y, max_z); + bounds.min = glm::vec3(min_x, min_y, min_z); + + return bounds; +} + +void BoundingTriangle::calculateBounds(const std::vector<glm::vec3> &obj_data){ + max_x = obj_data[0].x; + min_x = obj_data[0].x; + max_y = obj_data[0].y; + min_y = obj_data[0].y; + max_z = obj_data[0].z; + min_z = obj_data[0].z; + + for (const glm::vec3 &v : obj_data){ + // check max + if (v.x > max_x){ + max_x = v.x; + } + if (v.y > max_y){ + max_y = v.y; + } + if (v.z > max_z){ + max_z = v.z; + } + + // check mins + if (v.x < min_x){ + min_x = v.x; + } + if (v.y < min_y){ + min_y = v.y; + } + if (v.z < min_z){ + min_z = v.z; + } + } +} + +Bounds3f BoundingTriangle::getMeshBounds(){ + Bounds3f bounds; + bounds.max = glm::vec3(max_x, max_y, max_z); + bounds.min = glm::vec3(min_x, min_y, min_z); + return bounds; +} + +std::vector<glm::vec3> BoundingTriangle::getSurfacePoints(){ + if (!m_isGround){ + std::cout << "getting surface points of not-ground object!" << std::endl; + } + return m_surface_points; +} + +std::vector<Triangle> BoundingTriangle::getTriangleData(){ + return m_triangles; +} diff --git a/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp new file mode 100644 index 0000000..bea3f9e --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp @@ -0,0 +1,47 @@ +#include "collisioncomponent.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h" +#include "Graphics/shape.h" +#include <memory> + +// for dynamic objects +CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos) +{ + if (shapeType == "dynamic_mesh"){ + //addCollisionShape<CylinderCollider>(std::make_shared<CylinderCollider>(initial_pos, initial_scale)); + addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos)); + } +} + +CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data) +{ + if (shapeType == "dynamic_mesh"){ + addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos, obj_data)); + } +} + +// for rigid meshes / environment +CollisionComponent::CollisionComponent(std::string shapeType, + const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround){ + if (shapeType == "obj"){ + addCollisionShape<BoundingTriangle>(std::make_shared<BoundingTriangle>(obj_data, mt, isGround)); + } + +} + + + +bool CollisionComponent::isRigidBody(){ + return m_isRigid; +} + +float CollisionComponent::getReboundVel(){ + return m_rebound_vel; +} + +float CollisionComponent::getAcceleration(){ + return m_acceleration; +} diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp new file mode 100644 index 0000000..3dfded9 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp @@ -0,0 +1,47 @@ +#include "cylindercollider.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Graphics/modeltransform.h" + +CylinderCollider::CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale){ + m_scale = initial_scale; + + m_cyl.point = glm::vec2(initial_pos.x, initial_pos.z); + m_cyl.radius = .5f * glm::max(initial_scale.x, initial_scale.z); + m_cyl.height = 1.f * abs(initial_scale.y); + m_cyl.min = initial_pos.y - (initial_scale.y/2.f); + m_cyl.max = initial_pos.y + (initial_scale.y/2.f); + + m_cyl.aabbDimensions = abs(glm::vec3(2*m_cyl.radius, m_cyl.height, 2*m_cyl.radius)); + m_cyl.aabbCenterPos = initial_pos; + + updateBounds(); +} + +void CylinderCollider::updateCollisionPos(glm::vec3 new_pos){ + m_cyl.point = glm::vec2(new_pos.x, new_pos.z); // x and z loc + m_cyl.radius = .5f * m_scale.x; // x and z dim + m_cyl.height = 1.f * m_scale.y; // y dimensions + m_cyl.min = new_pos.y - (m_scale.y/2.f); // y coord + m_cyl.max = new_pos.y + (m_scale.y/2.f); // y coord + m_cyl.aabbCenterPos = new_pos; + + updateBounds(); +} + + +void CylinderCollider::updateBounds(){ + Bounds3f bounds; + bounds.min = glm::vec3(m_cyl.aabbCenterPos-glm::vec3(m_cyl.aabbDimensions/2.f)); + bounds.max = glm::vec3(m_cyl.aabbCenterPos+glm::vec3(m_cyl.aabbDimensions/2.f)); + + m_cyl.bounds = bounds; +} + + +Cylinder CylinderCollider::getCylinder(){ + return m_cyl; +} + + + + diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h new file mode 100644 index 0000000..3363b84 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h @@ -0,0 +1,37 @@ +#ifndef CYLINDERCOLLIDER_H +#define CYLINDERCOLLIDER_H + +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include "BoundingShape.h" +#include <memory> + + +struct Cylinder { + glm::vec2 point; // bottom Center + float radius; + + // lines + float height; + float min; + float max; + + glm::vec3 aabbDimensions; + glm::vec3 aabbCenterPos; + Bounds3f bounds; +}; + +class CylinderCollider +{ +public: + CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale); + Cylinder getCylinder();// override; + void updateCollisionPos(glm::vec3 new_pos); + void updateBounds(); +private: + glm::vec3 m_scale; + Cylinder m_cyl; +}; + +#endif // CYLINDERCOLLIDER_H diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp new file mode 100644 index 0000000..3f8ed07 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp @@ -0,0 +1,6 @@ +#include "boundingellipsoid.h" + +BoundingEllipsoid::BoundingEllipsoid() +{ + +} diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h new file mode 100644 index 0000000..0263007 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h @@ -0,0 +1,68 @@ +#ifndef BOUNDINGTRIANGLE_H +#define BOUNDINGTRIANGLE_H +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include <set> +#include <vector> +#include "BoundingShape.h" + +struct Bounds3f { + glm::vec3 min; + glm::vec3 max; +}; + +struct Triangle{ + glm::vec3 vertexA; // one vertex + glm::vec3 vertexB; + glm::vec3 vertexC; + + glm::vec3 edge1; // two edges + glm::vec3 edge2; + + glm::vec3 normal;// = glm::cross(edge1, edge2); + Bounds3f bounds; + + +}; + +class BoundingTriangle : public BoundingShape +{ +public: + BoundingTriangle(const std::vector<glm::vec3> &obj_data, + const std::shared_ptr<ModelTransform> &mt, + bool isGround = false); + std::vector<Triangle> getTriangleData(); + + Bounds3f getMeshBounds(); + std::vector<glm::vec3> getSurfacePoints(); + glm::vec3 getRandomSurfacePos(); + + + +private: + void addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC); + void populateTriangleData(const std::vector<glm::vec3> &obj_data); + void calculateBounds(const std::vector<glm::vec3> &obj_data); + Bounds3f calculateTriangleBounds(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC); + + float getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + glm::vec3 getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + void tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C); + + + int m_datasize = 0; + + + + + + std::vector<Triangle> m_triangles; + std::shared_ptr<ModelTransform> obj_mt; + std::set<glm::vec3> m_unique_surface_points; + std::vector<glm::vec3> m_surface_points; + bool m_isGround = false; + + float min_x, min_y, min_z, max_x, max_y, max_z; +}; + +#endif // BOUNDINGTRIANGLE_H diff --git a/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h new file mode 100644 index 0000000..daef723 --- /dev/null +++ b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h @@ -0,0 +1,49 @@ +#ifndef COLLISIONCOMPONENT_H +#define COLLISIONCOMPONENT_H + +#include "Game/Components/CollisionComponents/BoundingShape.h" +#include <map> +#include <string> +#include "Game/TypeMap.h" +#include "Graphics/modeltransform.h" +#include "glm/glm.hpp" +#include "Game/Components/Component.h" + + +class CollisionComponent : public Component +{ +public: + template <typename T> + void addCollisionShape(std::shared_ptr<T> &&component){ + m_collision_shapes.put<T>(std::forward<std::shared_ptr<T>>(component)); + } + + template <typename T> + bool hasCollisionShape(){ + return m_collision_shapes.contains<T>(); + } + + template <class T> + T* getCollisionShape(){ + auto comp = m_collision_shapes.find<T>(); + assert(comp != m_collision_shapes.end()); + return static_cast<T*>(comp->second.get()); + } + + CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data); + CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos); + CollisionComponent(std::string shapeType, const std::vector<glm::vec3> &obj_data, const std::shared_ptr<ModelTransform> &mt, + bool isGround = false); + + bool isRigidBody(); + float getReboundVel(); + float getAcceleration(); + +private: + TypeMap<std::shared_ptr<BoundingShape>> m_collision_shapes; + bool m_isRigid = true; + float m_rebound_vel = 0.f; + float m_acceleration = 0.f; +}; + +#endif // COLLISIONCOMPONENT_H diff --git a/engine-ocean/Game/Components/Component.h b/engine-ocean/Game/Components/Component.h new file mode 100644 index 0000000..fef4330 --- /dev/null +++ b/engine-ocean/Game/Components/Component.h @@ -0,0 +1,13 @@ +#ifndef COMPONENT_H +#define COMPONENT_H + + +class Component +{ +public: + Component(); + + +}; + +#endif // COMPONENT_H diff --git a/engine-ocean/Game/Components/DrawComponent.cpp b/engine-ocean/Game/Components/DrawComponent.cpp new file mode 100644 index 0000000..28640dd --- /dev/null +++ b/engine-ocean/Game/Components/DrawComponent.cpp @@ -0,0 +1,54 @@ +#include "drawcomponent.h" +#include <string> + +DrawComponent::DrawComponent(std::shared_ptr<Shape> shape, std::string shape_name) +{ + m_shape = shape; + m_shape_name = shape_name; +} + +DrawComponent::DrawComponent(std::shared_ptr<Shape> shape) +{ + m_shape = shape; +} + +DrawComponent::DrawComponent(std::vector<std::shared_ptr<Shape>> shapes) +{ + m_shapes = shapes; + hasMultipleShapes = true; +} + + +void DrawComponent::addMaterial(std::string material_name, std::string material_filepath){ + Global::graphics.addMaterial(material_name, material_filepath); + m_material_name = material_name; + hasMaterial = true; +} + +std::shared_ptr<Shape> DrawComponent::getShape(){ + return m_shape; +} + +std::vector<std::shared_ptr<Shape>> DrawComponent::getShapesWithMaterials(){ + if (hasMultipleShapes){ + return m_shapes; + } +} + +std::string DrawComponent::getShapeName(){ + return m_shape_name; +} + +std::shared_ptr<Material> DrawComponent::getMaterial(){ + return Global::graphics.getMaterial(m_material_name); +} + +bool DrawComponent::objHasMaterial(){ + return hasMaterial; +} + +bool DrawComponent::objHasMultipleShapes(){ + return hasMultipleShapes; +} + + diff --git a/engine-ocean/Game/Components/PathfindComponent.h b/engine-ocean/Game/Components/PathfindComponent.h new file mode 100644 index 0000000..13f4e6d --- /dev/null +++ b/engine-ocean/Game/Components/PathfindComponent.h @@ -0,0 +1,22 @@ +#ifndef PATHFINDCOMPONENT_H +#define PATHFINDCOMPONENT_H + + +#include "Game/Systems/Pathfinding/pathfinder.h" +#include "glm/fwd.hpp" +#include <vector> +#include "Component.h" + +class PathfindComponent : public Component +{ +public: + PathfindComponent(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles); + std::vector<glm::vec3> getPath(const glm::vec3 &A, const glm::vec3 &B); + +private: + std::vector<glm::vec3> m_vertices; + std::vector<glm::ivec3> m_triangles; + std::unique_ptr<Pathfinder> m_pathfinder; +}; + +#endif // PATHFINDCOMPONENT_H diff --git a/engine-ocean/Game/Components/TransformComponent.cpp b/engine-ocean/Game/Components/TransformComponent.cpp new file mode 100644 index 0000000..582b623 --- /dev/null +++ b/engine-ocean/Game/Components/TransformComponent.cpp @@ -0,0 +1,92 @@ +#include "transformcomponent.h" + +TransformComponent::TransformComponent(std::shared_ptr<ModelTransform> mt, + std::string entity_id, + std::map<std::string, + BlackboardData>& global_blackboard, bool isAI): + m_model_transform(mt), + m_global_blackboard(global_blackboard), + isAIObject(isAI) +{ + old_pos = mt->getPos(); + estimated_final_pos = mt->getPos(); + m_entity_id = entity_id; + + // initialize blackboard data for entity + BlackboardData data; + m_global_blackboard.insert(std::pair<std::string, BlackboardData>(m_entity_id, data)); + m_global_blackboard[m_entity_id].locationData.currPos = old_pos; +} + +std::shared_ptr<ModelTransform> TransformComponent::getMT(){ + return m_model_transform; +} +std::vector<std::shared_ptr<ModelTransform>> TransformComponent::getAllMT(){ + return m_all_model_transforms; +} + +bool TransformComponent::hasMultipleMT(){ + return multipleMT; +} + +void TransformComponent::translate(const glm::vec3 &delta){ + m_model_transform->translate(delta); + + // update old pos for collisions + + old_pos = m_model_transform->getPos(); + + if (isAIObject){ + m_global_blackboard[m_entity_id].locationData.currPos = old_pos; + } +} + +void TransformComponent::setPos(const glm::vec3 &new_pos){ + m_model_transform->setPos(new_pos); + + // update old pos for collisions + old_pos = new_pos; + + if (isAIObject){ + m_global_blackboard[m_entity_id].locationData.currPos = old_pos; + } +} + +glm::vec3 TransformComponent::getPos(){ + return m_model_transform->getPos(); +} + +void TransformComponent::setScale(const glm::vec3 &scale){ + m_model_transform->setScale(scale); +} + +glm::vec3 TransformComponent::getScale(){ + return m_model_transform->getScale(); +} + +float TransformComponent::getYRotationAngle(){ + glm::mat4 rotMat = m_model_transform->getRotation(); + float ry0 = rotMat[0][2]; +// float ry1 = rotMat[1][2]; +// float ry2 = rotMat[2][2]; + +// float sign = 1.f; +// if (ry1*ry2 < 0) sign = -1.f; + +// float angley = std::atan2(-ry0, sign*pow((pow(ry1,2) + pow(ry2,2)), .5)); + float angley = -std::asin(ry0); + float angley2 = M_PI - angley; + + //std::cout << "angle 1: " << angley << std::endl; + std::cout << "angle 2: " << angley2 << std::endl; + + return angley; +} + +void TransformComponent::setRotation(float angle, glm::vec3 axis){ + m_model_transform->rotate(angle, axis); +} + + + + diff --git a/engine-ocean/Game/Components/component.cpp b/engine-ocean/Game/Components/component.cpp new file mode 100644 index 0000000..f557273 --- /dev/null +++ b/engine-ocean/Game/Components/component.cpp @@ -0,0 +1,6 @@ +#include "component.h" + +Component::Component() +{ + +} diff --git a/engine-ocean/Game/Components/drawcomponent.h b/engine-ocean/Game/Components/drawcomponent.h new file mode 100644 index 0000000..94f4b21 --- /dev/null +++ b/engine-ocean/Game/Components/drawcomponent.h @@ -0,0 +1,41 @@ +#ifndef DRAWCOMPONENT_H +#define DRAWCOMPONENT_H + + +#include "Graphics/global.h" +#include <string> +#include "Component.h" + +class DrawComponent : public Component +{ +public: + DrawComponent(std::shared_ptr<Shape> shape); + DrawComponent(std::shared_ptr<Shape> shape, std::string shape_name); + + // for materials, with multiple shape parts + DrawComponent(std::vector<std::shared_ptr<Shape>> shapes); + + + void draw(const std::shared_ptr<ModelTransform> &entity_mt); + void addMaterial(std::string material_name, std::string material_filepath); + std::shared_ptr<Material> getMaterial(); + std::shared_ptr<Shape> getShape(); + std::vector<std::shared_ptr<Shape>> getShapesWithMaterials(); + bool objHasMaterial(); + bool objHasMultipleShapes(); + + std::string getShapeName(); + +private: + std::shared_ptr<Shape> m_shape; + std::vector<std::shared_ptr<Shape>> m_shapes; + + std::string m_material_name; + bool hasMaterial = false; + std::string m_shape_name = "empty"; + + bool hasMultipleShapes = false; + +}; + +#endif // DRAWCOMPONENT_H diff --git a/engine-ocean/Game/Components/pathfindcomponent.cpp b/engine-ocean/Game/Components/pathfindcomponent.cpp new file mode 100644 index 0000000..ad87e23 --- /dev/null +++ b/engine-ocean/Game/Components/pathfindcomponent.cpp @@ -0,0 +1,16 @@ +#include "pathfindcomponent.h" +#include "glm/glm.hpp" +#include <vector> + +PathfindComponent::PathfindComponent(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles): + m_vertices(vertices), + m_triangles(triangles), + m_pathfinder(std::make_unique<Pathfinder>(vertices, triangles)) +{ + +} + + +std::vector<glm::vec3> PathfindComponent::getPath(const glm::vec3 &A, const glm::vec3 &B){ + return m_pathfinder->findPath(A,B); +} diff --git a/engine-ocean/Game/Components/playercontrolcomponent.cpp b/engine-ocean/Game/Components/playercontrolcomponent.cpp new file mode 100644 index 0000000..40062f1 --- /dev/null +++ b/engine-ocean/Game/Components/playercontrolcomponent.cpp @@ -0,0 +1,6 @@ +#include "playercontrolcomponent.h" + +PlayerControlComponent::PlayerControlComponent() +{ + +} diff --git a/engine-ocean/Game/Components/playercontrolcomponent.h b/engine-ocean/Game/Components/playercontrolcomponent.h new file mode 100644 index 0000000..2a3d91c --- /dev/null +++ b/engine-ocean/Game/Components/playercontrolcomponent.h @@ -0,0 +1,11 @@ +#ifndef PLAYERCONTROLCOMPONENT_H +#define PLAYERCONTROLCOMPONENT_H + + +class PlayerControlComponent +{ +public: + PlayerControlComponent(); +}; + +#endif // PLAYERCONTROLCOMPONENT_H diff --git a/engine-ocean/Game/Components/transformcomponent.h b/engine-ocean/Game/Components/transformcomponent.h new file mode 100644 index 0000000..7b6a5c2 --- /dev/null +++ b/engine-ocean/Game/Components/transformcomponent.h @@ -0,0 +1,54 @@ +#ifndef TRANSFORMCOMPONENT_H +#define TRANSFORMCOMPONENT_H + +#include "Game/Systems/aisystem.h" +#include "Graphics/global.h" +#include <memory> +#include "Component.h" + +class TransformComponent : public Component +{ +public: + TransformComponent(std::shared_ptr<ModelTransform> mt, + std::string entity_id, + std::map<std::string, BlackboardData>& m_global_blackboard, + bool isAI = false); + + void translate(const glm::vec3 &delta); + void setPos(const glm::vec3 &new_pos); + void setScale(const glm::vec3 &scale); + std::shared_ptr<ModelTransform> getMT(); + std::vector<std::shared_ptr<ModelTransform>> getAllMT(); + glm::vec3 getScale(); + //glm::vec3 getRotation(); + void setRotation(float angle, glm::vec3 axis); + float getYRotationAngle(); + + + + + bool hasMultipleMT(); + glm::vec3 getPos(); + + // used for collisions + glm::vec3 old_pos; + glm::vec3 estimated_final_pos; + bool onGround = false; + bool movingLaterally = false; + float gravity = -25.f; + float yVelocity = 0.f; + + + +private: + std::shared_ptr<ModelTransform> m_model_transform; + std::vector<std::shared_ptr<ModelTransform>> m_all_model_transforms; + bool multipleMT = false; + std::map<std::string, BlackboardData>& m_global_blackboard; + std::string m_entity_id; + bool isAIObject = false; + + +}; + +#endif // TRANSFORMCOMPONENT_H diff --git a/engine-ocean/Game/Environment/Environment.cpp b/engine-ocean/Game/Environment/Environment.cpp new file mode 100644 index 0000000..2782194 --- /dev/null +++ b/engine-ocean/Game/Environment/Environment.cpp @@ -0,0 +1,6 @@ +#include "Environment.h" + +Environment::Environment() +{ + +} diff --git a/engine-ocean/Game/Environment/Environment.h b/engine-ocean/Game/Environment/Environment.h new file mode 100644 index 0000000..90a5409 --- /dev/null +++ b/engine-ocean/Game/Environment/Environment.h @@ -0,0 +1,12 @@ +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +class Environment +{ +public: + Environment(); + virtual void draw() = 0; + virtual void update(double deltaTime) = 0; +}; + +#endif // ENVIRONMENT_H diff --git a/engine-ocean/Game/Environment/environmentsystem.cpp b/engine-ocean/Game/Environment/environmentsystem.cpp new file mode 100644 index 0000000..f94b804 --- /dev/null +++ b/engine-ocean/Game/Environment/environmentsystem.cpp @@ -0,0 +1,40 @@ +#include "environmentsystem.h" +#include "Game/Environment/grassenvironment.h" +#include "Game/Environment/skyboxenvironment.h" +#include "Game/Environment/water.h" + +EnvironmentSystem::EnvironmentSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::shared_ptr<Camera> camera) +{ + addEnviron<GrassEnvironment>(std::make_shared<GrassEnvironment>(rigid_gameobjects, dynamic_gameobjects, camera)); + addEnviron<SkyboxEnvironment>(std::make_shared<SkyboxEnvironment>(camera)); + addEnviron<Water>(std::make_shared<Water>(camera)); + + + +} + +void EnvironmentSystem::draw(){ + for (auto &environ : m_environs){ + environ.second->draw(); + } + +} + +void EnvironmentSystem::drawNonWater(){ + getEnviron<GrassEnvironment>()->draw(); + getEnviron<SkyboxEnvironment>()->draw(); + + +} + +void EnvironmentSystem::update(double deltaTime){ + for (auto &environ : m_environs){ + environ.second->update(deltaTime); + } + +} + +void EnvironmentSystem::scrollEvent(double distance){} +void EnvironmentSystem::mousePosEvent(double xpos, double ypos) {} diff --git a/engine-ocean/Game/Environment/environmentsystem.h b/engine-ocean/Game/Environment/environmentsystem.h new file mode 100644 index 0000000..240ecb7 --- /dev/null +++ b/engine-ocean/Game/Environment/environmentsystem.h @@ -0,0 +1,41 @@ +#ifndef ENVIRONMENTSYSTEM_H +#define ENVIRONMENTSYSTEM_H +#include "Game/Environment/Environment.h" +#include "Game/Systems/system.h" + +class EnvironmentSystem : public System +{ +public: + EnvironmentSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::shared_ptr<Camera> camera); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + void drawNonWater(); + + + template <typename T> + void addEnviron(std::shared_ptr<T> &&environ){ + m_environs.put<T>(std::forward<std::shared_ptr<T>>(environ)); + } + + + template <class T> + T* getEnviron(){ + auto comp = m_environs.find<T>(); + assert(comp != m_environs.end()); + return static_cast<T*>(comp->second.get()); + } + + template <class T> + void removeEnviron(){ + m_environs.remove<T>(); + } +private: + TypeMap<std::shared_ptr<Environment>> m_environs; + +}; + +#endif // ENVIRONMENTSYSTEM_H diff --git a/engine-ocean/Game/Environment/grassenvironment.cpp b/engine-ocean/Game/Environment/grassenvironment.cpp new file mode 100644 index 0000000..1d1ed9b --- /dev/null +++ b/engine-ocean/Game/Environment/grassenvironment.cpp @@ -0,0 +1,85 @@ +#include "grassenvironment.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include "Graphics/global.h" + +GrassEnvironment::GrassEnvironment(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::shared_ptr<Camera> camera): + m_rigid_gameobjects(rigid_gameobjects), + m_dynamic_gameobjects(dynamic_gameobjects), + m_camera(camera) +{ + + initializeGrassVBO(); +} + +void GrassEnvironment::initializeGrassVBO(){ +// grass_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/meadow_texture_atlas.png").textureID; +// wind_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/wind_flowmap1.png").textureID; +// meadow_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/meadow_flower_map.png").textureID; + + +// std::vector<glm::vec3> surface_points = m_rigid_gameobjects["ground"]->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getSurfacePoints(); +// positions.insert(std::end(positions), std::begin(surface_points), std::end(surface_points)); + + +// glGenVertexArrays(1, &VAO); +// glGenBuffers(1, &VBO); +// glBindVertexArray(VAO); + +// glBindBuffer(GL_ARRAY_BUFFER, VBO); +// glBufferData(GL_ARRAY_BUFFER, positions.size()*sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW); + +// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0); + +// // unbind +// glEnableVertexAttribArray(0); +// glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +glm::vec2 GrassEnvironment::getRandomOffset(int ub, int numRows){ + int index = floor(Global::graphics.generateRandomNumbers(0, ub)); + int column = index % numRows; + float xoffset = static_cast<float>(column)/static_cast<float>(numRows); + + int row = floor(index/numRows); + float yOffset = static_cast<float>(row)/static_cast<float>(numRows); + return glm::vec2(xoffset, yOffset); +} + +void GrassEnvironment::draw(){ + // draw grass + glPointSize(8.f); + Global::graphics.bindShader("grass"); + + // activate texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, grass_tex); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, wind_tex); + + glActiveTexture(GL_TEXTURE7); + glBindTexture(GL_TEXTURE_2D, meadow_tex); + + // update time + glUniform1f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "u_time"), glfwGetTime()*.1f); + // update player pos + glm::vec3 playerPos = m_dynamic_gameobjects.at("player")->getComponent<TransformComponent>()->getPos(); + glUniform3f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "playerPos"), playerPos.x, playerPos.y, playerPos.z); + + //glm::vec2 offset = getRandomOffset(4, 2); + // update offset + //glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "atlas_offset"), offset.x, offset.y); + + + Global::graphics.setCameraData(m_camera); + Global::graphics.setGlobalData(glm::vec3(.5f)); + glBindVertexArray(VAO); + glDrawArrays(GL_POINTS, 0, positions.size()); +}; + +void GrassEnvironment::update(double deltaTime){}; diff --git a/engine-ocean/Game/Environment/grassenvironment.h b/engine-ocean/Game/Environment/grassenvironment.h new file mode 100644 index 0000000..f92b6c3 --- /dev/null +++ b/engine-ocean/Game/Environment/grassenvironment.h @@ -0,0 +1,37 @@ +#ifndef GRASSENVIRONMENT_H +#define GRASSENVIRONMENT_H +#include "Game/GameObjects/GameObject.h" +#include "Graphics/global.h" +#include "Graphics/camera.h" +#include <GLFW/glfw3.h> +#include "Environment.h" + +class GrassEnvironment : public Environment +{ +public: + GrassEnvironment(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::shared_ptr<Camera> camera); + + void draw() override; + void update(double deltaTime) override; +private: + GLuint VAO, VBO; + GLuint grass_tex, wind_tex, meadow_tex; + std::vector<glm::vec3> positions; + + + + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::shared_ptr<Camera> m_camera; + + + void initializeGrassVBO(); + glm::vec2 getRandomOffset(int ub, int numRows); + + + +}; + +#endif // GRASSENVIRONMENT_H diff --git a/engine-ocean/Game/Environment/skyboxenvironment.cpp b/engine-ocean/Game/Environment/skyboxenvironment.cpp new file mode 100644 index 0000000..f0ad41f --- /dev/null +++ b/engine-ocean/Game/Environment/skyboxenvironment.cpp @@ -0,0 +1,64 @@ +#include "skyboxenvironment.h" +#include "Graphics/global.h" + + +SkyboxEnvironment::SkyboxEnvironment(std::shared_ptr<Camera> camera): + m_camera(camera), + m_rotation_mat(std::make_shared<ModelTransform>()) +{ + initializeVAO(); +} + +void SkyboxEnvironment::initializeVAO(){ + skybox_tex = Global::graphics.loadCubeMap(m_skyboxTextureFiles); + + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, m_vertices.size()*sizeof(float), m_vertices.data(), GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0); + + // unbind + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + + +void SkyboxEnvironment::draw(){ + glDepthFunc(GL_LEQUAL); + glDisable(GL_CULL_FACE); + + Global::graphics.bindShader("skybox"); + //Global::graphics.setCameraData(m_camera); + + // activate texture + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex); + + // manually set view and projection, for non-translating view + glm::mat4 projection = m_camera->getProjection(); + glm::mat4 view = m_camera->getView(); + view[3] = glm::vec4(0.f); + + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "view"), 1, GL_FALSE, glm::value_ptr(view[0])); + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "projection"), 1, GL_FALSE, glm::value_ptr(projection[0])); + + // apply rotation matrix + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "rotation"), 1, GL_FALSE, glm::value_ptr(m_rotation_mat->getRotation()[0])); + + //Global::graphics.setGlobalData(glm::vec3(.5f)); + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, m_vertices.size()); + + glDepthFunc(GL_LESS); +} + +void SkyboxEnvironment::update(double deltaTime){ + m_rotation += ROTATE_SPEED * deltaTime; + m_rotation_mat->rotate(glm::radians(ROTATE_SPEED), glm::vec3(0.f, 1.f, 0.f)); + + +} diff --git a/engine-ocean/Game/Environment/skyboxenvironment.h b/engine-ocean/Game/Environment/skyboxenvironment.h new file mode 100644 index 0000000..aa86c0c --- /dev/null +++ b/engine-ocean/Game/Environment/skyboxenvironment.h @@ -0,0 +1,103 @@ +#ifndef SKYBOXENVIRONMENT_H +#define SKYBOXENVIRONMENT_H +#include "Graphics/global.h" +#include "Graphics/camera.h" +#include <GLFW/glfw3.h> +#include "Environment.h" + + +class SkyboxEnvironment : public Environment +{ +public: + SkyboxEnvironment(std::shared_ptr<Camera> camera); + void draw() override; + void update(double deltaTime) override; +private: + void initializeVAO(); + + GLuint VAO; + GLuint VBO; + GLuint EBO; + GLuint skybox_tex; + std::shared_ptr<Camera> m_camera; + + float SIZE = 500.f; + + std::vector<int> m_vertex_indices = { + // Right + 1, 2, 6, + 6, 5, 1, + // Left + 0, 4, 7, + 7, 3, 0, + // Top + 4, 5, 6, + 6, 7, 4, + // Bottom + 0, 3, 2, + 2, 1, 0, + // Back + 0, 1, 5, + 5, 4, 0, + // Front + 3, 7, 6, + 6, 2, 3 + }; + std::vector<GLfloat> m_vertices = { + -SIZE, SIZE, -SIZE, + -SIZE, -SIZE, -SIZE, + SIZE, -SIZE, -SIZE, + SIZE, -SIZE, -SIZE, + SIZE, SIZE, -SIZE, + -SIZE, SIZE, -SIZE, + + -SIZE, -SIZE, SIZE, + -SIZE, -SIZE, -SIZE, + -SIZE, SIZE, -SIZE, + -SIZE, SIZE, -SIZE, + -SIZE, SIZE, SIZE, + -SIZE, -SIZE, SIZE, + + SIZE, -SIZE, -SIZE, + SIZE, -SIZE, SIZE, + SIZE, SIZE, SIZE, + SIZE, SIZE, SIZE, + SIZE, SIZE, -SIZE, + SIZE, -SIZE, -SIZE, + + -SIZE, -SIZE, SIZE, + -SIZE, SIZE, SIZE, + SIZE, SIZE, SIZE, + SIZE, SIZE, SIZE, + SIZE, -SIZE, SIZE, + -SIZE, -SIZE, SIZE, + + -SIZE, SIZE, -SIZE, + SIZE, SIZE, -SIZE, + SIZE, SIZE, SIZE, + SIZE, SIZE, SIZE, + -SIZE, SIZE, SIZE, + -SIZE, SIZE, -SIZE, + + -SIZE, -SIZE, -SIZE, + -SIZE, -SIZE, SIZE, + SIZE, -SIZE, -SIZE, + SIZE, -SIZE, -SIZE, + -SIZE, -SIZE, SIZE, + SIZE, -SIZE, SIZE + }; + + std::vector<const char*> m_skyboxTextureFiles = {"/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/right.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/left.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/up.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/bottom.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/back.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/front.png"}; + + float ROTATE_SPEED = .1f; // 1 degree per sec + float m_rotation = 0.f; + std::shared_ptr<ModelTransform> m_rotation_mat; + +}; + +#endif // SKYBOXENVIRONMENT_H diff --git a/engine-ocean/Game/Environment/water.cpp b/engine-ocean/Game/Environment/water.cpp new file mode 100644 index 0000000..537bfbd --- /dev/null +++ b/engine-ocean/Game/Environment/water.cpp @@ -0,0 +1,48 @@ +#include "water.h" +#include "GLFW/glfw3.h" + +Water::Water(std::shared_ptr<Camera> camera): + m_camera(camera) +{ + + initializeQuad(); + +} + + +void Water::initializeQuad(){ + m_waterPlane = Global::graphics.addShape("water", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_water.obj"); + m_waterMT = std::make_shared<ModelTransform>(); + m_waterMT->setScale(glm::vec3(1.f)); + m_waterMT->setPos(glm::vec3(0.f)); + Global::graphics.setWaterHeight(m_waterMT->getPos().y); + + du_dv_map = Global::graphics.loadTextureFromFile_Repeat("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/waterDUDV.png").textureID; + + +} + +void Water::draw(){ + Global::graphics.bindShader("water"); + + glActiveTexture(GL_TEXTURE8); + glBindTexture(GL_TEXTURE_2D, Global::graphics.getReflectionTexture()); + glActiveTexture(GL_TEXTURE9); + glBindTexture(GL_TEXTURE_2D, Global::graphics.getRefractionTexture()); + glActiveTexture(GL_TEXTURE10); + glBindTexture(GL_TEXTURE_2D, du_dv_map); + glUniform1f(glGetUniformLocation(Global::graphics.getShaderID("water"), "moveFactor"), m_moveFactor); + + Global::graphics.setCameraData(m_camera); + + Global::graphics.drawShape(Global::graphics.getShape("water"), m_waterMT); + +} + +void Water::update(double deltaTime){ + m_moveFactor += WAVE_SPEED*deltaTime*.01f; + // loop back to 0 if it gets to one + if (m_moveFactor == 1) m_moveFactor = 0; +} + + diff --git a/engine-ocean/Game/Environment/water.h b/engine-ocean/Game/Environment/water.h new file mode 100644 index 0000000..c0df0da --- /dev/null +++ b/engine-ocean/Game/Environment/water.h @@ -0,0 +1,38 @@ +#ifndef WATER_H +#define WATER_H +#include "Graphics/global.h" + + +#include "Environment.h" + +class Water : public Environment +{ +public: + Water(std::shared_ptr<Camera> camera); + void draw() override; + void update(double deltaTime) override; + + + +private: + + GLuint du_dv_map; + void initializeQuad(); + + + + + + std::shared_ptr<Camera> m_camera; + std::vector<glm::vec3> m_waterPlane; + std::shared_ptr<ModelTransform> m_waterMT; + + const float WAVE_SPEED = .008f; + float m_moveFactor = 0.f; + + + + +}; + +#endif // WATER_H diff --git a/engine-ocean/Game/GameObjects/GameObject.cpp b/engine-ocean/Game/GameObjects/GameObject.cpp new file mode 100644 index 0000000..0c7bce8 --- /dev/null +++ b/engine-ocean/Game/GameObjects/GameObject.cpp @@ -0,0 +1,27 @@ +#include "gameobject.h" +#include "Game/Components/DrawComponent.h" + +//GameObject::GameObject(std::shared_ptr<Shape> object, std::shared_ptr<ModelTransform> object_mt) +//{ +// m_object = object; +// m_object_mt = object_mt; +//} + +GameObject::GameObject(){ + +} + +//GameObject::~GameObject(){ + +//} + +//void GameObject::addMaterial(std::string material_name, std::string material_filepath){ +// getComponent<DrawComponent>()->addMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse.png"); +//} + +//void GameObject::addComps(){ +// addComponent<DrawComponent>(m_object); +// getComponent<DrawComponent>()->addMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse.png"); +//} + + diff --git a/engine-ocean/Game/GameObjects/GameObject.h b/engine-ocean/Game/GameObjects/GameObject.h new file mode 100644 index 0000000..a9ddbd7 --- /dev/null +++ b/engine-ocean/Game/GameObjects/GameObject.h @@ -0,0 +1,54 @@ +#ifndef GAMEOBJECT_H +#define GAMEOBJECT_H + + +#include "Game/Components/Component.h" +#include "Game/TypeMap.h" +#include <memory> +#include "Graphics/global.h" + +class GameObject +{ +public: + GameObject(); + ~GameObject(){ + std::cout << "deleting" << std::endl; + } + + template <typename T> + void addComponent(std::unique_ptr<T> &&component){ + m_components.put<T>(std::forward<std::unique_ptr<T>>(component)); + } + + template <typename T> + bool hasComponent(){ + return m_components.contains<T>(); + } + + template <class T> + T* getComponent(){ + auto comp = m_components.find<T>(); + assert(comp != m_components.end()); + return static_cast<T*>(comp->second.get()); + } + + template <class T> + void removeComponent(){ +// auto comp = m_components.find<T>(); +// assert(comp != m_components.end()); + m_components.remove<T>(); + } + + + +private: + void setPlayerPos(); + void makePlayer(); + + TypeMap<std::unique_ptr<Component>> m_components; + std::shared_ptr<Shape> m_object; + std::shared_ptr<ModelTransform> m_object_mt; + +}; + +#endif // GAMEOBJECT_H diff --git a/engine-ocean/Game/GameWorld.cpp b/engine-ocean/Game/GameWorld.cpp new file mode 100644 index 0000000..a274ea7 --- /dev/null +++ b/engine-ocean/Game/GameWorld.cpp @@ -0,0 +1,224 @@ +#include "GameWorld.h" +#include "Game/Environment/environmentsystem.h" +#include "Game/Systems/Inventory/inventorysystem.h" +#include "Game/Systems/Pathfinding/aimovementsystem.h" +#include "Game/Systems/camerasystem.h" +#include "Game/Systems/charactercontrollersystem.h" +#include "Game/Systems/CollisionSystems/collisionsystem.h" +#include "Game/Systems/drawsystem.h" +#include "Game/Systems/objectcreationsystem.h" +#include "Game/Systems/physicssystem.h" +#include "Game/Systems/UI/uisystem.h" + + + +GameWorld::GameWorld(std::map<int, Input>& input_map) : + camera(std::make_shared<Camera>()), + m_input_map(input_map) +{ + + glDisable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + m_game_object_names = std::vector<std::string>(); + initializeInputMap(); + + addSystem<ObjectCreationSystem>(std::make_shared<ObjectCreationSystem>(m_gameobjects, + m_dynamic_gameobjects, + m_rigid_gameobjects, + m_global_blackboard, + m_lootables)); + addSystem<DrawSystem>(std::make_shared<DrawSystem>(m_gameobjects)); + addSystem<PhysicsSystem>(std::make_shared<PhysicsSystem>(m_dynamic_gameobjects, m_global_blackboard, m_lootables)); + // addSystem<CharacterControllerSystem>(std::make_shared<CharacterControllerSystem>(m_gameobjects, camera, m_input_map, m_global_blackboard)); + +// addSystem<CollisionSystem>(std::make_shared<CollisionSystem>(m_gameobjects, +// m_dynamic_gameobjects, +// m_rigid_gameobjects, +// m_input_map, +// m_global_blackboard)); +// addSystem<AIMovementSystem>(std::make_shared<AIMovementSystem>(m_dynamic_gameobjects, +// m_rigid_gameobjects)); + addSystem<CameraSystem>(std::make_shared<CameraSystem>(m_gameobjects, camera, m_input_map)); + + + // seperate systems +// collisionSystem = std::make_shared<EnvironmentCollisionDetectionSystem>(m_dynamic_gameobjects, +// m_rigid_gameobjects, +// m_lootables, +// m_global_blackboard); + //environmentSystem = std::make_shared<EnvironmentSystem>(m_rigid_gameobjects, m_dynamic_gameobjects, camera); + + +} + + +void GameWorld::createKeyInput(int inputVal){ + Input input; + input.inputVal = inputVal; + m_input_map[inputVal] = input; +} + +void GameWorld::initializeInputMap(){ + createKeyInput(GLFW_KEY_W); + createKeyInput(GLFW_KEY_A); + createKeyInput(GLFW_KEY_S); + createKeyInput(GLFW_KEY_D); + createKeyInput(GLFW_KEY_SPACE); + createKeyInput(GLFW_KEY_P); + //createKeyInput(GLFW_KEY_R); + + Input mousePress; + mousePress.inputVal = GLFW_MOUSE_BUTTON_LEFT; + m_input_map[GLFW_MOUSE_BUTTON_LEFT] = mousePress; + + Input scrollWheel; + scrollWheel.inputVal = 1; + m_input_map[1] = scrollWheel; +} + +void GameWorld::mousePosEvent(double xpos, double ypos){ +// m_mousePos = glm::vec2(xpos, ypos); + if (m_mouseIsHeldTime <= 1 && m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){ + m_mouseIsHeldTime ++; + } + + if (m_mouseIsHeldTime > 1 && m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){ + m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld = true; + m_mouseIsHeldTime ++; + } + + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){ + + } + + for (auto &system : m_systems){ + system.second->mousePosEvent(xpos, ypos); + } + + +} + +void GameWorld::scrollEvent(double distance){ + for (auto &system : m_systems){ + system.second->scrollEvent(distance); + } +} + +void GameWorld::update(double deltaTime){ + for (auto &system : m_systems){ + system.second->update(deltaTime); + + // detect collision after everything + // collisionSystem->update(deltaTime); + } + + // environmentSystem->update(deltaTime); + + +} + +void GameWorld::draw(){ + + // then render normally + Global::graphics.setClearColor(glm::vec3(.77f, .85f, .99f)); + Global::graphics.clearScreen(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + Global::graphics.bindShader("phong"); + Global::graphics.setCameraData(camera); + + Global::graphics.setGlobalData(glm::vec3(.5f)); + Global::graphics.setClipPlane(glm::vec4(0, -1, 0, 100000)); + + for (auto &system : m_systems){ + system.second->draw(); + } + + //Global::graphics.setCameraData(camera); + //environmentSystem->draw(); + +} + + +void GameWorld::mouseButtonEvent(int button, int action){ + if (button == GLFW_MOUSE_BUTTON_LEFT){ + if (action == GLFW_RELEASE){ + if ( m_input_map[button].isActive && !m_input_map[button].isHeld){ + // we know that button was released after one click (not hold), thus a click was made + m_input_map[button].isClicked = true; + } + m_input_map[button].isActive = false; + m_input_map[button].isHeld = false; + m_mouseIsHeldTime = 0; + m_input_map[button].checkClickTime = 0; + return; + } + + if (action == GLFW_PRESS && !m_input_map[button].isHeld && !m_input_map[button].isActive){ + m_input_map[button].isActive = true; + return; + } + } +} + +void GameWorld::keyEvent(int key, int action){ + switch(key){ + case GLFW_KEY_W: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + case GLFW_KEY_A: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + case GLFW_KEY_S: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + case GLFW_KEY_D: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + case GLFW_KEY_SPACE: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + case GLFW_KEY_P: + if (action == GLFW_PRESS){ + m_input_map.at(key).isActive = true; + } + if (action == GLFW_RELEASE){ + m_input_map.at(key).isActive = false; + } + break; + default: + break; + } +} + +void GameWorld::framebufferResizeEvent(int width, int height){ + Global::graphics.setFramebufferSize(glm::ivec2(width, height)); +} + +void GameWorld::windowResizeEvent(int width, int height){ + Global::graphics.setWindowSize(glm::ivec2(width, height)); + camera->resize(Global::graphics.getWindowSize().x, Global::graphics.getWindowSize().y); +} diff --git a/engine-ocean/Game/GameWorld.h b/engine-ocean/Game/GameWorld.h new file mode 100644 index 0000000..8a99a9b --- /dev/null +++ b/engine-ocean/Game/GameWorld.h @@ -0,0 +1,132 @@ +#ifndef GameWorld_H +#define GameWorld_H +#include "Game/Environment/environmentsystem.h" +#include "Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h" +#include "Game/Systems/aisystem.h" +#include "Game/Systems/system.h" +#include "Graphics/global.h" +#include "Graphics/camera.h" +#include <GLFW/glfw3.h> +#include "screen.h" +#include <set> + +struct Input { + // key presses + int inputVal = 0; + + // mouse clicks + int xpos; + int ypos; + + // mouse scrolls + double distance; + + glm::vec3 translationDir = glm::vec3(0.f); + + bool isActive = false; + bool isHeld = false; + + bool isClicked = false; + int checkClickTime = 0; +}; + + +class GameWorld +{ +public: + GameWorld(std::map<int, Input>& input_map); + + + void update(double deltaTime); + void draw(); + void keyEvent(int key, int action); + void mousePosEvent(double xpos, double ypos); + void mouseButtonEvent(int button, int action); + void scrollEvent(double distance); + void windowResizeEvent(int width, int height); + void framebufferResizeEvent(int width, int height); + + + template <typename T> + void addSystem(std::shared_ptr<T> &&component){ + m_systems.put<T>(std::forward<std::shared_ptr<T>>(component)); + } + + + template <class T> + T* getSystem(){ + auto comp = m_systems.find<T>(); + assert(comp != m_systems.end()); + return static_cast<T*>(comp->second.get()); + } + + template <class T> + void removeSystem(){ + m_external_systems.remove<T>(); + } + + template <typename T> + void addExternalSystem(std::shared_ptr<T> &&component){ + m_external_systems.put<T>(std::forward<std::shared_ptr<T>>(component)); + } + + + template <class T> + T* getExternalSystem(){ + auto comp = m_external_systems.find<T>(); + assert(comp != m_external_systems.end()); + return static_cast<T*>(comp->second.get()); + } + + template <class T> + void removeExternalSystem(){ + m_external_systems.remove<T>(); + } + + + +private: +// GLuint VAO, VBO; +// GLuint grass_tex, wind_tex; +// std::vector<glm::vec3> positions; + + std::map<int, Input> m_input_map; + + void createKeyInput(int inputVal); + void initializeInputMap(); + void reset(); + + + void initializeGrassVBO(); + + TypeMap<std::shared_ptr<System>> m_systems; + TypeMap<std::shared_ptr<System>> m_external_systems; + + std::shared_ptr<Camera> camera; + + std::map<std::string, std::shared_ptr<GameObject>> m_gameobjects; + std::vector<std::string> m_game_object_names; + std::map<std::string, std::shared_ptr<GameObject>> m_dynamic_gameobjects; + std::vector<std::string> m_dynamic_game_object_names; + std::map<std::string, std::shared_ptr<GameObject>> m_rigid_gameobjects; + std::vector<std::string> m_rigid_game_object_names; + + + std::shared_ptr<EnvironmentCollisionDetectionSystem> collisionSystem; + std::shared_ptr<EnvironmentSystem> environmentSystem; + + + // map that contains submaps of each data type + std::map<std::string, BlackboardData> m_global_blackboard; + bool m_checkingMouseClick = false; + int m_mouseIsHeldTime = 0; + + glm::vec2 m_mousePos; + + std::map<std::string, std::vector<std::shared_ptr<GameObject>>> m_lootables; + std::set<std::string> m_shownScreens; + + +}; + +#endif // GameWorld_H diff --git a/engine-ocean/Game/GameplayScreen.cpp b/engine-ocean/Game/GameplayScreen.cpp new file mode 100644 index 0000000..6d7acd7 --- /dev/null +++ b/engine-ocean/Game/GameplayScreen.cpp @@ -0,0 +1,44 @@ +#include "GameplayScreen.h" + +GameplayScreen::GameplayScreen(std::map<int, Input>& input_map): + m_input_map(input_map), + game(GameWorld(input_map)) + +{ + //game = GameWorld(m_input_map); +} + + +void GameplayScreen::mousePosEvent(double xpos, double ypos){ + game.mousePosEvent(xpos, ypos); +} + +void GameplayScreen::mouseButtonEvent(int button, int action){ + game.mouseButtonEvent(button, action); +} + + +void GameplayScreen::scrollEvent(double distance){ + game.scrollEvent(distance); +} + + +void GameplayScreen::update(double deltaTime){ + game.update(deltaTime); +} + +void GameplayScreen::draw(){ + game.draw(); +} + +void GameplayScreen::keyEvent(int key, int action){ + game.keyEvent(key, action); +} + +void GameplayScreen::framebufferResizeEvent(int width, int height){ + game.framebufferResizeEvent(width, height); +} + +void GameplayScreen::windowResizeEvent(int width, int height){ + game.windowResizeEvent(width, height); +} diff --git a/engine-ocean/Game/GameplayScreen.h b/engine-ocean/Game/GameplayScreen.h new file mode 100644 index 0000000..d25d9ca --- /dev/null +++ b/engine-ocean/Game/GameplayScreen.h @@ -0,0 +1,34 @@ +#ifndef GAMEPLAYSCREEN_H +#define GAMEPLAYSCREEN_H +#include "Game/GameWorld.h" +#include "Graphics/global.h" +#include "Graphics/camera.h" +#include <GLFW/glfw3.h> +#include "screen.h" + + + +class GameplayScreen: public Screen +{ +public: + GameplayScreen(std::map<int, Input>& input_map); + + + void update(double deltaTime) override; + void draw() override; + void keyEvent(int key, int action) override; + void mousePosEvent(double xpos, double ypos) override; + void mouseButtonEvent(int button, int action) override; + void scrollEvent(double distance) override; + void windowResizeEvent(int width, int height) override; + void framebufferResizeEvent(int width, int height) override; + +private: + std::map<int, Input>& m_input_map; + + + + GameWorld game; +}; + +#endif // GAMEPLAYSCREEN_H diff --git a/engine-ocean/Game/MenuScreen.cpp b/engine-ocean/Game/MenuScreen.cpp new file mode 100644 index 0000000..dcf2f2e --- /dev/null +++ b/engine-ocean/Game/MenuScreen.cpp @@ -0,0 +1,59 @@ +#include "menuscreen.h" +#include "Game/GameWorld.h" +#include "Graphics/global.h" + +MenuScreen::MenuScreen(std::map<int, Input>& input_map): + m_input_map(input_map) +{ + +} + +MenuScreen::~MenuScreen(){ + +} + + +void MenuScreen::update(double deltaTime){ + + +} + +void MenuScreen::draw(){ + Global::graphics.setClearColor(glm::vec3(0.f)); + Global::graphics.clearScreen(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + Global::graphics.bindShader("text"); + Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Game Menu", glm::ivec2(200, 200), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 1.f, 0.1f, glm::vec3(1, 1, 1)); + Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Press 'B' to resume the game.", glm::ivec2(20, 70), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1)); + + +} + +void MenuScreen::keyEvent(int key, int action){ + +} + +void MenuScreen::mousePosEvent(double xpos, double ypos){ + + + +} + +void MenuScreen::mouseButtonEvent(int button, int action){ + + +} + +void MenuScreen::scrollEvent(double distance){ + + +} + +void MenuScreen::framebufferResizeEvent(int width, int height){ + Global::graphics.setFramebufferSize(glm::ivec2(width, height)); + +} + +void MenuScreen::windowResizeEvent(int width, int height){ + Global::graphics.setWindowSize(glm::ivec2(width, height)); + +} diff --git a/engine-ocean/Game/Ocean/ocean.cpp b/engine-ocean/Game/Ocean/ocean.cpp new file mode 100644 index 0000000..e8b88a8 --- /dev/null +++ b/engine-ocean/Game/Ocean/ocean.cpp @@ -0,0 +1,325 @@ +#include "ocean.h" +#include <iostream> +#include <Eigen/Dense> + +ocean::ocean() +{ + // to be used for efficiency during fft + init_wave_index_constants(); + +} + +// initializes static constants (aka they are not time dependent) +void ocean::init_wave_index_constants(){ + + for (int i=0; i<N; i++){ + Eigen::Vector2i m_n = index_1d_to_2d(i); + int n_prime = m_n[0]; + int m_prime = m_n[1]; + + Eigen::Vector2d k = get_k_vector(n_prime, m_prime); + Eigen::Vector2d k_conj = get_k_vector(-n_prime, m_prime); + + + // store h0'(n,m) and w'(n,m) for every index, to be used for later + Eigen::Vector2d h0_prime = h_0_prime(k); + + // conjugate of a+bi is a-bi + Eigen::Vector2d h0_prime_conj = h_0_prime(k_conj); + h0_prime_conj = Eigen::Vector2d(h0_prime_conj[0], -h0_prime_conj[1]); + + double w_prime = omega_prime(k); + + // populate map to be used for later + WaveIndexConstant wave_const; + wave_const.h0_prime = h0_prime; + wave_const.h0_prime_conj = h0_prime_conj; + wave_const.w_prime = w_prime; + wave_const.base_horiz_pos = get_horiz_pos(i); + wave_const.k_vector = k; + + m_waveIndexConstants[i] = wave_const; + + // initialize m_current_h to be h0 for now + m_current_h.push_back(h0_prime); + m_displacements.push_back(Eigen::Vector2d(0.0, 0.0)); + } +} + +std::vector<Eigen::Vector2d> ocean::fast_fft(std::vector<Eigen::Vector2d> h) +{ + int N = h.size(); + std::vector<Eigen::Vector2d> H = std::vector<Eigen::Vector2d>(N); + + if (N == 1) + { + H[0] = h[0]; + return H; + } + else + { + std::vector<Eigen::Vector2d> even = std::vector<Eigen::Vector2d>(N / 2); + std::vector<Eigen::Vector2d> odd = std::vector<Eigen::Vector2d>(N / 2); + + for (int i = 0; i < N / 2; i++) + { + even[i] = h[2 * i]; + odd[i] = h[2 * i + 1]; + } + + std::vector<Eigen::Vector2d> even_fft = fast_fft(even); + std::vector<Eigen::Vector2d> odd_fft = fast_fft(odd); + + for (int i = 0; i < N / 2; i++) + { + + Eigen::Vector2d k = m_waveIndexConstants[i].k_vector; + Eigen::Vector2d x = m_waveIndexConstants[i].base_horiz_pos; + + + double k_dot_xz = k.dot(x); + + Eigen::Vector2d omega = complex_exp(k_dot_xz); + Eigen::Vector2d omega_times_odd = Eigen::Vector2d(omega[0] * odd_fft[i][0] - omega[1] * odd_fft[i][1], omega[0] * odd_fft[i][1] + omega[1] * odd_fft[i][0]); + + H[i] = Eigen::Vector2d(even_fft[i][0] + omega_times_odd[0], even_fft[i][1] + omega_times_odd[1]); + H[i + N / 2] = Eigen::Vector2d(even_fft[i][0] - omega_times_odd[0], even_fft[i][1] - omega_times_odd[1]); + } + + return H; + } +} + +// fast fourier transform at time t +void ocean::fft_prime(double t){ + +// // NON FFT +// for (int i=0; i<N; i++){ +// Eigen::Vector2d h_t_prime = h_prime_t(i, t); // vector(real, imag) + +// m_current_h[i] = h_t_prime; +// } + +// return; + + // FFT + std::vector<Eigen::Vector2d> h_tildas = std::vector<Eigen::Vector2d>(); + + // find each h_tilda at each index, to be used for next for loop + for (int i=0; i<N; i++){ + Eigen::Vector2d h_t_prime = h_prime_t(i, t); // vector(real, imag) + + h_tildas.emplace_back(h_t_prime); + } + + // for each position in grid, sum up amplitudes dependng on that position + for (int i=0; i<N; i++){ + Eigen::Vector2d x_vector = m_waveIndexConstants[i].base_horiz_pos; + m_current_h[i] = Eigen::Vector2d(0.0, 0.0); + m_displacements[i] = Eigen::Vector2d(0.0, 0.0); + + + for (int j = 0; j < N; j++){ + Eigen::Vector2d k_vector = m_waveIndexConstants[j].k_vector; + Eigen::Vector2d h_tilda_prime = h_tildas[j]; // vector(real, imag) + + + // add x vector and k vector as imaginary numbers + double imag_xk_sum = x_vector.dot(k_vector); + Eigen::Vector2d exp = complex_exp(imag_xk_sum); // vector(real, imag) + + double real_comp = h_tilda_prime[0]*exp[0] - h_tilda_prime[1]*exp[1]; + double imag_comp = h_tilda_prime[0]*exp[1] + h_tilda_prime[1]*exp[0]; + + m_current_h[i] += Eigen::Vector2d(real_comp, imag_comp); + + Eigen::Vector2d k_normalized = k_vector.normalized(); + + m_displacements[i] += k_normalized*imag_comp; + + } + } + +} + +// time dependent calculation of h'(n,m,t) +Eigen::Vector2d ocean::h_prime_t(int i, double t){ + Eigen::Vector2d h0_prime = m_waveIndexConstants[i].h0_prime; // vector(real, imag) + Eigen::Vector2d h0_prime_conj = m_waveIndexConstants[i].h0_prime_conj; // vector(real, imag) + double w_prime = m_waveIndexConstants[i].w_prime; + + Eigen::Vector2d pos_complex_exp = complex_exp(w_prime*t); // vector(real, imag) + Eigen::Vector2d neg_complex_exp = complex_exp(-w_prime*t); // vector(real, imag) + + // now multiply our four vector(real, imag) out + + double real_comp = + h0_prime[0]*pos_complex_exp[0] + - h0_prime[1]*pos_complex_exp[1] + + h0_prime_conj[0]*neg_complex_exp[0] + + h0_prime_conj[1]*neg_complex_exp[1]; + + double imag_comp = + h0_prime[0]*pos_complex_exp[1] + + h0_prime[1]*pos_complex_exp[0] + + h0_prime_conj[0]*neg_complex_exp[1] + - h0_prime_conj[1]*neg_complex_exp[0]; + + + + return Eigen::Vector2d(real_comp, imag_comp); +} + +double ocean::omega_prime(Eigen::Vector2d k){ + // calculate omega^4 first to prevent sqrts + double w = sqrt(gravity*k.norm()); + + return w; +} + +Eigen::Vector2d ocean::h_0_prime(Eigen::Vector2d k){ + double Ph_prime = phillips_prime(k); + std::pair<double,double> randoms = sample_complex_gaussian(); + double random_r = randoms.first; + double random_i = randoms.second; + + // seperate real and imag products + double coeff = 0.707106781187 * sqrt(Ph_prime); + double real_comp = coeff*random_r; + double imag_comp = coeff*random_i; + + return Eigen::Vector2d(real_comp, imag_comp); +} + + +double ocean::phillips_prime(Eigen::Vector2d k){ + double k_mag = k.norm(); + + k.normalize(); + double dot_prod = k.dot(omega_wind); + + double output = 0.0; + // l = 1 + if (k_mag < .0001) return 0.0; + + if (k_mag > 1.0){ + + output = A*exp(-(k_mag*k_mag))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag); + } else { + output = A*exp(-1.0/(k_mag*L*k_mag*L))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag); + + } + + + + return output; +} + +Eigen::Vector2d ocean::get_k_vector(int n_prime, int m_prime){ + double n_ = (double)n_prime; + double m_ = (double)m_prime; + double N_ = (double)num_rows; + double M_ = (double)num_cols; + + double k_x = (2.0*M_PI*n_ - M_PI*N_)/Lx; + double k_z = (2.0*M_PI*m_ - M_PI*M_)/Lz; + + return Eigen::Vector2d(k_x, k_z); +} + +Eigen::Vector2d ocean::get_horiz_pos(int i){ + Eigen::Vector2i m_n = index_1d_to_2d(i); + double n_prime = (double)m_n[0]; + double m_prime = (double)m_n[1]; + double N_ = (double)num_rows; + double M_ = (double)num_cols; + + + double x = (n_prime-.5*N_)*Lx / N_; + double z = (m_prime-.5*M_)*Lz / M_; + + + + return Eigen::Vector2d(x, z); +} + + +Eigen::Vector2i ocean::index_1d_to_2d(int i){ + int row = i/num_rows; // n' + int col = i%num_rows; // m' + + return Eigen::Vector2i(row, col); + +} + +std::pair<double,double> ocean::sample_complex_gaussian(){ + double uniform_1 = (double)rand() / (RAND_MAX); + double uniform_2 = (double)rand() / (RAND_MAX); + + // set a lower bound on zero to avoid undefined log(0) + if (uniform_1 == 0) + { + uniform_1 = 1e-10; + } + if (uniform_2 == 0) + { + uniform_2 = 1e-10; + } + + // real and imaginary parts of the complex number + double real = sqrt(-2 * log(uniform_1)) * cos(2 * M_PI * uniform_2); + double imag = sqrt(-2 * log(uniform_1)) * sin(2 * M_PI * uniform_2); + + return std::make_pair(real, imag); +} + +Eigen::Vector2d ocean::complex_exp(double exponent){ + double real = cos(exponent); + double imag = sin(exponent); + + return Eigen::Vector2d(real, imag); +} + +std::vector<Eigen::Vector3f> ocean::get_vertices() +{ + std::vector<Eigen::Vector3f> vertices = std::vector<Eigen::Vector3f>(); + for (int i = 0; i < N; i++){ + Eigen::Vector2d horiz_pos = spacing*m_waveIndexConstants[i].base_horiz_pos; + Eigen::Vector2d amplitude = m_current_h[i]; + + + // calculate displacement + Eigen::Vector2d disp = lambda*m_displacements[i]; + + + // for final vertex position, use the real number component of amplitude vector + vertices.push_back(Eigen::Vector3f(horiz_pos[0] + disp[0], amplitude[0], horiz_pos[1] + disp[1])); + } + return vertices; +} + +std::vector<Eigen::Vector3i> ocean::get_faces() +{ + // connect the vertices into faces + std::vector<Eigen::Vector3i> faces = std::vector<Eigen::Vector3i>(); + for (int i = 0; i < N; i++) + { + int x = i / num_rows; + int z = i % num_rows; + + // connect the vertices into faces + if (x < num_rows - 1 && z < num_cols - 1) + { + int i1 = i; + int i2 = i + 1; + int i3 = i + num_rows; + int i4 = i + num_rows + 1; + +// faces.emplace_back(i2, i1, i3); +// faces.emplace_back(i2, i3, i4); + faces.emplace_back(i1, i2, i3); + faces.emplace_back(i3, i2, i4); + } + } + return faces; +} diff --git a/engine-ocean/Game/Ocean/ocean.h b/engine-ocean/Game/Ocean/ocean.h new file mode 100644 index 0000000..b2abe87 --- /dev/null +++ b/engine-ocean/Game/Ocean/ocean.h @@ -0,0 +1,89 @@ +#ifndef ocean_H +#define ocean_H + +#include <map> +#include <vector> +#include <utility> +#include <Eigen/Dense> + +// for every 1d index up to length*width +struct WaveIndexConstant{ + Eigen::Vector2d h0_prime = Eigen::Vector2d(0.f, 0.f); + Eigen::Vector2d h0_prime_conj = Eigen::Vector2d(0.f, 0.f); + + double w_prime = 0.0; + + + Eigen::Vector2d base_horiz_pos = Eigen::Vector2d(0.f, 0.f); // static horiz pos with no displacement + Eigen::Vector2d k_vector = Eigen::Vector2d(0.f, 0.f); // static horiz pos with no displacement + + + +}; + +class ocean +{ +public: + ocean(); + void updateVertexAmplitudes(double t); + std::vector<Eigen::Vector3f> get_vertices(); + std::vector<Eigen::Vector3i> get_faces(); + void fft_prime(double t); + + + + + +private: + + Eigen::Vector2i index_1d_to_2d(int i); + Eigen::Vector2d get_k_vector(int n_prime, int m_prime); + double phillips_prime(Eigen::Vector2d k); + Eigen::Vector2d h_0_prime(Eigen::Vector2d k); + double omega_prime(Eigen::Vector2d k); + void init_wave_index_constants(); + Eigen::Vector2d complex_exp(double exponent); + Eigen::Vector2d h_prime_t(int i, double t); + Eigen::Vector2d get_horiz_pos(int i); + std::pair<double, double> sample_complex_gaussian(); + std::vector<Eigen::Vector2d> fast_fft(std::vector<Eigen::Vector2d> h); + + + + + + + + + + std::map<int, WaveIndexConstant> m_waveIndexConstants; // stores constants that only need to be calculate once for each grid constant + + + + const double Lx = 10.0; + const double Lz = 10.0; + + const int num_rows = 8; + const int num_cols = 8; + + const int N = num_rows*num_cols; // total number of grid points + const double lambda = .40; // how much displacement matters + const double spacing = 35.0; // spacing between grid points + + const double A = 1.0; // numeric constant for the Phillips spectrum + const double V = 5.5; // wind speed + const double gravity = 9.81; + const double L = V*V/gravity; + const Eigen::Vector2d omega_wind = Eigen::Vector2d(1.0, 0.0); // wind direction, used in Phillips equation + + std::vector<Eigen::Vector2d> m_current_h; // current height fields for each K + std::vector<Eigen::Vector2d> m_displacements; // current displacement vector for each K + + + + const double D = 1.0; // Depth below mean water level (for dispersion relation) + + +}; + +#endif // ocean_H diff --git a/engine-ocean/Game/Systems/AI/Actions/btaction.cpp b/engine-ocean/Game/Systems/AI/Actions/btaction.cpp new file mode 100644 index 0000000..1b35340 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Actions/btaction.cpp @@ -0,0 +1,6 @@ +#include "btaction.h" + +BTAction::BTAction() +{ + +} diff --git a/engine-ocean/Game/Systems/AI/Actions/btaction.h b/engine-ocean/Game/Systems/AI/Actions/btaction.h new file mode 100644 index 0000000..180f72c --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Actions/btaction.h @@ -0,0 +1,17 @@ +#ifndef BTACTION_H +#define BTACTION_H +#include "Game/Systems/AI/btnode.h" + +class BTAction : public BTNode +{ +public: + BTAction(); + virtual Status update(float seconds) = 0; + virtual void reset() = 0; + +private: + Status m_status; + +}; + +#endif // BTACTION_H diff --git a/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp b/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp new file mode 100644 index 0000000..6a6d116 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp @@ -0,0 +1,90 @@ +#include "walkaction.h" +#include "Game/Components/PathfindComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include "glm/glm.hpp" +#include <memory> + + +WalkAction::WalkAction(std::string entity_id, + std::map<std::string, BlackboardData>& global_blackboard): + m_global_blackboard(global_blackboard) +{ + + m_entity_id = entity_id; + m_path.clear(); + + m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false; + m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue = false; + m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue = false; + + + + +} + +void WalkAction::setPath(glm::vec3 entity_pos){ + std::cout << "---------SETTING PATHH" << std::endl; + m_destination = m_global_blackboard["player"].locationData.currPos; + m_path = m_global_blackboard["navmesh"].environment->getComponent<PathfindComponent>()->getPath(glm::vec3(-0.58249, 0, -0.0210782), glm::vec3(19.5371, 0, 1.39167)); +} + +// only activates if the previous conditions are true +Status WalkAction::update(float seconds){ + + glm::vec3 pos = m_global_blackboard[m_entity_id].locationData.currPos; + + // get a path if entity is not pathfinding + if (!m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue && + !m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue && + !m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue){ + setPath(pos); + m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = true; + m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue = true; + + } + + if (!m_path.empty()){ + if (m_global_blackboard[m_entity_id].conditionData["onGround"].conditionTrue){ + //std::cout << "on ground" << std::endl; + + std::shared_ptr<ModelTransform> temp_mt = std::make_shared<ModelTransform>(); + temp_mt->setPos(pos); + glm::vec3 v = m_path.back();//glm::vec3(m_path.back().x, pos.y, m_path.back().z); + glm::vec3 dir = glm::normalize(v-temp_mt->getPos()); + temp_mt->translate(dir); + //std::cout << "v: (" << v.x << ", " << v.y << ", " << v.z << ")" << std::endl; + glm::vec3 pos_eps = v + .01f; + glm::vec3 neg_eps = v - .01f; + + // pop if entity within a certain episilon of node + if (neg_eps.x < temp_mt->getPos().x < pos_eps.x && + neg_eps.z < temp_mt->getPos().z < pos_eps.z){ + m_path.pop_back(); + } + + m_global_blackboard[m_entity_id].locationData.setToPos = temp_mt->getPos(); + } + + return Status::RUNNING; + } + + // if reached destination, then walking succeeded + if (pos.x == m_destination.x && pos.z == m_destination.z){ + m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false; + m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue = true; + std::cout << "-reached-" << std::endl; + return Status::SUCCESS; + + } + + // otherwise + m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false; + return Status::FAIL; + +} + +void WalkAction::reset(){} +void WalkAction::addChildren(BTNode *node){} + + diff --git a/engine-ocean/Game/Systems/AI/Actions/walkaction.h b/engine-ocean/Game/Systems/AI/Actions/walkaction.h new file mode 100644 index 0000000..2e24864 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Actions/walkaction.h @@ -0,0 +1,29 @@ +#ifndef WALKACTION_H +#define WALKACTION_H +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/Systems/AI/btnode.h" +#include "glm/fwd.hpp" +#include <memory> +#include "btaction.h" + +class WalkAction : public BTNode +{ +public: + WalkAction(std::string entity_id, std::map<std::string, BlackboardData>& global_blackboard); + Status update(float seconds) override; + void reset() override; + void setPath(glm::vec3 entity_pos); + void addChildren(BTNode *node) override; + + + +private: + std::vector<glm::vec3> m_path; + glm::vec3 m_destination; + std::map<std::string, BlackboardData>& m_global_blackboard; + std::string m_entity_id; +}; + + +#endif // WALKACTION_H diff --git a/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp b/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp new file mode 100644 index 0000000..f4de4af --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp @@ -0,0 +1,6 @@ +#include "btcondition.h" + +BTCondition::BTCondition() +{ + +} diff --git a/engine-ocean/Game/Systems/AI/Conditions/btcondition.h b/engine-ocean/Game/Systems/AI/Conditions/btcondition.h new file mode 100644 index 0000000..6ded57b --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Conditions/btcondition.h @@ -0,0 +1,18 @@ +#ifndef BTCONDITION_H +#define BTCONDITION_H +#include "Game/Systems/AI/btnode.h" + + +class BTCondition : public BTNode +{ +public: + BTCondition(); + virtual Status update(float seconds) = 0; + virtual void reset() = 0; + + +private: + bool m_condition; +}; + +#endif // BTCONDITION_H diff --git a/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp new file mode 100644 index 0000000..2e40ce7 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp @@ -0,0 +1,43 @@ +#include "proximitycondition.h" +#include "Game/Components/TransformComponent.h" +#include "glm/glm.hpp" +#include <memory> + +ProximityCondition::ProximityCondition(std::string entity_id, + std::map<std::string, BlackboardData>& global_blackboard, + float proximity): + m_global_blackboard(global_blackboard) +{ + m_proximity = proximity; + m_entity_id = entity_id; + // initialize just in case + m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = false; + + +} + +// maybe can check locations from blackboard +// pass blackboard into constructor +// struct: positiondata --> getCurrentPos, setCurrentPos +bool ProximityCondition::checkProximity(){ + // unrooted distance + glm::vec3 aiPos = m_global_blackboard[m_entity_id].locationData.currPos; + glm::vec3 otherPos = m_global_blackboard["player"].locationData.currPos; + float distance = pow(aiPos.x-otherPos.x, 2) + pow(aiPos.y-otherPos.y, 2) + pow(aiPos.z-otherPos.z, 2); + + if (distance <= m_proximity) return true; + return false; +} + +// at every update, check if AIPos is near otherPos +Status ProximityCondition::update(float seconds){ + // while entity is still pathfinding, keep returning success + if (m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue) return Status::SUCCESS; + if (checkProximity() && m_global_blackboard["player"].conditionData["isJumping"].conditionTrue) return Status::SUCCESS; + + return Status::FAIL; +} + + +void ProximityCondition::reset(){} +void ProximityCondition::addChildren(BTNode *node){} diff --git a/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h new file mode 100644 index 0000000..e43d178 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h @@ -0,0 +1,27 @@ +#ifndef PROXIMITYCONDITION_H +#define PROXIMITYCONDITION_H +#include "Game/Components/TransformComponent.h" +#include "btcondition.h" +#include <memory> + + +class ProximityCondition : public BTNode +{ +public: + ProximityCondition(std::string entity_id, + std::map<std::string, BlackboardData>& global_blackboard, + float proximity); + Status update(float seconds) override; + void reset() override; + void addChildren(BTNode *node) override; + + +private: + bool checkProximity(); + float m_proximity; + std::string m_entity_id; + std::map<std::string, BlackboardData>& m_global_blackboard; + +}; + +#endif // PROXIMITYCONDITION_H diff --git a/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp new file mode 100644 index 0000000..b43ed07 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp @@ -0,0 +1,46 @@ +#include "aibehaviorcomponent.h" +#include "Game/Systems/AI/Actions/walkaction.h" +#include "Game/Systems/AI/Conditions/proximitycondition.h" +#include "Game/Systems/AI/btselector.h" +#include "Game/Systems/AI/btsequence.h" + +AIBehaviorComponent::AIBehaviorComponent(std::string entity_id, + std::map<std::string, BlackboardData>& global_blackboard): + m_global_blackboard(global_blackboard) +{ + m_entity_id = entity_id; + makeBehaviorTree(); + +} + +void AIBehaviorComponent::makeBehaviorTree(){ + // leaves + //std::unique_ptr<BTNode> walk = std::make_unique<WalkAction>(m_entity_id, m_global_blackboard); + BTNode *proximCond = new ProximityCondition(m_entity_id, m_global_blackboard, 20.f); + BTNode *walk = new WalkAction(m_entity_id, m_global_blackboard); + + +// // pathfind sequence + BTNode *pathfindSeq = new BTSequence; + pathfindSeq->addChildren(proximCond); + pathfindSeq->addChildren(walk); + +// // idle sequence + +// // root + m_root = new BTSelector; + m_root->addChildren(pathfindSeq); +} + +// how might i be able to generalize the creation of the tree? +void AIBehaviorComponent::update(float seconds){ + // update root, which updates all its children + //std::cout << "---------in ai system" << std::endl; + + m_status = m_root->update(seconds); +} + +AIBehaviorComponent::~AIBehaviorComponent(){ + delete m_root; +} + diff --git a/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h new file mode 100644 index 0000000..5a86b88 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h @@ -0,0 +1,27 @@ +#ifndef AIBEHAVIORCOMPONENT_H +#define AIBEHAVIORCOMPONENT_H + + +#include "Game/Components/Component.h" +#include "Game/Systems/AI/btselector.h" +#include "Game/Systems/aisystem.h" +#include <map> +#include <string> +class AIBehaviorComponent : public Component +{ +public: + AIBehaviorComponent(std::string entity_id, + std::map<std::string, BlackboardData>& global_blackboard); + ~AIBehaviorComponent(); + void update(float seconds); + +private: + void makeBehaviorTree(); + + std::string m_entity_id; + std::map<std::string, BlackboardData>& m_global_blackboard; + BTNode *m_root = 0; + Status m_status = Status::SUCCESS; +}; + +#endif // AIBEHAVIORCOMPONENT_H diff --git a/engine-ocean/Game/Systems/AI/btnode.cpp b/engine-ocean/Game/Systems/AI/btnode.cpp new file mode 100644 index 0000000..2740089 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btnode.cpp @@ -0,0 +1,6 @@ +#include "btnode.h" + +BTNode::BTNode() +{ + +} diff --git a/engine-ocean/Game/Systems/AI/btnode.h b/engine-ocean/Game/Systems/AI/btnode.h new file mode 100644 index 0000000..b025da6 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btnode.h @@ -0,0 +1,18 @@ +#ifndef BTNODE_H +#define BTNODE_H + + +enum Status{ + SUCCESS, FAIL, RUNNING +}; + +class BTNode +{ +public: + BTNode(); + virtual ~BTNode() = default; + virtual Status update(float seconds) = 0; + virtual void reset() = 0; + virtual void addChildren(BTNode *node) = 0; +}; +#endif // BTNODE_H diff --git a/engine-ocean/Game/Systems/AI/btselector.cpp b/engine-ocean/Game/Systems/AI/btselector.cpp new file mode 100644 index 0000000..9652838 --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btselector.cpp @@ -0,0 +1,29 @@ +#include "btselector.h" +#include <iostream> + +BTSelector::BTSelector() +{ + +} + +void BTSelector::addChildren(BTNode* node){ + m_children.push_back(node); +} + +Status BTSelector::update(float seconds){ + // update each children until one doesnt fail + for (auto node : m_children){ + Status result = node->update(seconds); + + // select this one and return its status --> this node is currently running + if (result != Status::FAIL){ + m_selected_node = node; + return result; + } + } + + // otherwise if all children fail, then fail this selector + return Status::FAIL; +} + +void BTSelector::reset(){} diff --git a/engine-ocean/Game/Systems/AI/btselector.h b/engine-ocean/Game/Systems/AI/btselector.h new file mode 100644 index 0000000..20058ac --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btselector.h @@ -0,0 +1,21 @@ +#ifndef BTSELECTOR_H +#define BTSELECTOR_H +#include "Game/Systems/AI/btnode.h" +#include <vector> + + +class BTSelector : public BTNode +{ +public: + BTSelector(); + Status update(float seconds) override; + void reset() override; + void addChildren(BTNode *node) override; + + +private: + std::vector<BTNode *> m_children; + BTNode *m_selected_node; +}; + +#endif // BTSELECTOR_H diff --git a/engine-ocean/Game/Systems/AI/btsequence.cpp b/engine-ocean/Game/Systems/AI/btsequence.cpp new file mode 100644 index 0000000..ba6169d --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btsequence.cpp @@ -0,0 +1,30 @@ +#include "btsequence.h" +#include <vector> + +BTSequence::BTSequence() +{ + +} + +void BTSequence::addChildren(BTNode *node){ + m_sequence.push_back(node); +} + +Status BTSequence::update(float seconds){ + + for (auto node : m_sequence){ + if (node->update(seconds) == Status::FAIL){ + return Status::RUNNING; + } + // if come across any node that fails + if (node->update(seconds) == Status::FAIL){ + return Status::FAIL; + } + } + + // if no node is fail or running, sequence is completed + return Status::SUCCESS; +} + +void BTSequence::reset(){} + diff --git a/engine-ocean/Game/Systems/AI/btsequence.h b/engine-ocean/Game/Systems/AI/btsequence.h new file mode 100644 index 0000000..5ff230c --- /dev/null +++ b/engine-ocean/Game/Systems/AI/btsequence.h @@ -0,0 +1,20 @@ +#ifndef BTSEQUENCE_H +#define BTSEQUENCE_H +#include "btnode.h" +#include <vector> + + +class BTSequence : public BTNode +{ +public: + BTSequence(); + Status update(float seconds) override; + void reset() override; + void addChildren(BTNode* node) override; + + +private: + std::vector<BTNode *> m_sequence; +}; + +#endif // BTSEQUENCE_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp new file mode 100644 index 0000000..46155bc --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp @@ -0,0 +1,234 @@ +#include "bvhtree.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/boundingtriangle.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include <map> + +BVHTree::BVHTree(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) : + m_rigid_gameobjects(rigid_gameobjects) +{ + initializePrimitiveInfo(); + buildBVH(); + BVHNode one = m_bvhNodes[0]; + BVHNode two = m_bvhNodes[1]; + BVHNode three = m_bvhNodes[2]; + + + std::cout << "primitives size: " << m_primitives.size() << std::endl; +} + +// populate primitive info vector -> primitives = triangles +void BVHTree::initializePrimitiveInfo(){ + for (const auto &go : m_rigid_gameobjects){ + N += go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getTriangleData().size(); + for (const Triangle &tri : go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getTriangleData()){ + // the order might not be accurate.... + BVHPrimitive prim = {tri}; + //std::cout << "centroid: (" << prim.centroid.x << ", " << prim.centroid.y << ", " << prim.centroid.z << ")" << std::endl; + + m_primitives.push_back(prim); + + } + } +} + +void BVHTree::buildBVH(){ + // initialize array of primitive indices + m_primitive_indices = new int[N]; + for (int i=0; i<N; i++){ + m_primitive_indices[i] = i; + } + + m_bvhNodes = new BVHNode[N*2 - 1]; + int rootNodeID = 0; + m_nodesUsed = 1; + + // assign all primitives to root node + BVHNode& root = m_bvhNodes[0]; + root.leftNode = 0; + root.firstPrimitiveIndex = 0; + root.primitiveCount = N; + + updateNodeBounds(rootNodeID); + // subdivide recursively + subdivide(rootNodeID); +} + +void BVHTree::updateNodeBounds(int nodeIndex){ + BVHNode& node = m_bvhNodes[nodeIndex]; + node.bounds.max = glm::vec3(-INFINITY); + node.bounds.min = glm::vec3(INFINITY); + + for (int first = node.firstPrimitiveIndex, i=0; i<node.primitiveCount; i++){ + int leafIndex = m_primitive_indices[first + i]; + BVHPrimitive& leafPrimitive = m_primitives[leafIndex]; + // update node bounds with the most max and most min coordinates + node.bounds = getNodeBounds<Bounds3f>(node.bounds, leafPrimitive.bounds); + } +} + +void BVHTree::subdivide(int nodeIndex){ + BVHNode& node = m_bvhNodes[nodeIndex]; + // terminate recursion + + + if (node.primitiveCount <= 1) return; + + // otherwise determine split axis and position +// // SAHH HEREEEEE +// int bestAxis = 0; +// float bestPos = 0; +// float bestCost = INFINITY; +// for (int axis=0; axis<3; axis++){ +// for (int i=0; i<node.primitiveCount; i++){ +// BVHPrimitive& primitive = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]]; +// float candidatePos = primitive.centroid[axis]; +// float cost = evaluateSAH(node, axis, candidatePos); +// if (cost < bestCost){ +// bestPos = candidatePos; +// bestAxis = axis; +// bestCost = cost; +// } + +// } +// } + +// int axis = bestAxis; +// float splitPos = bestPos; + +// glm::vec3 e = node.bounds.max - node.bounds.min; +// float parentArea = (e.x*e.y) + (e.y*e.z) * (e.z*e.x); +// float parentCost = node.primitiveCount*parentArea; +// if (bestCost >= parentCost) return; + + // longest axis split (temporary) + glm::vec3 extent = node.bounds.max - node.bounds.min; + int axis = 0; // initialize to be x axis + if (extent.y > extent.x) axis = 1; + if (extent.z > extent[axis]) axis = 2; + float splitPos = node.bounds.min[axis] + extent[axis] * 0.5f; + + // in-place partition + int i = node.firstPrimitiveIndex; + int j = i + node.primitiveCount - 1; + while (i <= j){ + // if to the left of split axis + if (m_primitives[m_primitive_indices[i]].centroid[axis] < splitPos){ + i++; + } else { + std::swap(m_primitive_indices[i], m_primitive_indices[j--]); + } + } + + // abort split if one of the sides is empty + int leftCount = i - node.firstPrimitiveIndex; + if (leftCount == 0 || leftCount == node.primitiveCount) return; + + // create child nodes + int leftChildID = m_nodesUsed++; + int rightChildID = m_nodesUsed++; + + // left child + m_bvhNodes[leftChildID].firstPrimitiveIndex = node.firstPrimitiveIndex; + m_bvhNodes[leftChildID].primitiveCount = leftCount; + + // right child + m_bvhNodes[rightChildID].firstPrimitiveIndex = i; + m_bvhNodes[rightChildID].primitiveCount = node.primitiveCount - leftCount; + + node.leftNode = leftChildID; + node.primitiveCount = 0; + + // recurse + updateNodeBounds(leftChildID); + updateNodeBounds(rightChildID); + subdivide(leftChildID); + subdivide(rightChildID); +} + +float BVHTree::evaluateSAH(BVHNode& node, int axis, float pos){ + BVHaabb leftBox, rightBox; + leftBox.bounds.min = glm::vec3(INFINITY), rightBox.bounds.min = glm::vec3(INFINITY); + leftBox.bounds.max = glm::vec3(-INFINITY), rightBox.bounds.max = glm::vec3(-INFINITY); + + int leftCount = 0, rightCount = 0; + for (int i=0; i<node.primitiveCount; i++){ + BVHPrimitive& primitive = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]]; + if (primitive.centroid[axis] < pos){ + leftCount++; + leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexA)); + leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexB)); + leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexC)); + } else { + rightCount++; + rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexA)); + rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexB)); + rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexC)); + } + } + float cost = leftCount * leftBox.area() + rightCount * rightBox.area(); + return cost > 0 ? cost : INFINITY; +} + + +void BVHTree::intersectBVH(const glm::vec3 posA, const glm::vec3 posB, const int nodeIndex, std::vector<Triangle> &candidates, glm::vec3 ellip_R){ + //std::cout << "-" << std::endl; + + BVHNode& node = m_bvhNodes[nodeIndex]; + if (!intersectsNode(posA, posB, node.bounds.min, node.bounds.max, ellip_R+glm::vec3(.001))){ + return; + } + if (node.isLeaf()){ + // intersect with primitives of the leaf + //std::cout << "candidate size: " << node.primitiveCount << std::endl; + for (int i=0; i<node.primitiveCount; i++){ + Triangle triangle = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]].triangle; +// BVHPrimitive prim = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]]; + +// if (prim.centroid == glm::vec3(39.42457, 1.84954, -15.7088)){ +// std::cout << "found correct triangle" << std::endl; +// } + //std::cout << "centroid: (" << prim.centroid.x << ", " << prim.centroid.y << ", " << prim.centroid.z << ")" << std::endl; + candidates.push_back(triangle); + + } + } else { + // recurse + intersectBVH(posA, posB, node.leftNode, candidates, ellip_R); + intersectBVH(posA, posB, node.leftNode + 1, candidates, ellip_R); + } +} + +std::vector<Triangle> BVHTree::getBVHDetectedCollisions(glm::vec3 posA, glm::vec3 posB, glm::vec3 ellip_R){ + // keep recursing, starting at root node, and then return final result in candidate_obstacles + std::vector<Triangle> candidate_rigid_tri; + intersectBVH(posA, posB, 0, candidate_rigid_tri, ellip_R); + return candidate_rigid_tri; +} + +// determines if movement ray intersects an AABB via the slab test +bool BVHTree::intersectsNode(glm::vec3 posA, glm::vec3 posB, glm::vec3 min, glm::vec3 max, glm::vec3 ellip_R){ + glm::vec3 object_min = glm::vec3(std::min(posA.x, posB.x), std::min(posA.y, posB.y), std::min(posA.z, posB.z)); + glm::vec3 object_max = glm::vec3(std::max(posA.x, posB.x), std::max(posA.y, posB.y), std::max(posA.z, posB.z)); + object_min -= ellip_R; + object_max += ellip_R; + + bool x_int = object_max.x > min.x && object_min.x < max.x; + bool y_int = object_max.y > min.y && object_min.y < max.y; + bool z_int = object_max.z > min.z && object_min.z < max.z; + + if (x_int && y_int && z_int){ + return true; + } + return false; +} + +BVHTree::~BVHTree(){ + delete[] m_bvhNodes; + delete[] m_primitive_indices; + m_bvhNodes = NULL; + m_primitive_indices = NULL; + +} + diff --git a/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h new file mode 100644 index 0000000..b175e44 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h @@ -0,0 +1,106 @@ +#ifndef BVHTREE_H +#define BVHTREE_H +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/GameObjects/GameObject.h" +#include "glm/glm.hpp" +#include <map> +#include <vector> + +// primitive = triangle +struct BVHPrimitive{ + + Bounds3f bounds; + glm::vec3 centroid; + Triangle triangle; + + BVHPrimitive(const Triangle &tri): + triangle(tri), + bounds(tri.bounds), + centroid(.333f*(tri.vertexA + tri.vertexB + tri.vertexC)){} +}; + +struct BVHNode{ + // glm::vec3 aabbMin, aabbMax; + Bounds3f bounds; + int leftNode, firstPrimitiveIndex, primitiveCount; + bool isLeaf(){ + return primitiveCount > 0; + } +}; + +struct BVHaabb { + Bounds3f bounds; + + + void grow(Bounds3f newbounds){ + bounds.min = newbounds.min; + bounds.max = newbounds.max; + } + + float area(){ + glm::vec3 e = bounds.max-bounds.min; + return (e.x*e.y) + (e.y*e.z) * (e.z*e.x); + } +}; + + +template <typename T> Bounds3f +getNodeBounds(const Bounds3f &b1, const Bounds3f &b2){ + Bounds3f bounds; + bounds.min = glm::vec3(std::min(b1.min.x, b2.min.x), + std::min(b1.min.y, b2.min.y), + std::min(b1.min.z, b2.min.z)); + bounds.max = glm::vec3(std::max(b1.max.x, b2.max.x), + std::max(b1.max.y, b2.max.y), + std::max(b1.max.z, b2.max.z)); + return bounds; +} + +template <typename T> Bounds3f +getNodeBounds_Point(const Bounds3f &b, const glm::vec3 &p){ + Bounds3f bounds; + bounds.min = glm::vec3(std::min(b.min.x, p.x), + std::min(b.min.y, p.y), + std::min(b.min.z, p.z)); + bounds.max = glm::vec3(std::max(b.max.x, p.x), + std::max(b.max.y, p.y), + std::max(b.max.z, p.z)); + return bounds; +} + +class BVHTree + +{ + BVHNode *m_bvhNodes; + int *m_primitive_indices; +public: + BVHTree(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects); + ~BVHTree(); + std::vector<Triangle> getBVHDetectedCollisions(glm::vec3 posA, glm::vec3 posB, glm::vec3 ellip_R); + void intersectBVH(glm::vec3 posA, glm::vec3 posB, const int nodeIndex, std::vector<Triangle> &candidates, glm::vec3 ellip_R); + + +private: + float evaluateSAH(BVHNode& node, int axis, float pos); + void initializePrimitiveInfo(); + void buildBVH(); + void updateNodeBounds(int nodeIndex); + void subdivide(int nodeIndex); + bool intersectsNode(glm::vec3 posA, glm::vec3 posB, glm::vec3 min, glm::vec3 max, glm::vec3 ellip_R); + + + //std::unique_ptr<EllipsoidTriangleCollisionSystem> m_ellipsoid_triangle_collision_system; + + std::vector<BVHPrimitive> m_primitives; + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + + + //std::vector<BVHNode> m_bvhNodes; + //std::vector<int> m_primitive_indices; + int m_nodesUsed = 1; + int N = 0; + + // std::pair<std::vector<CollisionData>, glm::vec3> m_detected_collisions; +}; + +#endif // BVHTREE_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp new file mode 100644 index 0000000..822129b --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp @@ -0,0 +1,127 @@ +#include "uniformgrid.h" +#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include <algorithm> + +UniformGrid::UniformGrid(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects): + m_dynamic_gameobjects(dynamic_gameobjects) +{ + initializeGrid(); +} + +void UniformGrid::initializeGrid(){ + // grid square: size it based on the largest entity + + // set default square size to be same dimensions as player + m_square_dimensions = ceil(m_dynamic_gameobjects.at("player")->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions); + + + // find largest shape dimension in order to set grid square dimensions + for (const auto &go : m_dynamic_gameobjects){ + if (go.second->hasComponent<CollisionComponent>()){ + glm::vec3 shape_dimensions = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions; + // find the largest Bounds3f for a shape + if (glm::all(glm::greaterThan(shape_dimensions, m_square_dimensions))){ + m_square_dimensions = ceil(shape_dimensions); + } + } + } + + // initialize grid based on where entities are initially placed + for (const auto &go : m_dynamic_gameobjects){ + updateUniformGrid(go); + } +} + +std::string UniformGrid::vecToString(glm::vec3 v){ + std::string square_bound = std::to_string(v.x) + std::to_string(v.y) + std::to_string(v.z); + return square_bound; +} + + +void UniformGrid::populateContainingCell(glm::vec3 bound_corner, std::string entity_id){ + glm::vec3 factor = floor(bound_corner/m_square_dimensions); + glm::vec3 container_min = factor*m_square_dimensions; + + for (auto &square : m_grid_map){ + //if the containing square is already in map, then append entity id to its associate list + if (square.first == vecToString(container_min)){ + m_grid_map.at(square.first).insert(entity_id); + return; + } + } + // if not yet in map, add to map + std::set<std::string> ids; + ids.insert(entity_id); + m_grid_map.insert(std::pair(vecToString(container_min), ids)); +} + +void UniformGrid::updateUniformGrid(const std::pair<std::string, std::shared_ptr<GameObject>> &go){ + if (go.second->hasComponent<CollisionComponent>()){ + Bounds3f shapeBounds = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().bounds; + // if bounds min is within an interval of square dimensions, then occupy map with that entity + glm::vec3 shape_dimensions = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions; + + + // check all 6 aabb corners + float x_val = shapeBounds.min.x; + for (int x=0; x<2; x++){ + float y_val = shapeBounds.min.y; + for (int y=0; y<2; y++){ + float z_val = shapeBounds.min.z; + for (int z=0; z<2; z++){ + glm::vec3 corner = glm::vec3(x_val,y_val,z_val); + populateContainingCell(corner, go.first); + z_val += shape_dimensions.z; + } + y_val += shape_dimensions.y; + } + x_val += shape_dimensions.x; + } + } +} + +// only for entities that moved: +void UniformGrid::moveEntityGridPosition(const std::pair<std::string, std::shared_ptr<GameObject>> &go){ + // remove previous cells that entity occupied + for (auto &cell : m_grid_map){ + cell.second.erase(go.first); + } + + // if there are no more ids associated with that cell, remove it from map + for (auto cell = m_grid_map.cbegin(), next_i = cell; cell != m_grid_map.cend(); cell = next_i){ + ++next_i; + if (cell->second.empty()){ + m_grid_map.erase(cell); + } + } + + // then update based on new pos + updateUniformGrid(go); +} + +void UniformGrid::updateAllGrid(){ + // initialize grid based on where entities are initially placed + for (const auto &go : m_dynamic_gameobjects){ + moveEntityGridPosition(go); + } + + //std::cout << "new ugrid size: " << m_grid_map.size() << std::endl; +} + +std::set<std::set<std::string>> UniformGrid::detectPossibleCollisions(){ + // store list of names of objects that are near e/o + // uses set there are no duplicate inner sets of the same objects + std::set<std::set<std::string>> candidate_collision_sets; + + for (const auto &cell : m_grid_map){ + if (cell.second.size() > 1){ + candidate_collision_sets.insert(cell.second); + } + } + + // then for each inner set, detect collisions between the contained objects + return candidate_collision_sets; +} diff --git a/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h new file mode 100644 index 0000000..c4e5aaa --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h @@ -0,0 +1,67 @@ +#ifndef UNIFORMGRID_H +#define UNIFORMGRID_H + + +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/GameObjects/GameObject.h" +#include <set> +#include <vector> + +struct GridSquare { + Bounds3f bounds; + glm::vec3 centroid = (bounds.max - bounds.min)/ 2.f; + + +// bool operator<( const GridSquare & s ) const { +// return glm::all(glm::lessThan(this->bounds.min,s.bounds.min)); // for example +// } + + +}; + +//bool operator<(const GridSquare& l, const GridSquare& r) +//{ +// return glm::all(glm::lessThan(l.bounds.min, r.bounds.min)); +//} + +//bool operator==(const GridSquare& l, const GridSquare& r) +//{ +// return l.bounds.min == r.bounds.min; +//} + +//bool operator<(const glm::vec3& l, const glm::vec3& r) +//{ +// return glm::all(glm::lessThan(l, r));; +//} + +//bool operator==(const glm::vec3& l, const glm::vec3& r) +//{ +// return glm::all(glm::equal(l, r));; +//} + + +class UniformGrid +{ +public: + UniformGrid(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects); + std::set<std::set<std::string>> detectPossibleCollisions(); + void updateAllGrid(); + + + +private: + void populateContainingCell(glm::vec3 bound_corner, std::string entity_id); + void updateUniformGrid(const std::pair<std::string, std::shared_ptr<GameObject>> &go); + void moveEntityGridPosition(const std::pair<std::string, std::shared_ptr<GameObject>> &go); + void initializeGrid(); + std::string vecToString(glm::vec3 v); + + + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + // maps square corner to set of strings + std::map<std::string, std::set<std::string>> m_grid_map; + glm::vec3 m_square_dimensions; + +}; + +#endif // UNIFORMGRID_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp new file mode 100644 index 0000000..c81be68 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp @@ -0,0 +1,6 @@ +#include "accelerationsystem.h" + +AccelerationSystem::AccelerationSystem() +{ + +} diff --git a/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h new file mode 100644 index 0000000..dd47731 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h @@ -0,0 +1,11 @@ +#ifndef ACCELERATIONSYSTEM_H +#define ACCELERATIONSYSTEM_H + + +class AccelerationSystem +{ +public: + AccelerationSystem(); +}; + +#endif // ACCELERATIONSYSTEM_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp new file mode 100644 index 0000000..40816de --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp @@ -0,0 +1,183 @@ +#include "collisionsystem.h" +#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Game/Components/TransformComponent.h" + +CollisionSystem::CollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<int, Input>& input_map, + std::map<std::string, BlackboardData>& global_blackboard) : + m_gameobjects(gameobjects), + m_dynamic_gameobjects(dynamic_gameobjects), + m_rigid_gameobjects(rigid_gameobjects), + m_uniform_grid_system(std::make_unique<UniformGrid>(dynamic_gameobjects)), + m_global_blackboard(global_blackboard) +{ + +} + +TransformComponent* CollisionSystem::getTransform(std::shared_ptr<GameObject> &go){ + return go->getComponent<TransformComponent>(); + +} + +CollisionComponent* CollisionSystem::getCollisionComp(std::shared_ptr<GameObject> &go){ + return go->getComponent<CollisionComponent>(); +} + +glm::vec2 CollisionSystem::calculateCircleMVT(const Cylinder &a, const Cylinder &b){ + float len = glm::length(a.point - b.point); + + glm::vec2 mtv = ((b.point - a.point)/len) * (a.radius+b.radius - len); + return mtv; +} + +float CollisionSystem::calculateLineMVT(const Cylinder &a, const Cylinder &b){ + float aRight = b.max - a.min; + float aLeft = a.max - b.min; + if ((aLeft < 0) || (aRight < 0)){ + return -1.f; + } + if (aRight < aLeft){ + return aRight; + } + return -aLeft; +} + +glm::vec3 CollisionSystem::collideCylinderCylinder(const std::shared_ptr<GameObject> &a_go, const std::shared_ptr<GameObject> &b_go){ + Cylinder a = a_go->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder(); + Cylinder b = b_go->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder(); + + //std::cout << "a max: " << a.max << std::endl; + //std::cout << "b max: " << b.max << std::endl; + + + + float len_squared = pow(a.point[0]-b.point[0],2) + pow(a.point[1]-b.point[1],2); + float radius_sum = pow(a.radius + b.radius, 2); + + // check if circles overlap + if (len_squared < radius_sum){ + //std::cout << "CIRCLES OVERLAP" << std::endl; + // check if lines overlap + if ((a.min < b.max) && (b.min < a.max)){ + std::cout << "COLLIDINGGG" << std::endl; + // calculate both circle and line mtvs, and then return the shortest mtv + glm::vec2 circle_mtv = calculateCircleMVT(a, b); + float circle_len = glm::length(circle_mtv); + + float line_mtv = calculateLineMVT(a, b); + + if (abs(circle_len) < abs(line_mtv)){ + return glm::vec3(circle_mtv[0], 0.f, circle_mtv[1]); + } else { + return glm::vec3(0.f, line_mtv, 0.f); + } + } + } + + // return translation of 0 if there is no collision + return glm::vec3(0.f); +} + + +bool CollisionSystem::checkCollisionShape(const std::shared_ptr<GameObject> &go, std::string shape_type){ + // add more collision shapes here + if (shape_type == "cylinder"){ + return (go->getComponent<CollisionComponent>()->hasCollisionShape<CylinderCollider>()); + } + return false; +} + +void CollisionSystem::resolveCollision(std::shared_ptr<GameObject> &go, + glm::vec3 mtv, + float deltaTime, + std::string go_name){ + glm::vec3 potential_pos = go->getComponent<TransformComponent>()->getPos(); + go->getComponent<TransformComponent>()->old_pos = potential_pos; + go->getComponent<TransformComponent>()->movingLaterally = false; + + // translate, and also update the collision cylinder point + float a = go->getComponent<CollisionComponent>()->getAcceleration(); + float v = go->getComponent<CollisionComponent>()->getReboundVel(); + float delta_x = mtv.x + v*deltaTime + .5*a*pow(deltaTime, 2); + float delta_z = mtv.z + v*deltaTime + .5*a*pow(deltaTime, 2); + + // update estimated_final_pos, so that tri-ellip collision can see if the new pos collides with environment + glm::vec3 translationDir = glm::vec3(delta_x, mtv.y, delta_z); + if (delta_x != 0 || delta_z != 0){ + go->getComponent<TransformComponent>()->movingLaterally = true; + } + + std::shared_ptr<ModelTransform> temp_mt = go->getComponent<TransformComponent>()->getMT(); + temp_mt->translate(translationDir); + potential_pos = temp_mt->getPos(); + + + m_global_blackboard[go_name].locationData.setToPos = potential_pos; + go->getComponent<TransformComponent>()->estimated_final_pos = potential_pos; +} + +void CollisionSystem::detectCylinderCollisions(std::shared_ptr<GameObject> &a, + std::shared_ptr<GameObject> &b, + float deltaTime, + std::string a_name, std::string b_name){ + // if its a cyl-cyl collision + glm::vec3 mtv(0.f); + + mtv = collideCylinderCylinder(a, b); + if (mtv != glm::vec3(0.f)){ + resolveCollision(b, 1.f*mtv, deltaTime, b_name); + resolveCollision(a, -1.f*mtv, deltaTime, a_name); + } + +} + +bool CollisionSystem::areCollidable(const std::shared_ptr<GameObject> &a, const std::shared_ptr<GameObject> &b){ + return (a->hasComponent<CollisionComponent>() && b->hasComponent<CollisionComponent>()); +} + + +// DYNAMIC-DYNAMIC COLLISIONS: CYLINDER +void CollisionSystem::dynamicDynamicCollisions(double deltaTime){ + std::set<std::set<std::string>> candidate_collison_set = m_uniform_grid_system->detectPossibleCollisions(); + + // std::cout << "all collisions size : " << candidate_collison_set.size() << std::endl; + + for (const std::set<std::string> &set : candidate_collison_set){ + + // std::cout << "collision group size : " << set.size() << std::endl; + + std::vector<std::string> coll_group; + for (const std::string &name : set){ + coll_group.push_back(name); + } + + for (int i=0; i < coll_group.size(); i++){ + auto a = m_dynamic_gameobjects.at(coll_group[i]); + for (int j=i+1; j < coll_group.size(); j++){ + auto b = m_dynamic_gameobjects.at(coll_group[j]); + // if a is not the same GO as b, and at least has collide components and thus is collidable, + if ((a != b) && (areCollidable(a, b))){ + //std::cout << "collide: " << coll_group[i] << " + " << coll_group[j] << std::endl; + detectCylinderCollisions(a, b, deltaTime, coll_group[i], coll_group[j]); + } + } + } + } +} + + +void CollisionSystem::update(double deltaTime){ + // update uniform grid before detecting with it + m_uniform_grid_system->updateAllGrid(); + dynamicDynamicCollisions(deltaTime); +} + +void CollisionSystem::draw(){} +void CollisionSystem::scrollEvent(double distance){} +void CollisionSystem::mousePosEvent(double xpos, double ypos){} + + diff --git a/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h new file mode 100644 index 0000000..5c635ba --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h @@ -0,0 +1,53 @@ +#ifndef COLLISIONSYSTEM_H +#define COLLISIONSYSTEM_H +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameWorld.h" +#include "Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include "Game/Systems/system.h" + +class CollisionSystem : public System +{ +public: + CollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<int, Input>& input_map, + std::map<std::string, BlackboardData>& global_blackboard); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; +private: + bool areCollidable(const std::shared_ptr<GameObject> &a, const std::shared_ptr<GameObject> &b); + void detectCylinderCollisions(std::shared_ptr<GameObject> &a, std::shared_ptr<GameObject> &b, float deltaTime, + std::string a_name, std::string b_name); + void resolveCollision(std::shared_ptr<GameObject> &go, glm::vec3 translation, float deltaTime, std::string go_name); + bool checkCollisionShape(const std::shared_ptr<GameObject> &go, std::string shape_type); + glm::vec3 projectMotion(const glm::vec3 &initial_pos, float deltaTime); + + TransformComponent* getTransform(std::shared_ptr<GameObject> &go); + CollisionComponent* getCollisionComp(std::shared_ptr<GameObject> &go); + + void rigidDynamicCollisions(double deltaTime); + void dynamicDynamicCollisions(double deltaTime); + + + // cylinder-cylinder + glm::vec3 collideCylinderCylinder(const std::shared_ptr<GameObject> &a_go, const std::shared_ptr<GameObject> &b_go); + float calculateLineMVT(const Cylinder &a, const Cylinder &b); + glm::vec2 calculateCircleMVT(const Cylinder &a, const Cylinder &b); + + + std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + + std::unique_ptr<UniformGrid> m_uniform_grid_system; + std::map<std::string, BlackboardData>& m_global_blackboard; +}; + + +#endif // COLLISIONSYSTEM_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp new file mode 100644 index 0000000..52b8916 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp @@ -0,0 +1,370 @@ +#include "ellipsoidtrianglecollisionsystem.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/boundingellipsoid.h" +#include "Game/Components/DrawComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include <memory> + +EllipsoidTriangleCollisionSystem::EllipsoidTriangleCollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) : + m_rigid_gameobjects(rigid_gameobjects), + m_bvh_system(std::make_unique<BVHTree>(rigid_gameobjects)) +{ +} + + +Triangle EllipsoidTriangleCollisionSystem::convertTriangleToSphereSpace(const glm::vec3 &orig_R, const Triangle &orig_triangle){ + Triangle transformed_triangle; + + // divide vertex pos by Rs + transformed_triangle.vertexA = orig_triangle.vertexA / orig_R; + transformed_triangle.vertexB = orig_triangle.vertexB / orig_R; + transformed_triangle.vertexC = orig_triangle.vertexC / orig_R; + + transformed_triangle.edge1 = transformed_triangle.vertexB - transformed_triangle.vertexA; + transformed_triangle.edge2 = transformed_triangle.vertexC - transformed_triangle.vertexA; + + // does the normal stay the same across transformations? + transformed_triangle.normal = glm::normalize(glm::cross(transformed_triangle.edge1, transformed_triangle.edge2)); + + return transformed_triangle; +} + + +glm::vec3 EllipsoidTriangleCollisionSystem::getIntersectionPt(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const float t){ + return ray_p + t*ray_d; +} + +float EllipsoidTriangleCollisionSystem::solveQuadratic(float a, float b, float c){ + float discriminant = pow(b,2) - 4*a*c; + + // check for imaginary numbers + if (discriminant >= 0){ + float pos_quad = (-b + sqrt(discriminant)) / (2*a); + float neg_quad = (-b - sqrt(discriminant)) / (2*a); + + // if the mininum is a neg number, then return the larger of the two + if (fmin(pos_quad, neg_quad) < ZERO){ + return fmax(pos_quad, neg_quad); + } else { + return fmin(pos_quad, neg_quad); + } + } + return -1; +} + + +float EllipsoidTriangleCollisionSystem::raycastSphere(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const glm::vec3 posA, const glm::vec3 posB){ + // shift ray and ellipsoid to center first in order to use regular implicit sphere equation + glm::vec3 p = ray_p - posA; + glm::vec3 d = ray_d - posA; + + float a = (d.x*d.x) + (d.y*d.y) + (d.z*d.z); + float b = (2.f*p.x*d.x) + (2.f*p.y*d.y) + (2.f*p.z*d.z); + float c = (p.x*p.x) + (p.y*p.y) + (p.z*p.z) - 1.f; + + return solveQuadratic(a,b,c); +} + +float EllipsoidTriangleCollisionSystem::raycastTriangle(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const Triangle &triangle){ + float t = (glm::dot((triangle.vertexA - ray_p), triangle.normal))/(glm::dot(ray_d, triangle.normal)); + return t; +} + +glm::vec3 EllipsoidTriangleCollisionSystem::getTriangleEdge(const glm::vec3 v1, const glm::vec3 v2){ + return v2 - v1; +} + +bool EllipsoidTriangleCollisionSystem::isSameDirection(const glm::vec3 edge1, const glm::vec3 edge2, const glm::vec3 n){ + if (glm::dot(glm::cross(edge1, edge2), n) > 0){ + return true; + } + return false; +} + +void EllipsoidTriangleCollisionSystem::makeCollisionData(const float t, const glm::vec3 triangle_n, + const glm::vec3 intersection_pos, + const glm::vec3 point_of_contact, + const bool isVertex){ + CollisionData data; + data.t = t; + data.triangle_n = triangle_n; + data.intersection_pos = intersection_pos; + data.point_of_contact = point_of_contact; + data.isVertex = isVertex; + m_collisionData.push_back(data); +} + + +bool EllipsoidTriangleCollisionSystem::detectSphere_with_Interior(const Triangle &triangle, const glm::vec3 posA, const glm::vec3 posB){ + // calculate point on sphere closest to the plane and cast a ray + glm::vec3 ray_p = posA-triangle.normal; // closest point on unit sphere + glm::vec3 ray_d = (posB-posA); + + glm::vec3 n = triangle.normal; + glm::vec3 v = triangle.vertexA; + float plane_const = -1 * (n.x*v.x + n.y*v.y + n.z*v.z); + + // pdf equation + float t = (1-(glm::dot(n, posA) + plane_const)) / (glm::dot(n, (posB-posA))); + if (t < ZERO || t > ONE){ + return false; + } + + // the point P on the sphere closest to plane surface + glm::vec3 P_edge = getIntersectionPt(ray_p, ray_d, t); + + + // determine if point is on triangle plane + // determine if point is also within triangle bounds + glm::vec3 AB = getTriangleEdge(triangle.vertexA, triangle.vertexB); + glm::vec3 BC = getTriangleEdge(triangle.vertexB, triangle.vertexC); + glm::vec3 CA = getTriangleEdge(triangle.vertexC, triangle.vertexA); + + glm::vec3 AP = getTriangleEdge(triangle.vertexA, P_edge); + glm::vec3 BP = getTriangleEdge(triangle.vertexB, P_edge); + glm::vec3 CP = getTriangleEdge(triangle.vertexC, P_edge); + + if (isSameDirection(AB, AP, triangle.normal) && + isSameDirection(BC, BP, triangle.normal) && + isSameDirection(CA, CP, triangle.normal)){ + + // the actual center of sphere + glm::vec3 P_centered = getIntersectionPt(posA, posB-posA, t); + makeCollisionData(t, triangle.normal, P_centered, P_edge, false); + return true; + } + return false; +} + +// do this for each vertex pair AB, BC, CA +bool EllipsoidTriangleCollisionSystem::detectSphere_with_Edge(const glm::vec3 &v1, const glm::vec3 &v2, + const glm::vec3 &triangle_normal, + const glm::vec3 &posA, const glm::vec3 &posB){ + glm::vec3 C = v1; + glm::vec D = v2; + + float a = pow(glm::length(glm::cross(posB-posA, D-C)),2); + float b = glm::dot(2.f*glm::cross(posB-posA, D-C), glm::cross(posA-C, D-C)); + float c = pow(glm::length(glm::cross(posA-C, D-C)),2) - pow(glm::length(D-C),2); + + float t = solveQuadratic(a,b,c); + + // discard a negative t --> indicates no collision with edge + if (t < ZERO || t > ONE){ + return false; + } + + glm::vec3 P = getIntersectionPt(posA, posB-posA, t); + + glm::vec3 AP = P-C; + glm::vec3 AB = D-C; + glm::vec3 normal = AP - (glm::dot(AB,AP)/glm::dot(AB,AB))*AB; + + // determine if intersection pt is between C and D + if ( (0 < glm::dot(P-C,D-C)) && (glm::dot(P-C,D-C) < pow(glm::length(D-C),2)) ){ + makeCollisionData(t, normal, P, P, false); + return true; + } + + return false; +} + +// needs to be done with each vertex +bool EllipsoidTriangleCollisionSystem::detectSphere_with_Vertex(const glm::vec3 &v, const glm::vec3 triangle_normal, const glm::vec3 &posA, const glm::vec3 &posB){ + glm::vec3 ray_p = v; + //glm::vec3 ray_d = v-(posB-posA); + + // convert to origin space: + glm::vec3 vel = posB-posA; + glm::vec3 v_origined = v - posA; + + float a = glm::dot(vel,vel); + float b = 2*(glm::dot(vel, -v_origined)); + float c = pow(glm::length(v_origined),2) - 1.f; + + float t = solveQuadratic(a,b,c); + if (t < ZERO || t > ONE){ + return false; + } + + // where the center is when the sphere hits vertex + glm::vec3 center_pt_origined = t*vel; + // convert back to non-origin space + glm::vec3 center_pt = center_pt_origined + posA; + glm::vec3 normal = center_pt - v; + makeCollisionData(t, normal, center_pt, v, true); + return true; +} + +CollisionData EllipsoidTriangleCollisionSystem::getNearestCollision(const std::vector<CollisionData> &collisionData, const Triangle &sphere_tri){ + CollisionData nearestCollision; + nearestCollision.t = INFINITY; + + for (const CollisionData &data : collisionData){ + if (data.t < nearestCollision.t){ + // set nearest collision to datapoint + nearestCollision = data; + } + } + return nearestCollision; +} + +// SPHERE SPACE +CollisionData EllipsoidTriangleCollisionSystem::detectTriangleCollision(const Triangle &sphere_tri, const glm::vec3 &posA, const glm::vec3 &posB){ + + m_collisionData.clear(); + // if interior is true, no need to check rest. get the only collision data + if (detectSphere_with_Interior(sphere_tri, posA, posB)){ + return m_collisionData[0]; + } + + // otherwise check rest: + + // detect edge with all 3 edges + // | operator executes regardless of if left hand side is true or not + if ( + detectSphere_with_Edge(sphere_tri.vertexA, sphere_tri.vertexB, sphere_tri.normal, posA, posB) | + detectSphere_with_Edge(sphere_tri.vertexB, sphere_tri.vertexC, sphere_tri.normal, posA, posB) | + detectSphere_with_Edge(sphere_tri.vertexC, sphere_tri.vertexA, sphere_tri.normal, posA, posB) ){ + return getNearestCollision(m_collisionData, sphere_tri); + } + + // detect vertex with all 3 vertices + detectSphere_with_Vertex(sphere_tri.vertexA, sphere_tri.normal, posA, posB); + detectSphere_with_Vertex(sphere_tri.vertexB, sphere_tri.normal, posA, posB); + detectSphere_with_Vertex(sphere_tri.vertexC, sphere_tri.normal, posA, posB); + + return getNearestCollision(m_collisionData, sphere_tri); +} + +CollisionData EllipsoidTriangleCollisionSystem::revertDataToOriginalSpace(const CollisionData &sphere_datum, const glm::vec3 &ellip_R, const glm::vec3 orig_triangle_n){ + CollisionData reverted_datum = sphere_datum; + reverted_datum.intersection_pos = reverted_datum.intersection_pos*ellip_R; + reverted_datum.point_of_contact = reverted_datum.point_of_contact*ellip_R; + + return reverted_datum; +} + +void EllipsoidTriangleCollisionSystem::setEllipsoidDimensions(const glm::vec3 &dimensions){ + m_ellipsoid_dimensions = dimensions; +} + +CollisionData EllipsoidTriangleCollisionSystem::collideWithWorld(const glm::vec3 &posA, const glm::vec3 &posB){ + // makes ellipsoids + Ellipsoid ellipsoidA; + ellipsoidA.R = m_ellipsoid_dimensions; + ellipsoidA.center_pos = posA; + + + Ellipsoid ellipsoidB; + ellipsoidB.R = m_ellipsoid_dimensions; + ellipsoidB.center_pos = posB; + + // convert ellipsoid centers to sphere space + glm::vec3 sphere_posA = ellipsoidA.center_pos/m_ellipsoid_dimensions; + glm::vec3 sphere_posB = ellipsoidB.center_pos/m_ellipsoid_dimensions; + + CollisionData nearestCollision; + nearestCollision.t = INFINITY; + + + std::vector<Triangle> candidates = m_bvh_system->getBVHDetectedCollisions(posA, posB, ellipsoidA.R); + // std::cout << "candidate size: " << candidates.size() << std::endl; + + +// for (auto &rigid_go : candidates){ +// //std::cout << "candidate shape name: " << rigid_go->getComponent<DrawComponent>()->getShapeName() << std::endl; +// if (rigid_go->hasComponent<CollisionComponent>()){ +// if (rigid_go->getComponent<CollisionComponent>()->hasCollisionShape<BoundingTriangle>()){ +// // for every triangle in game obj, transform to sphere space and collide with ellipsoid (aka sphere) + for (int i=0; i< candidates.size(); i++){ + Triangle triangle = candidates[i]; +// std::cout<< "triangle i: " << i << ", v1: (" << triangle.vertexA.x << ", " << triangle.vertexA.y << ", " << triangle.vertexA.z << "), v2: (" +// << triangle.vertexB.x << ", " << triangle.vertexB.y << ", " << triangle.vertexB.z << "), v3: (" +// << triangle.vertexC.x << ", " << triangle.vertexC.y << ", " << triangle.vertexC.z << ")" << std::endl; + + // transform triangle to sphere space and detect collision data (in sphere space) for this specific triangle + Triangle sphere_triangle = convertTriangleToSphereSpace(m_ellipsoid_dimensions, triangle); + CollisionData sphere_collisionDatum = detectTriangleCollision(sphere_triangle, sphere_posA, sphere_posB); + CollisionData ellip_collisionDatum = revertDataToOriginalSpace(sphere_collisionDatum, m_ellipsoid_dimensions, triangle.normal); + + // keep track of nearest Collision + if (ellip_collisionDatum.t < nearestCollision.t && ellip_collisionDatum.t <= ONE && ellip_collisionDatum.t >= ZERO){ + nearestCollision = ellip_collisionDatum; + } + // repeat for the other triangles + } + //} + //} + // repeat for all gameobjects + //} + + return nearestCollision; +} + +glm::vec3 EllipsoidTriangleCollisionSystem::doNudge(glm::vec3 curr_pos, CollisionData collision){ + glm::vec3 nudge = m_scale_normals_mt*collision.triangle_n; + + glm::vec3 pos_nudged = collision.intersection_pos + nudge * .01f; + int MAX_NUDGES = 3; + for (int i=0; i<MAX_NUDGES; i++){ + CollisionData nudge_collision = collideWithWorld(curr_pos, pos_nudged); + if (nudge_collision.t == INFINITY){ + curr_pos = pos_nudged; + break; + } else { + if (glm::length((m_scale_normals_mt*nudge_collision.triangle_n) - nudge) < .0001 || glm::length((m_scale_normals_mt*nudge_collision.triangle_n) + nudge) < .0001){ + nudge = -m_scale_normals_mt*nudge_collision.triangle_n; + } else { + nudge = m_scale_normals_mt*nudge_collision.triangle_n; + } + pos_nudged = nudge_collision.intersection_pos + nudge * .01f; + } + } + return curr_pos; + +} + +glm::mat3 EllipsoidTriangleCollisionSystem::makeConversionMT(glm::vec3 initial_center_pos, glm::vec3 dimensions){ + m_conversion_mt = std::make_shared<ModelTransform>(); + m_conversion_mt->translate(-initial_center_pos); + m_conversion_mt->scale(dimensions); + m_scale_normals_mt = glm::transpose((glm::inverse(glm::mat3(m_conversion_mt->getModelMatrix())))); + m_scale_normals_mt = glm::mat4(1.f); + return m_scale_normals_mt; +} + +// in sphere space +std::pair<std::vector<CollisionData>, glm::vec3> EllipsoidTriangleCollisionSystem::mtvSlide(glm::vec3 initial_pos, glm::vec3 final_pos, glm::vec3 dimensions){ + setEllipsoidDimensions(dimensions); + glm::mat3 normals_scale = makeConversionMT(initial_pos, dimensions); + + std::vector<CollisionData> collisions; + glm::vec3 curr_pos = initial_pos; + glm::vec3 next_pos = final_pos; + int MAX_TRANSLATIONS = 3; + for (int i=0; i<MAX_TRANSLATIONS; i++){ + CollisionData c = collideWithWorld(initial_pos, next_pos); + + // if no collisions [0,1] found, then continue on regular path + if (c.t == INFINITY){ + //std::cout << "--mtv-- " << next_pos.x << "," << next_pos.y << "," << next_pos.z << std::endl; + return std::pair<std::vector<CollisionData>, glm::vec3>(collisions, next_pos); + } else { + // nudge along the collision data + //std::cout << "COLLIDING......" << std::endl; + curr_pos = doNudge(curr_pos, c); + glm::vec3 d = next_pos - curr_pos; + glm::vec3 d_corrected = (d - glm::dot(d, normals_scale*c.triangle_n)) * (normals_scale*c.triangle_n); + next_pos = curr_pos + d_corrected; + collisions.push_back(c); + } + + } + + return std::pair<std::vector<CollisionData>, glm::vec3>(collisions, curr_pos); +} + + diff --git a/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h new file mode 100644 index 0000000..8a7d102 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h @@ -0,0 +1,69 @@ +#ifndef ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H +#define ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H +#include "Game/Components/CollisionComponents/BoundingEllipsoid.h" +#include "Game/Components/CollisionComponents/BoundingTriangle.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/Systems/CollisionSystems/BVH/bvhtree.h" +#include "glm/glm.hpp" +#include <vector> + +struct CollisionData{ + bool hasCollided = true; // only false when there is no collision data to return + bool isVertex = false; + float t = INFINITY; + glm::vec3 triangle_n; // normal of the triangle its colliding with + glm::vec3 intersection_pos; + glm::vec3 point_of_contact; +}; + +class EllipsoidTriangleCollisionSystem +{ +public: + EllipsoidTriangleCollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects); + + + std::pair<std::vector<CollisionData>, glm::vec3> mtvSlide(glm::vec3 initial_pos, glm::vec3 final_pos, glm::vec3 dimensions); + +private: + CollisionData collideWithWorld(const glm::vec3 &posA, const glm::vec3 &posB); + void setEllipsoidDimensions(const glm::vec3 &dimensions); + glm::vec3 doNudge(glm::vec3 curr_pos, CollisionData collision); + CollisionData revertDataToOriginalSpace(const CollisionData &sphere_datum, const glm::vec3 &ellip_R, const glm::vec3 orig_triangle_n); + CollisionData detectTriangleCollision(const Triangle &sphere_tri, const glm::vec3 &posA, const glm::vec3 &posB); + CollisionData getNearestCollision(const std::vector<CollisionData> &collisionData, const Triangle &sphere_tri); + glm::mat3 makeConversionMT(glm::vec3 initial_center_pos, glm::vec3 dimensions); + + + bool detectSphere_with_Vertex(const glm::vec3 &v, const glm::vec3 triangle_normal, const glm::vec3 &posA, const glm::vec3 &posB); + bool detectSphere_with_Edge(const glm::vec3 &v1, const glm::vec3 &v2, + const glm::vec3 &triangle_normal, + const glm::vec3 &posA, const glm::vec3 &posB); + void makeCollisionData(const float t, const glm::vec3 triangle_n, const glm::vec3 intersection_pos, const glm::vec3 point_of_contact, const bool isVertex); + bool detectSphere_with_Interior(const Triangle &triangle, const glm::vec3 posA, const glm::vec3 posB); + + + bool isSameDirection(const glm::vec3 edge1, const glm::vec3 edge2, const glm::vec3 n); + glm::vec3 getTriangleEdge(const glm::vec3 v1, const glm::vec3 v2); + float raycastSphere(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const glm::vec3 posA, const glm::vec3 posB); + float raycastTriangle(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const Triangle &triangle); + float solveQuadratic(float a, float b, float c); + glm::vec3 getIntersectionPt(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const float t); + Triangle convertTriangleToSphereSpace(const glm::vec3 &orig_R, const Triangle &orig_triangle); + + std::vector<CollisionData> m_collisionData; + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + + glm::vec3 m_ellipsoid_dimensions = glm::vec3(1.0); + + float ZERO = -.0001f; + float ONE = 1.0001f; + + std::shared_ptr<ModelTransform> m_conversion_mt; + glm::mat3 m_scale_normals_mt = glm::mat3(1.f); + + std::vector<std::shared_ptr<GameObject>> m_candidate_obstacles; + std::unique_ptr<BVHTree> m_bvh_system; + +}; + +#endif // ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H diff --git a/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp new file mode 100644 index 0000000..3470dd8 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp @@ -0,0 +1,93 @@ +#include "environmentcollisiondetectionsystem.h" +#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include <utility> + +EnvironmentCollisionDetectionSystem::EnvironmentCollisionDetectionSystem( + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables, + std::map<std::string, BlackboardData>& global_blackboard) : + m_dynamic_gameobjects(dynamic_gameobjects), + m_ellipsoid_triangle_collision_system(std::make_unique<EllipsoidTriangleCollisionSystem>(rigid_gameobjects)), + m_global_blackboard(global_blackboard), + m_lootables(lootables) +{ + +} + +TransformComponent* EnvironmentCollisionDetectionSystem::getTransform(std::shared_ptr<GameObject> &go){ + return go->getComponent<TransformComponent>(); + +} + +CollisionComponent* EnvironmentCollisionDetectionSystem::getCollisionComp(std::shared_ptr<GameObject> &go){ + return go->getComponent<CollisionComponent>(); +} + +void EnvironmentCollisionDetectionSystem::detectCollisionWithEnvironment(double deltaTime){ + for (auto &go : m_dynamic_gameobjects){ + collideDynamic(go.first, go.second); + + } +} + + +void EnvironmentCollisionDetectionSystem::collideDynamic(std::string go_name, std::shared_ptr<GameObject> go){ + if (!go->hasComponent<CollisionComponent>()){ + return; + } + + std::pair<std::vector<CollisionData>, glm::vec3> pair = + m_ellipsoid_triangle_collision_system->mtvSlide(getTransform(go)->old_pos, + //getTransform(go.second)->estimated_final_pos, + m_global_blackboard[go_name].locationData.setToPos, + getCollisionComp(go)->getCollisionShape<BoundingDynamicMesh>()->getEllipsoidDimensions()); + + // assume not on ground first; then determine if we are touching ground + getTransform(go)->onGround = false; + m_global_blackboard[go_name].conditionData["onGround"].conditionTrue = false; + for (const CollisionData &collision : pair.first){ + if (glm::dot(glm::vec3(0,1,0), collision.triangle_n) > 0.f){ + getTransform(go)->onGround = true; + m_global_blackboard[go_name].conditionData["onGround"].conditionTrue = true; + + } + } + + if (getTransform(go)->onGround){ + if (getTransform(go)->yVelocity < 0){ + getTransform(go)->yVelocity = 0.f; + getTransform(go)->gravity = 0.f; + } + } + + if (!getTransform(go)->onGround){ + getTransform(go)->gravity = -25.f; + } + + + if (!getTransform(go)->movingLaterally && + getTransform(go)->onGround){ + getTransform(go)->setPos(getTransform(go)->old_pos); + } else { + getTransform(go)->setPos(pair.second); + } + + getCollisionComp(go)->getCollisionShape<BoundingDynamicMesh>()->updateCenterPos(getTransform(go)->getPos()); +} + + +void EnvironmentCollisionDetectionSystem::update(double deltaTime){ + detectCollisionWithEnvironment(deltaTime); +} + +void EnvironmentCollisionDetectionSystem::draw(){} +void EnvironmentCollisionDetectionSystem::scrollEvent(double distance){} +void EnvironmentCollisionDetectionSystem::mousePosEvent(double xpos, double ypos){} + + + diff --git a/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h new file mode 100644 index 0000000..8beca39 --- /dev/null +++ b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h @@ -0,0 +1,43 @@ +#ifndef ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H +#define ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H + + +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include <memory> +#include "Game/Systems/system.h" + +class EnvironmentCollisionDetectionSystem /*: public System*/ +{ +public: + EnvironmentCollisionDetectionSystem( + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables, + std::map<std::string, BlackboardData>& global_blackboard); + void draw() ; + void update(double deltaTime); + void scrollEvent(double distance); + void mousePosEvent(double xpos, double ypos) ; + + +private: + void detectCollisionWithEnvironment(double deltaTime); + CollisionComponent* getCollisionComp(std::shared_ptr<GameObject> &go); + TransformComponent* getTransform(std::shared_ptr<GameObject> &go); + + void collideDynamic(std::string go_name, std::shared_ptr<GameObject> go); + + + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::unique_ptr<EllipsoidTriangleCollisionSystem> m_ellipsoid_triangle_collision_system; + //std::unique_ptr<BVHTree> m_bvh_system; + std::vector<std::shared_ptr<GameObject>> all_rigid_go; + std::map<std::string, BlackboardData>& m_global_blackboard; + + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables; + +}; + +#endif // ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H diff --git a/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp b/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp new file mode 100644 index 0000000..44f20ef --- /dev/null +++ b/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp @@ -0,0 +1,33 @@ +#include "inventoryitem.h" + +InventoryItem::InventoryItem(const char* worldLabelFile, const char* inventoryLabelFile, + glm::vec2 worldLabelScale, + glm::vec2 inventoryLabelScale, + std::set<std::string>& m_shownScreens) +{ + TextureData worldLabelTex = Global::graphics.loadTextureFromFile(worldLabelFile); + TextureData inventoryLabelTex = Global::graphics.loadTextureFromFile(inventoryLabelFile); + + m_world_label = std::make_shared<UIDisplay>(worldLabelTex, glm::vec2(0.f), worldLabelScale, m_shownScreens, AspectRatio::LAND_FIT); + m_inventory_label = std::make_shared<UIDisplay>(inventoryLabelTex, glm::vec2(0.f), inventoryLabelScale, m_shownScreens, AspectRatio::LAND_FIT); +} + +void InventoryItem::updateWorldLabelPos(glm::vec2 pos){ + m_world_label->setPos(pos); +} + +glm::mat4 InventoryItem::getWorldLabelTransformationMat(){ + return m_world_label->getTransformationMat(); +} + +GLuint InventoryItem::getWorldLabelTexID(){ + return m_world_label->getTexID(); +} + +float InventoryItem::getWorldLabelTexAspect(){ + return m_world_label->getTextureScaleAspect(); +} + +std::shared_ptr<UIDisplay> InventoryItem::getUIDisplay(){ + return m_world_label; +} diff --git a/engine-ocean/Game/Systems/Inventory/inventoryitem.h b/engine-ocean/Game/Systems/Inventory/inventoryitem.h new file mode 100644 index 0000000..efa093b --- /dev/null +++ b/engine-ocean/Game/Systems/Inventory/inventoryitem.h @@ -0,0 +1,31 @@ +#ifndef INVENTORYITEM_H +#define INVENTORYITEM_H + + +#include "Game/Systems/UI/UITextures/uidisplay.h" +class InventoryItem +{ +public: + InventoryItem(const char* worldLabelFile, const char* inventoryLabelFile, + glm::vec2 worldLabelScale, + glm::vec2 inventoryLabelScale, + std::set<std::string>& m_shownScreens); + void updateWorldLabelPos(glm::vec2 pos); + glm::mat4 getWorldLabelTransformationMat(); + GLuint getWorldLabelTexID(); + float getWorldLabelTexAspect(); + std::shared_ptr<UIDisplay> getUIDisplay(); + + + + + +private: + std::shared_ptr<UIDisplay> m_world_label; + std::shared_ptr<UIDisplay> m_inventory_label; + + int m_inventoryCount = 0; + +}; + +#endif // INVENTORYITEM_H diff --git a/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp b/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp new file mode 100644 index 0000000..46f5558 --- /dev/null +++ b/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp @@ -0,0 +1,206 @@ +#include "inventorysystem.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/drawcomponent.h" +#include "Game/Components/transformcomponent.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/GameWorld.h" +#include <memory> + +InventorySystem::InventorySystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& all_gameobjects, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables, + std::map<int, Input>& input_map, + std::shared_ptr<Camera>& camera, + std::set<std::string>& m_shownScreens): + m_dynamic_gameobjects(dynamic_gameobjects), + m_input_map(input_map), + m_camera(camera), + m_lootables(lootables), + m_shownScreens(m_shownScreens), + m_all_gameobjects(all_gameobjects) +{ + int m_bamboo_count = 0; + m_screenVAO = Global::graphics.makeVAO(m_quadPos); + + //m_texID = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/enterbutton.png").textureID; + + + initializeInventory("mushroom", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mushroom_loot.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mushroom_loot.png"); + initializeInventory("amantia", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/amantia_loot.png", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/amantia_loot.png"); + + TextureData sparkle = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/sparkle.png"); + m_sparkle = std::make_shared<UIDisplay>(sparkle, glm::vec2(0.f), glm::vec2(.05f), m_shownScreens, AspectRatio::LAND_FIT); + +} + +InventorySystem::~InventorySystem(){ + glDeleteVertexArrays(1, &m_screenVAO); +} + +void InventorySystem::initializeInventory(std::string itemName, const char* label_filename, const char* inventory_filename){ + std::shared_ptr<InventoryItem> inventoryItem = std::make_shared<InventoryItem>(label_filename, inventory_filename, glm::vec2(.2f), glm::vec2(.5f), m_shownScreens); + m_inventoryItems.insert({itemName, inventoryItem}); +} + + +void InventorySystem::addToInventory(std::shared_ptr<GameObject> &go){ + // if G is pressed down, remove go from screen and add it to the inventory + if (m_input_map.at(GLFW_KEY_P).isActive){ + if (go->hasComponent<DrawComponent>()){ + go->removeComponent<DrawComponent>(); + go->removeComponent<CollisionComponent>(); + m_bamboo_count += 1; + } + } +} + +bool InventorySystem::withinPlayerReach(const std::shared_ptr<GameObject> &go){ + glm::vec3 player_pos = m_dynamic_gameobjects.at("player")->getComponent<TransformComponent>()->getPos(); + + // be careful --> the below line will crash if its attempting to get an object with multiple + // transforms, like the ground! + glm::vec3 go_pos = go->getComponent<TransformComponent>()->getPos(); + + float vicinity = 3.f; + // is player and game object are close in either x or z dir + if ((abs(player_pos.x - go_pos.x) < vicinity) + && (abs(player_pos.z - go_pos.z) < vicinity) + && (abs(player_pos.y - go_pos.y) < vicinity)){ + return true; + } + return false; +} + +void InventorySystem::drawUIText(){ + Global::graphics.drawUIText(Global::graphics.getFont("opensans"), std::to_string(m_bamboo_count) + " bamboo collected.", glm::ivec2(20, 90), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1)); + Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Collect 20 bamboos to clear the game.", glm::ivec2(20, 110), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1)); + + if (m_bamboo_count >= 20){ + Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "You Won! Press 'R' to restart.", glm::ivec2(200, 300), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.4f, 0.4f, glm::vec3(1, 1, 1)); + } +} + + + + +void InventorySystem::draw(){ + // bind shader + Global::graphics.bindShader("inventory"); + + // for window resizing + Global::graphics.setCameraData(m_camera); + + // enable alpha blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // disable depth testing + glDisable(GL_DEPTH_TEST); + + // for every item in inventory, compute screen coordinates and draw if near player and on the screen + glm::mat4 proj = m_camera->getProjection(); + glm::mat4 view = m_camera->getView(); + + // if home page is rendered + if (m_shownScreens.contains("home")){ + glBindVertexArray(m_screenVAO); + glEnableVertexAttribArray(0); + + for (auto &lootID : m_lootables){ + for (auto &lootObject : lootID.second){ + glm::vec3 pos = lootObject->getComponent<TransformComponent>()->getMT()->getPos(); + glm::vec4 projected = proj*view*glm::vec4(pos, 1.f); + glm::vec2 screen = glm::vec2(projected.x/projected.w, projected.y/projected.w); + + // if visible on screen + if ((-1.f < screen.x && screen.x < 1.f) && (-1.f < screen.y && screen.y < 1.f)){ + + + + // update texture pos, and draw associated texture + if (withinPlayerReach(lootObject)){ + // update pos + m_inventoryItems[lootID.first]->updateWorldLabelPos(screen + m_offset); + + // get uniforms + glm::mat4 transMat = m_inventoryItems[lootID.first]->getWorldLabelTransformationMat(); + GLuint texID = m_inventoryItems[lootID.first]->getWorldLabelTexID(); + float texAspect = m_inventoryItems[lootID.first]->getWorldLabelTexAspect(); + + glActiveTexture(GL_TEXTURE6); + glBindTexture(GL_TEXTURE_2D, texID); + glm::vec2 texScale = glm::vec2(1.f, texAspect); + glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "textureScale"), texScale.x, texScale.y); + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0])); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + } + // draw sparkle + else { + // update pos + m_sparkle->setPos(screen); + + // get uniforms + glm::mat4 transMat = m_sparkle->getTransformationMat(); + GLuint texID = m_sparkle->getTexID(); + float texAspect = m_sparkle->getTextureScaleAspect(); + + glActiveTexture(GL_TEXTURE6); + glBindTexture(GL_TEXTURE_2D, texID); + glm::vec2 texScale = glm::vec2(1.f/texAspect, 1.f); + glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "textureScale"), texScale.x, texScale.y); + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0])); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + } + } + + } + + } + + glDisableVertexAttribArray(0); + glBindVertexArray(0); + } + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); +} + + +void InventorySystem::update(double deltaTime){ + + // remove from m_lootables to remove labels and drawing + for (auto &lootGroup : m_lootables){ + for (auto itr = lootGroup.second.begin(); itr != lootGroup.second.end();){ + auto& loot = *itr; + if (withinPlayerReach(loot) && m_input_map.at(GLFW_KEY_P).isActive){ + loot->removeComponent<DrawComponent>(); + itr = lootGroup.second.erase(itr); + } else { + ++itr; + } + } + } + + // remove game object entirely based on if its not drawn +// for(auto it = m_all_gameobjects.begin(); it != m_all_gameobjects.end();){ +// if (!it->second->hasComponent<DrawComponent>()){ +// it = m_all_gameobjects.erase(it); +// } +// } +} + +void InventorySystem::onWindowResize(int width, int height){ + for (auto &lootID : m_lootables){ + m_inventoryItems[lootID.first]->getUIDisplay()->setWindowPos(width, height); + + } +} + +void InventorySystem::scrollEvent(double distance){} +void InventorySystem::mousePosEvent(double xpos, double ypos){} + diff --git a/engine-ocean/Game/Systems/Inventory/inventorysystem.h b/engine-ocean/Game/Systems/Inventory/inventorysystem.h new file mode 100644 index 0000000..4305f68 --- /dev/null +++ b/engine-ocean/Game/Systems/Inventory/inventorysystem.h @@ -0,0 +1,78 @@ +#ifndef INVENTORYSYSTEM_H +#define INVENTORYSYSTEM_H + + +#include "Game/GameWorld.h" +#include <map> +#include "inventoryitem.h" + +//struct InventoryItem{ +// TextureData lootLabelUI; +// TextureData lootInventoryUI; +// int inventoryCount = 0; + +// InventoryItem(TextureData label, TextureData inventory): +// lootLabelUI(label), +// lootInventoryUI(inventory) +// {} +//}; + +class InventorySystem : public System +{ +public: + InventorySystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& all_gameobjects, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables, + std::map<int, Input>& input_map, + std::shared_ptr<Camera>& camera, + std::set<std::string>& m_shownScreens); + ~InventorySystem(); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + void drawUIText(); + void onWindowResize(int width, int height); + + + +private: + void addToInventory(std::shared_ptr<GameObject> &go); + bool withinPlayerReach(const std::shared_ptr<GameObject> &go); + void initializeInventory(std::string itemName, const char* label_filename, const char* inventory_filename); + + + + + + int m_bamboo_count = 0; + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + + // maps loot id to game objects/associated textures + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables; // holds position + std::map<std::string, std::shared_ptr<InventoryItem>> m_inventoryItems; + + std::map<int, Input>& m_input_map; + std::shared_ptr<Camera>& m_camera; + + //std::set<std::string> m_inventoryScreens; // stores ids of all scenes in which inventory is rendered + std::set<std::string>& m_shownScreens; + + std::vector<float> m_quadPos = { + -1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f + }; + + GLuint m_screenVAO; + GLuint m_texID; + + glm::vec2 m_offset = glm::vec2(.2f); + + std::shared_ptr<UIDisplay> m_sparkle; + + std::map<std::string, std::shared_ptr<GameObject>>& m_all_gameobjects; +}; + +#endif // INVENTORYSYSTEM_H diff --git a/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp new file mode 100644 index 0000000..8abbec8 --- /dev/null +++ b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp @@ -0,0 +1,35 @@ +#include "aimovementsystem.h" +#include "Game/Components/TransformComponent.h" +#include "Game/Components/PathfindComponent.h" +#include "Game/Systems/AI/aibehaviorcomponent.h" + +AIMovementSystem::AIMovementSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) : + m_dynamic_gameobjects(dynamic_gameobjects), + m_rigid_gameobjects(rigid_gameobjects) + +{ + // m_path = m_rigid_gameobjects.at("navmesh")->getComponent<PathfindComponent>()->getPath(glm::vec3(-0.58249, 0, -0.0210782), glm::vec3(19.5371, 0, 1.39167)); + +} + +TransformComponent* AIMovementSystem::getTransform(std::shared_ptr<GameObject> &go){ + return go->getComponent<TransformComponent>(); +} + + +void AIMovementSystem::update(double deltaTime){ + for (auto &go : m_dynamic_gameobjects){ + if (go.second->hasComponent<AIBehaviorComponent>()){ + go.second->getComponent<AIBehaviorComponent>()->update(deltaTime); + } + } +} + + + + +void AIMovementSystem::draw(){} +void AIMovementSystem::scrollEvent(double distance){} +void AIMovementSystem::mousePosEvent(double xpos, double ypos){} + diff --git a/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h new file mode 100644 index 0000000..e880e44 --- /dev/null +++ b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h @@ -0,0 +1,34 @@ +#ifndef AIMOVEMENTSYSTEM_H +#define AIMOVEMENTSYSTEM_H +#include "Game/Components/TransformComponent.h" +#include "Game/Systems/Pathfinding/pathfinder.h" +#include "Game/Systems/system.h" + + +class AIMovementSystem : public System +{ +public: + AIMovementSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + +private: + float gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity); + TransformComponent* getTransform(std::shared_ptr<GameObject> &go); + + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + + + float horiz_velocity = .005f; + float snapshot_time = 0.f; + + std::vector<glm::vec3> m_path; + + //std::shared_ptr<Pathfinder> m_pathfinder; +}; + +#endif // AIMOVEMENTSYSTEM_H diff --git a/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp b/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp new file mode 100644 index 0000000..35d67d2 --- /dev/null +++ b/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp @@ -0,0 +1,321 @@ +#include "pathfinder.h" +#include "glm/glm.hpp" +#include "glm/gtx/hash.hpp" + +#include <iostream> +#include <set> +#include <vector> + +// there can be multiple pathfinders for multiple environemnt meshes +// pathfinding/environment component for an environment mesh? +Pathfinder::Pathfinder(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles): + m_vertices(vertices), + m_triangles(triangles) +{ + initializeEdges(); +} + +// for entire scene, generate data structure that holds nav mesh +void Pathfinder::initializeEdges(){ + + std::map<std::pair<int,int>, TriangleEdge> temp_data; + + // indices of vertex pairs + std::vector<std::pair<int,int>> range = {std::make_pair(0, 1), + std::make_pair(1, 2), + std::make_pair(2, 0)}; + + // make edges for all triangles and populate temp_data map + for (glm::vec3 triangle : m_triangles){ + std::vector<std::pair<int,int>> keys; + for (auto index_pair : range ){ + // make ordered pair of the index of vertex held by triangle , for all edges + std::pair<int, int> key = makeOrderedPair(triangle[index_pair.first], triangle[index_pair.second]); + keys.push_back(key); + + if (temp_data.count(key) != 0){ + temp_data.at(key).count ++; + } else { + // make a new entry that populates the midpoint + TriangleEdge edge = {m_vertices[key.first], m_vertices[key.second]}; + temp_data.insert(std::make_pair(key, edge)); + } + } + + for (auto key : keys){ + // add the two neighbors for each key + for (auto neighbor_id : keys){ + if (key != neighbor_id){ + temp_data.at(key).adjacentEdges.insert(neighbor_id); + } + } + } + } + + std::set<std::pair<int,int>> interiorEdges; + + // remove exterior edges from adjacent lists + for (auto &entry : temp_data){ + // make new adjacency list + std::set<std::pair<int,int>> edited_adj_list; + + for (const auto adjNode : entry.second.adjacentEdges){ + // if adjacent node is an interior node, add to new adj list + if (temp_data.at(adjNode).count > 1){ + edited_adj_list.insert(adjNode); + } + } + + // reassign adj list + entry.second.adjacentEdges.swap(edited_adj_list); + } + + // add interior edges + for (const auto &entry : temp_data){ + if (entry.second.count > 1){ + ANode node; + node.adjacentNodes = entry.second.adjacentEdges; + node.pos = entry.second.midpoint; + m_navdata.insert(std::make_pair(entry.first, node)); + } + } + + +} + + +std::pair<int, int> Pathfinder::makeOrderedPair(int i, int j){ + std::pair<int, int> pair = std::pair(std::min(i,j), std::max(i,j)); + return pair; +} + +// traverse navmeshgraph +// A --> start ; B --> destination +std::vector<glm::vec3> Pathfinder::findPath(const glm::vec3 A, const glm::vec3 B){ + // start and end indices are double pair because no existing edge has two of the same vertices + m_startNodePos = A; + m_endNodePos = B; + + // initialize empty path + std::vector<glm::vec3> empty; + empty.push_back(glm::vec3(0.f)); + + // initialize start and ending node + ANode startNode, endNode; + startNode.pos = m_startNodePos; + endNode.pos = m_endNodePos; + startNode.Gcost = 0; + m_navdata.insert(std::pair(startNodeID, startNode)); + m_navdata.insert(std::pair(endNodeID, endNode)); + + + // calculate distance to end point for each item in map + for (auto &node : m_navdata){ + node.second.Hcost = getDistance(node.second.pos, B); + updateFCost(node.first); + } + + // determine if one or both start/end points are in navmesh or not + std::pair<bool, std::set<std::pair<int, int>>> validStartPoint = findEnclosingTriangle(A); + std::pair<bool, std::set<std::pair<int, int>>> validEndPoint = findEnclosingTriangle(B); + + // if neither or both points can be found in navmesh, end early + if (!validStartPoint.first || !validEndPoint.first){ + std::cout << "-- a point is not in navmesh" << std::endl; + return empty; + } + + // if both points are on same triangle, then return only the destination + if (validStartPoint.second == validEndPoint.second){ + std::vector<glm::vec3> destination; + destination.push_back(B); + std::cout << "-- SAME TRIANGLE" << std::endl; + return destination; + } + + std::set<std::pair<int,int>> open; + std::set<std::pair<int,int>> closed; + + // initialize open list + // check if id is a valid interior node + for (const auto &id : validStartPoint.second){ + if (m_navdata.contains(id)){ + m_navdata[id].previousV = startNodeID; + m_navdata[id].Gcost = getDistance(m_navdata[id].pos, m_startNodePos); + updateFCost(id); + open.insert(id); + } + } + + // calculate paths with Astar + bool reachable = traverseAStar(startNodeID, validEndPoint.second, open, closed); + + if (reachable){ + std::cout << "reachable!" << std::endl; + return getNavigablePath(startNodeID, endNodeID); + } + + // otherwise, return glm::vec3(0) so that entity doesnt move + std::cout << "not reachable" << std::endl; + return empty; +} + +void Pathfinder::updateFCost(const std::pair<int,int> &node){ + m_navdata[node].Fcost = m_navdata[node].Gcost + m_navdata[node].Hcost; + +} + +bool Pathfinder::traverseAStar(const std::pair<int,int> &currNodeID, const std::set<std::pair<int,int>> &endpointNodeIDs, + std::set<std::pair<int,int>> &open, std::set<std::pair<int,int>> &closed){ + + glm::vec3 currNodePos = m_navdata.at(currNodeID).pos; + + // base case: if looking at nodes that are way too far from entity start pos, then just end + if (getDistance(currNodePos, m_startNodePos) > m_maxDistance){ + std::cout << "-- DISTANCE TOO FAR" << std::endl; + return false; + } + + float lowestF = INFINITY; + float lowestH = INFINITY; + std::pair<int,int> C; // where C is the next node to visit + + for (const std::pair<int,int> &nodeID : open){ + // calculate G, which also populates F + // --------------- do i also need to check if the previous f cost was less than the updated f cost? + float new_Gcost = getDistance(m_navdata[nodeID].pos, currNodePos) + m_navdata[currNodeID].Gcost; + m_navdata[nodeID].Gcost = new_Gcost; + updateFCost(nodeID); + + if (m_navdata[nodeID].Fcost == lowestF){ + // go by lowest H if F costs are equal + if (m_navdata[nodeID].Hcost < lowestH){ + C = nodeID; + lowestF = m_navdata[nodeID].Fcost; + lowestH = m_navdata[nodeID].Hcost; + } + } + + if (m_navdata[nodeID].Fcost < lowestF){ + C = nodeID; + lowestF = m_navdata[nodeID].Fcost; + lowestH = m_navdata[nodeID].Hcost; + } + } + + // move C from open to closed list + open.erase(C); + closed.insert(C); + + //if C is equal to any of the endpoint indices, then path is found + for (const std::pair<int,int> &id : endpointNodeIDs){ + if (C == id){ + m_navdata[endNodeID].previousV = C; + return true; + } + } + + // for neighbor N of C + for (const std::pair<int,int> &N: m_navdata[C].adjacentNodes){ + if (closed.contains(N)) continue; + + // calculate potential F cost of C-->N + float new_Gcost = getDistance(m_navdata[N].pos, m_navdata[C].pos) + m_navdata[C].Gcost; + float new_Fcost = new_Gcost + m_navdata[N].Hcost; + + if (new_Fcost < m_navdata[N].Fcost || !open.contains(N)){ + // update N's G and F cost + m_navdata[N].Gcost = new_Gcost; + updateFCost(N); + // set previous node of N to be C + m_navdata[N].previousV = C; + + // add N to open if its not already in it + open.insert(N); + } + } + + // if there are still open nodes, visit the next one (recurse) + if (!open.empty()){ + traverseAStar(C, endpointNodeIDs, open, closed); + } + + // otherwise no more open nodes, thus a* has finished + return true; +} + + +// distance is the un-squarerooted distance between two points +float Pathfinder::getDistance(glm::vec3 a, glm::vec3 b){ + return pow(a.x-b.x, 2) + pow(a.y-b.y, 2) + pow(a.z-b.z, 2); +} + + +// referenced from https://blackpawn.com/texts/pointinpoly/default.html +bool Pathfinder::sameSide(glm::vec3 p1, glm::vec3 p2, glm::vec3 a, glm::vec3 b){ + glm::vec3 cp1 = glm::cross(b-a, p1-a); + glm::vec3 cp2 = glm::cross(b-a, p2-a); + + glm::vec3 a1 = glm::vec3(cp1.x, cp1.y + .001, cp1.z); + glm::vec3 a2 = glm::vec3(cp1.x, cp1.y - .001, cp1.z); + + glm::vec3 b1 = glm::vec3(cp2.x, cp2.y + .001, cp2.z); + glm::vec3 b2 = glm::vec3(cp2.x, cp2.y - .001, cp2.z); + + + if (glm::dot(a1, b1) >= 0 || glm::dot(a2, b2) >= 0 + || glm::dot(a1, b2) >= 0 || glm::dot(a2, b1) >= 0) return true; + return false; +} + +bool Pathfinder::pointInTriangle(glm::vec3 p, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3){ + if (sameSide(p,v1, v2,v3) && sameSide(p,v2, v1,v3) && sameSide(p,v3, v1,v2)) return true; + return false; +} + +std::pair<bool, std::set<std::pair<int, int>>> Pathfinder::findEnclosingTriangle(glm::vec3 point){ + + // for each triangle in navmesh, get its vertices + for (glm::vec3 vertex_triple : m_triangles){ + // if point is in any navmesh triangle, then return the 3 nodes associated with that tri + if (pointInTriangle(point, m_vertices[vertex_triple[0]], m_vertices[vertex_triple[1]], m_vertices[vertex_triple[2]])){ + return std::make_pair(true, getEnclosingTriangleEdges(vertex_triple)); + } + } + + // if no triangles contained the point, return false + return std::make_pair(false, getEnclosingTriangleEdges(glm::vec3(0.f))); +} + +// gets node indices +std::set<std::pair<int, int>> Pathfinder::getEnclosingTriangleEdges(glm::vec3 indices){ + std::set<std::pair<int, int>> ids; + ids.insert(makeOrderedPair(indices[0], indices[1])); + ids.insert(makeOrderedPair(indices[1], indices[2])); + ids.insert(makeOrderedPair(indices[2], indices[0])); + + return ids; +} + +std::vector<glm::vec3> Pathfinder::getNavigablePath(const std::pair<int,int> &start, const std::pair<int,int> &end){ + // start at B, and use previousV pointers to get back to A + std::vector<glm::vec3> path; + path.push_back(m_navdata[end].pos); + + std::pair<int,int> currV = end; + + while (currV != start){ + // add current point to path + glm::vec3 pos = m_navdata[m_navdata[currV].previousV].pos; + path.push_back(pos); + + // reassign variable to where currV points, and enter loop again + currV = m_navdata[currV].previousV; + } + + // path where the very last entry is the start point, and the very first entry is the end point + return path; + +} + + diff --git a/engine-ocean/Game/Systems/Pathfinding/pathfinder.h b/engine-ocean/Game/Systems/Pathfinding/pathfinder.h new file mode 100644 index 0000000..d9abbd6 --- /dev/null +++ b/engine-ocean/Game/Systems/Pathfinding/pathfinder.h @@ -0,0 +1,83 @@ +#ifndef PATHFINDER_H +#define PATHFINDER_H + +#include "glm/fwd.hpp" +#include "glm/gtx/hash.hpp" + + +#include <map> +#include <set> +#include <vector> + +struct ANode{ + glm::vec3 pos; + // A* related: + float Hcost = 0; // distance to destination + float Gcost = 0; // distance from start to current node (accumulative G) + float Fcost = Gcost+Hcost; + std::pair<int,int> previousV; + std::set<std::pair<int,int>> adjacentNodes; +}; + +struct TriangleEdge{ + glm::vec3 midpoint; + std::set<std::pair<int,int>> adjacentEdges; + + TriangleEdge(glm::vec3 v1, glm::vec3 v2): + midpoint(.5f*(v2+v1)) + {} + // num of times it appears in the navgraph + int count = 1; +}; + +class Pathfinder +{ +public: + Pathfinder(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles); + std::vector<glm::vec3> findPath(const glm::vec3 A, const glm::vec3 B); + + + +private: + + void updateFCost(const std::pair<int,int> &node); + + + + + bool traverseAStar(const std::pair<int,int> &currNodeID, const std::set<std::pair<int,int>> &endpointNodeIDs, + std::set<std::pair<int,int>> &open, std::set<std::pair<int,int>> &closed); + + std::set<std::pair<int, int>> getEnclosingTriangleEdges(glm::vec3 indices); + + void initializeEdges(); + float getDistance(glm::vec3 a, glm::vec3 b); + std::vector<glm::vec3> getNavigablePath(const std::pair<int,int> &start, const std::pair<int,int> &end); + std::pair<bool, std::set<std::pair<int, int>>> findEnclosingTriangle(glm::vec3 point); + bool pointInTriangle(glm::vec3 p, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3); + bool sameSide(glm::vec3 p1, glm::vec3 p2, glm::vec3 a, glm::vec3 b); + + std::set<std::vector<float>> getAdjacentNodes(const std::set<std::pair<int,int>> &id_pairs, std::map<std::pair<int,int>, TriangleEdge> &temp_data); + + + std::pair<int, int> makeOrderedPair(int i, int j); + + // maps pos (midpoint of a edge) to node + std::map<std::pair<int,int>, ANode> m_navdata; + std::vector<glm::vec3> m_vertices; + std::vector<glm::ivec3> m_triangles; + glm::vec3 m_startNodePos; + glm::vec3 m_endNodePos; + + std::pair<int,int> startNodeID = std::make_pair(0,0); + std::pair<int,int> endNodeID = std::make_pair(1,1); + + + float m_maxDistance = 500; // 20 meters max distance that an ai can pathfind + + + + +}; + +#endif // PATHFINDER_H diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp new file mode 100644 index 0000000..c7314f6 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp @@ -0,0 +1,6 @@ +#include "buttonaction.h" + +ButtonAction::ButtonAction() +{ + +} diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h new file mode 100644 index 0000000..d6c1674 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h @@ -0,0 +1,13 @@ +#ifndef BUTTONACTION_H +#define BUTTONACTION_H + + +class ButtonAction +{ +public: + ButtonAction(); + virtual void activate() = 0; + virtual void deactivate() = 0; +}; + +#endif // BUTTONACTION_H diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp new file mode 100644 index 0000000..e6b9797 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp @@ -0,0 +1,33 @@ +#include "showwindowaction.h" +#include "Game/Systems/UI/uisystem.h" +#include <map> + +ShowWindowAction::ShowWindowAction(std::map<std::string, std::shared_ptr<UIScreen>>& all_screens, + std::set<std::string>& shownScreens, + const std::string screenName): + m_screens(all_screens), + m_shownScreens(shownScreens) +{ + m_screenName = screenName; +} + + + +void ShowWindowAction::activate(){ + std::cout << "activated window show!!!" << std::endl; + + // add screen to be rendered, and also set it be the only one active + //m_screens[m_screenName] = m_screen; +// for (auto &screen : m_screens){ +// screen.second->isActive = false; +// } + +// m_screens[m_screenName]->isActive = true; + m_shownScreens.insert(m_screenName); + m_screens[m_screenName]->isActive = true; + +} + +void ShowWindowAction::deactivate(){ + m_shownScreens.erase(m_screenName); +} diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h new file mode 100644 index 0000000..781f093 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h @@ -0,0 +1,21 @@ +#ifndef SHOWWINDOWACTION_H +#define SHOWWINDOWACTION_H +#include "Game/Systems/UI/uisystem.h" +#include <map> +#include "buttonaction.h" + +class ShowWindowAction : public ButtonAction +{ +public: + ShowWindowAction(std::map<std::string, std::shared_ptr<UIScreen>>& screens, + std::set<std::string>& shownScreens, + const std::string screenName); + void activate() override; + void deactivate() override; +private: + std::set<std::string>& m_shownScreens; + std::string m_screenName; + std::map<std::string, std::shared_ptr<UIScreen>>& m_screens; +}; + +#endif // SHOWWINDOWACTION_H diff --git a/engine-ocean/Game/Systems/UI/UITextures/UIButton.h b/engine-ocean/Game/Systems/UI/UITextures/UIButton.h new file mode 100644 index 0000000..8cf02ee --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/UIButton.h @@ -0,0 +1,94 @@ +#ifndef UIBUTTON_H +#define UIBUTTON_H +#include "Game/Systems/UI/ButtonAction/buttonaction.h" +#include "Game/Systems/UI/UITextures/uidisplay.h" +#include "Graphics/global.h" +#include <GLFW/glfw3.h> +#include <set> +#include "uitexture.h" + +enum CornerPosition { + TOPLEFT, + TOPRIGHT, + BOTTOMLEFT, + BOTTOMRIGHT, + NONE +}; + +class UIButton : public UITexture +{ +public: + UIButton(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens, + bool isCloseButton = false, CornerPosition corner = NONE, AspectRatio ratio = LAND_FIT); + ~UIButton(); + void draw() override; + GLuint getTexID() override; + glm::vec2 getPos() override; + glm::vec2 getScale() override; + float getTextureRatio() override; + AspectRatio getAspectRatio(); + + + + void setWindowPos(int width, int height) override; + glm::vec2 getWindowPos(); + + int getHeight() override; + int getWidth() override; + Bounds2f getBounds() override; + float getTextureScaleAspect() override; + + void addButtonAction(std::shared_ptr<ButtonAction> &action); + bool onButtonPress(); + void setWindowToClose(std::string windowID); + + void setParentDisplay(std::string parent); + std::string getParentDisplay(); + + CornerPosition getCornerPos(); + bool hasCornerPos = false; + void setToCorner(const CornerPosition corner, int width, int height); + + void setTransformationMat(glm::vec2 translation, glm::vec2 scale); + glm::mat4 getTransformationMat(); + + + +private: + glm::mat4 getScaleMatrix(glm::vec2 scale); + int getScreenHeight(); + int getScreenWidth(); + void setTexID(GLuint &newTexID); + + + TextureData m_tex; + glm::vec2 m_pos; + glm::vec2 m_scale; + Bounds2f m_bounds; + glm::vec2 m_windowPos; // width, height + float m_windowHeight = 480.f; + float m_windowWidth = 640.f; + float m_toScreenScale = 1.f; + + int m_screenImageHeight; + int m_screenImageWidth; + float m_tex_aspectRatio = 1.f; + bool m_isCloseButton = false; + std::string m_attachedWindow; + + std::vector<std::shared_ptr<ButtonAction>> m_actions; + std::set<std::string>& m_shownScreens; + + CornerPosition m_cornerPos; + std::string m_parentDisplay; + + glm::mat4 m_transformationMat; + float m_textureAspect = 1.f; + + AspectRatio m_aspectRatio; + + + +}; + +#endif // UIButton_H diff --git a/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp b/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp new file mode 100644 index 0000000..031be2f --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp @@ -0,0 +1,202 @@ +#include "UIButton.h" +#include "Game/Systems/UI/UITextures/UIDisplay.h" +#include <set> + +UIButton::UIButton(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens, + bool isCloseButton, CornerPosition corner, AspectRatio ratio): + m_tex(tex), + m_shownScreens(shownScreens), + m_aspectRatio(ratio) +{ + + // set variables + m_isCloseButton = isCloseButton; + m_pos = pos; + m_scale = scale; + m_tex_aspectRatio = static_cast<float>(m_tex.height)/static_cast<float>(m_tex.width); + + setToCorner(corner, 640, 480); + setWindowPos(640, 480); + setTransformationMat(m_pos, scale); + +} +UIButton::~UIButton(){ + glDeleteTextures(1, &m_tex.textureID); +} + + +AspectRatio UIButton::getAspectRatio(){ + return m_aspectRatio; +} + +glm::mat4 UIButton::getScaleMatrix(glm::vec2 scale) { + glm::mat4 M = glm::mat4(1.f); + M[0][0] = scale.x; //* (m_screenImageHeight/m_screenImageWidth); + M[1][1] = scale.y; //* (m_tex_aspectRatio); + M[2][2] = 1.f; + return M; +} + +void UIButton::setTransformationMat(glm::vec2 translation, glm::vec2 scale){ + glm::mat4 transMat = glm::mat4(1.f); + transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f); + glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale)); + m_transformationMat = transMat*scaleMat; +} + +glm::mat4 UIButton::getTransformationMat(){ + return m_transformationMat; +} + +float UIButton::getTextureRatio(){ + return m_tex_aspectRatio; +} + + +void UIButton::draw(){} + +GLuint UIButton::getTexID(){ + return m_tex.textureID; +} + +glm::vec2 UIButton::getPos(){ + return m_pos; +} + +glm::vec2 UIButton::getScale(){ + return m_scale; +} + +//void UIButton::setTexID(GLuint &newTexID){ +// m_tex.textureID = newTexID; +//} + +void UIButton::setWindowPos(int width, int height){ + m_windowHeight = static_cast<float>(height); + m_windowWidth = static_cast<float>(width); + + // find where on window it is, for bound checking + float xpos = .5f*(m_pos.x + 1.f)*m_windowWidth; + float ypos = (1.f-.5f*(m_pos.y + 1.f))*m_windowHeight; + m_windowPos = glm::vec2(xpos, ypos); + + // set everything according to window dimensions -- this is for bound checking + m_toScreenScale = m_windowHeight*m_scale.y; + m_screenImageHeight = m_toScreenScale; + m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio; + + float windowRatio = m_windowHeight/m_windowWidth; + m_textureAspect = windowRatio / m_tex_aspectRatio; + + // calculate window bounds + glm::vec2 halfDimensions = glm::vec2(m_screenImageWidth, m_screenImageHeight)*.5f; + m_bounds.max = glm::vec2(m_windowPos.x + halfDimensions.x, m_windowPos.y - halfDimensions.y); + m_bounds.min = glm::vec2(m_windowPos.x - halfDimensions.x, m_windowPos.y + halfDimensions.y); +} + +float UIButton::getTextureScaleAspect(){ + return m_textureAspect; +} + +void UIButton::setParentDisplay(std::string parent){ + m_parentDisplay = parent; + +} + +std::string UIButton::getParentDisplay(){ + return m_parentDisplay; + +} + +CornerPosition UIButton::getCornerPos(){ + return m_cornerPos; + +} + +void UIButton::setToCorner(const CornerPosition corner, int width, int height){ + + m_toScreenScale = static_cast<float>(height)*m_scale.y; + m_screenImageHeight = m_toScreenScale; + m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio; + + // in texture space + float xtrans = m_screenImageWidth/(.5f*static_cast<float>(width)); + float ytrans = m_screenImageHeight/(.5f*static_cast<float>(height)); + + // find where window pos should be + switch(corner){ + case TOPLEFT: + m_pos = glm::vec2(-1+xtrans, 1-ytrans); + + break; + case TOPRIGHT: + m_pos = glm::vec2(1-xtrans, 1-ytrans); + + break; + case BOTTOMLEFT: + m_pos = glm::vec2(-1+xtrans, -1+ytrans); + + break; + case BOTTOMRIGHT: + m_pos = glm::vec2(1-xtrans, -1+ytrans); + break; + default: + break; + } +} + +glm::vec2 UIButton::getWindowPos(){ + return m_windowPos; +} + +int UIButton::getHeight(){ + return m_tex.height; +} +int UIButton::getWidth(){ + return m_tex.width; +} + +int UIButton::getScreenHeight(){ + return m_screenImageHeight; +} +int UIButton::getScreenWidth(){ + return m_screenImageWidth; +} + +// remember that origin is top left corner!! +Bounds2f UIButton::getBounds(){ + + return m_bounds; +} + +void UIButton::addButtonAction(std::shared_ptr<ButtonAction> &action){ + m_actions.push_back(action); +} + +//////*/ for close button only +void UIButton::setWindowToClose(std::string windowID){ + if (m_isCloseButton){ + m_attachedWindow = windowID; + } + +} + +bool UIButton::onButtonPress(){ + // if button is a close button, then deactivate everything + if (m_isCloseButton){ + std::cout << "shownWindowSize: " << m_shownScreens.size() << std::endl; + //m_shownScreens.erase(m_attachedWindow); + std::cout << "new shownWindowSize: " << m_shownScreens.size() << std::endl; + std::cout << "CLOSE WINDOW: " << m_attachedWindow << std::endl; + return true; + + + } else { + for (auto &action : m_actions){ + action->activate(); + } + return false; + } + +} + diff --git a/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp new file mode 100644 index 0000000..2ddaf62 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp @@ -0,0 +1,130 @@ +#include "uidisplay.h" +#include <set> + +UIDisplay::UIDisplay(TextureData tex, glm::vec2 pos, glm::vec2 scale, + std::set<std::string>& shownScreens, + AspectRatio ratio): + m_tex(tex), + m_shownScreens(shownScreens), + m_aspectRatio(ratio) +{ + + m_pos = (pos); + m_scale = (scale); + m_tex_aspectRatio = static_cast<float>(m_tex.height)/static_cast<float>(m_tex.width); + setTransformationMat(pos, scale); +// std::cout << "tex aspect ratio:" << m_tex_aspectRatio << std::endl; + +// std::cout << "aspect ratio w: " << m_tex.width << std::endl; +// std::cout << "aspect ratio h: " << m_tex.height << std::endl; + + + setWindowPos(640, 480); +// std::cout << "screen image height: " << m_screenImageHeight << std::endl; +// std::cout << "screen image width: " << m_screenImageWidth << std::endl; + +} + +UIDisplay::~UIDisplay(){ + glDeleteTextures(1, &m_tex.textureID); +} + +void UIDisplay::draw(){} + +GLuint UIDisplay::getTexID(){ + return m_tex.textureID; +} + +glm::vec2 UIDisplay::getPos(){ + return m_pos; +} + +glm::vec2 UIDisplay::getScale(){ + return m_scale; +} + +AspectRatio UIDisplay::getAspectRatio(){ + return m_aspectRatio; +} + +void UIDisplay::setWindowPos(int width, int height){ + float xpos = .5f*(m_pos.x + 1.f)*static_cast<float>(width); + float ypos = (1.f-.5f*(m_pos.y + 1.f))*static_cast<float>(height); + m_windowPos = glm::vec2(xpos, ypos); + + // set everything according to window dimensions + m_toScreenScale = static_cast<float>(height)*m_scale.y; + m_screenImageHeight = m_toScreenScale; + m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio; + + float windowRatio = static_cast<float>(height)/static_cast<float>(width); + m_textureAspect = windowRatio / m_tex_aspectRatio; +} + +void UIDisplay::setPos(glm::vec2 pos){ + m_pos = pos; + setTransformationMat(m_pos, m_scale); +} +void UIDisplay::setScale(glm::vec2 scale){ + m_scale = scale; + setTransformationMat(m_pos, m_scale); +} + +float UIDisplay::getTextureScaleAspect(){ + return m_textureAspect; +} + +glm::vec2 UIDisplay::getWindowPos(){ + return m_windowPos; +} + +int UIDisplay::getHeight(){ + return m_tex.height; +} +int UIDisplay::getWidth(){ + return m_tex.width; +} + +int UIDisplay::getScreenHeight(){ + return m_screenImageHeight; +} +int UIDisplay::getScreenWidth(){ + return m_screenImageWidth; +} + +glm::mat4 UIDisplay::getScaleMatrix(glm::vec2 scale) { + glm::mat4 M = glm::mat4(1.f); + M[0][0] = scale.x;//* (m_screenImageHeight/m_screenImageWidth); + M[1][1] = scale.y; //* (m_tex_aspectRatio); + M[2][2] = 1.f; + return M; +} + +void UIDisplay::setTransformationMat(glm::vec2 translation, glm::vec2 scale){ + glm::mat4 transMat = glm::mat4(1.f); + transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f); + + glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale)); + + m_transformationMat = transMat*scaleMat; +} + +glm::mat4 UIDisplay::getTransformationMat(){ + return m_transformationMat; +} + +// remember that origin is top left corner!! +Bounds2f UIDisplay::getBounds(){ + glm::vec2 halfDimensions = glm::vec2(m_screenImageWidth, m_screenImageHeight)*.5f; + m_bounds.max = glm::vec2(m_windowPos.x + halfDimensions.x, m_windowPos.y - halfDimensions.y); + m_bounds.min = glm::vec2(m_windowPos.x - halfDimensions.x, m_windowPos.y + halfDimensions.y); + return m_bounds; +} + +float UIDisplay::getTextureRatio(){ + return m_tex_aspectRatio; +} + + + + diff --git a/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h new file mode 100644 index 0000000..4b739cc --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h @@ -0,0 +1,67 @@ +#ifndef UIDISPLAY_H +#define UIDISPLAY_H +#include "uitexture.h" +#include <set> + + + +class UIDisplay : public UITexture +{ +public: + UIDisplay(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens, + AspectRatio ratio = FIT_SCREEN); + ~UIDisplay(); + void draw() override; + GLuint getTexID() override; + glm::vec2 getPos() override; + glm::vec2 getScale() override; + + void setWindowPos(int width, int height) override; + glm::vec2 getWindowPos(); + + int getHeight() override; + int getWidth() override; + Bounds2f getBounds() override; + float getTextureRatio() override; + float getTextureScaleAspect() override; + void setPos(glm::vec2 pos); + void setScale(glm::vec2 scale); + + AspectRatio getAspectRatio(); + + + // glm::vec2 getCornerPos(CornerPosition corner, glm::vec2 elementDimensions); + void setTransformationMat(glm::vec2 translation, glm::vec2 scale); + glm::mat4 getTransformationMat(); + +private: + int getScreenHeight(); + int getScreenWidth(); + void setTexID(GLuint &newTexID); + glm::mat4 getScaleMatrix(glm::vec2 scale); + + + + TextureData m_tex; + glm::vec2 m_pos; + glm::vec2 m_scale; + Bounds2f m_bounds; + glm::vec2 m_windowPos; // width, height + int m_windowHeight = 480.f; + int m_windowWidth = 640.f; + float m_toScreenScale = 1.f; + + int m_screenImageHeight; + int m_screenImageWidth; + float m_tex_aspectRatio = 1.f; + bool m_isCloseButton = false; + std::string m_attachedWindow; + + std::set<std::string>& m_shownScreens; + glm::mat4 m_transformationMat; + float m_textureAspect = 1.f; + + AspectRatio m_aspectRatio; +}; + +#endif // UIDISPLAY_H diff --git a/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp b/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp new file mode 100644 index 0000000..8680baf --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp @@ -0,0 +1,6 @@ +#include "uitexture.h" + +UITexture::UITexture() +{ + +} diff --git a/engine-ocean/Game/Systems/UI/UITextures/uitexture.h b/engine-ocean/Game/Systems/UI/UITextures/uitexture.h new file mode 100644 index 0000000..53e429d --- /dev/null +++ b/engine-ocean/Game/Systems/UI/UITextures/uitexture.h @@ -0,0 +1,39 @@ +#ifndef UITEXTURE_H +#define UITEXTURE_H +#include "Graphics/global.h" +#include <GLFW/glfw3.h> + +struct Bounds2f{ + glm::vec2 min; + glm::vec2 max; +}; + +enum AspectRatio { + LAND_FIT, + LAND_FILL, + PORTRAIT_FIT, + PORTRAIT_FILL, + FIT_SCREEN +}; + +class UITexture +{ +public: + UITexture(); + virtual void draw() = 0; + virtual GLuint getTexID() = 0; + virtual glm::vec2 getPos() = 0; + virtual glm::vec2 getScale() = 0; + virtual int getHeight() = 0; + virtual int getWidth() = 0; + virtual Bounds2f getBounds() = 0; + virtual void setWindowPos(int width, int height) = 0; + virtual float getTextureRatio() = 0; + virtual float getTextureScaleAspect() = 0; + + + + +}; + +#endif // UITEXTURE_H diff --git a/engine-ocean/Game/Systems/UI/uielement.cpp b/engine-ocean/Game/Systems/UI/uielement.cpp new file mode 100644 index 0000000..bb7d91f --- /dev/null +++ b/engine-ocean/Game/Systems/UI/uielement.cpp @@ -0,0 +1,6 @@ +#include "uielement.h" + +UIElement::UIElement() +{ + +} diff --git a/engine-ocean/Game/Systems/UI/uielement.h b/engine-ocean/Game/Systems/UI/uielement.h new file mode 100644 index 0000000..c2c3a2e --- /dev/null +++ b/engine-ocean/Game/Systems/UI/uielement.h @@ -0,0 +1,40 @@ +#ifndef UIELEMENT_H +#define UIELEMENT_H + + +#include "Game/Systems/UI/UITextures/uitexture.h" +#include "Game/TypeMap.h" +#include <memory> +class UIElement +{ +public: + UIElement(); + + template <typename T> + void addComponent(std::unique_ptr<T> &&component){ + m_components.put<T>(std::forward<std::unique_ptr<T>>(component)); + } + + template <typename T> + bool hasComponent(){ + return m_components.contains<T>(); + } + + template <class T> + T* getComponent(){ + auto comp = m_components.find<T>(); + assert(comp != m_components.end()); + return static_cast<T*>(comp->second.get()); + } + + template <class T> + void removeComponent(){ + m_components.remove<T>(); + } + +private: + + TypeMap<std::unique_ptr<UITexture>> m_components; +}; + +#endif // UIELEMENT_H diff --git a/engine-ocean/Game/Systems/UI/uisystem.cpp b/engine-ocean/Game/Systems/UI/uisystem.cpp new file mode 100644 index 0000000..09aff49 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/uisystem.cpp @@ -0,0 +1,383 @@ +#include "uisystem.h" +#include "Game/GameWorld.h" +#include "Game/Systems/UI/ButtonAction/showwindowaction.h" +#include "Game/Systems/UI/UITextures/UIButton.h" +#include "Game/Systems/UI/UITextures/uidisplay.h" +#define GLFW_POINTING_HAND_CURSOR + +UISystem::UISystem(std::shared_ptr<Camera> camera, + std::map<int, Input>& input_map, + std::set<std::string>& shownScreens): + m_camera(camera), + m_input_map(input_map), + m_shownScreens(shownScreens) +{ + + + initializeStartScreen(); + initializeScreenMap(); + //m_pointerCursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR); + +} + +UISystem::~UISystem(){ + for (auto &screenID : m_all_screens){ + glDeleteVertexArrays(1, &screenID.second->screenVAOID); + } +} + +void UISystem::initializeScreenMap(){ + initializeProfileScreen(); + initializeInventory(); + initializeScreen(); + + m_shownScreens.insert("home"); + +} + +void UISystem::initializeScreen(){ + std::shared_ptr<UIScreen> home = std::make_shared<UIScreen>(); + home->isActive = true; + home->screenVAOID = Global::graphics.makeVAO(m_quadPos); + m_quad_numVertices = 4; + + float topLevel = .85f; + + makeButtonElement(home, "profileButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/profileicon.png", glm::vec2(.85f,topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL); + std::shared_ptr<ButtonAction> showProfile = std::make_shared<ShowWindowAction>(m_all_screens, m_shownScreens, "profile"); + home->screenElements.at("profileButton")->getComponent<UIButton>()->addButtonAction(showProfile); + + makeButtonElement(home, "inventoryButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventoryicon.png", glm::vec2(.75f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL); + std::shared_ptr<ButtonAction> showInv = std::make_shared<ShowWindowAction>(m_all_screens, m_shownScreens, "inventory"); + home->screenElements.at("inventoryButton")->getComponent<UIButton>()->addButtonAction(showInv); + + makeButtonElement(home, "questsButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/questicon.png", glm::vec2(.65f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL); + makeButtonElement(home, "settingsButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/settings_icon.png", glm::vec2(-.85f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL); + makeDisplayElement(home, "healthbar", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/healthbar.png", glm::vec2(0.f, -.5f), glm::vec2(.4f), AspectRatio::LAND_FIT); + +// TextureData reflectTex; +// reflectTex.textureID = Global::graphics.getReflectionTexture(); +// reflectTex.width = Global::graphics.REFLECTION_W; +// reflectTex.height = Global::graphics.REFLECTION_H; +// makeDisplayElement(home, "reflection", reflectTex, glm::vec2(.5f, -.5f), glm::vec2(.3f), AspectRatio::LAND_FIT); + +// TextureData refractTex; +// refractTex.textureID = Global::graphics.getRefractionTexture(); +// refractTex.width = Global::graphics.REFRACTION_W; +// refractTex.height = Global::graphics.REFRACTION_H; +// makeDisplayElement(home, "refract", refractTex, glm::vec2(-.5f, -.5f), glm::vec2(.3f), AspectRatio::LAND_FIT); + + + + + home->elementsDepthOrder.push_back("profileButton"); + home->elementsDepthOrder.push_back("inventoryButton"); + home->elementsDepthOrder.push_back("questsButton"); + home->elementsDepthOrder.push_back("settingsButton"); + home->elementsDepthOrder.push_back("healthbar"); + // home->elementsDepthOrder.push_back("reflection"); + // home->elementsDepthOrder.push_back("refract"); + + + + m_all_screens.insert({"home", home}); +} + +void UISystem::initializeProfileScreen(){ + + std::shared_ptr<UIScreen> profile = std::make_shared<UIScreen>(); + profile->isActive = false; + profile->screenVAOID = Global::graphics.makeVAO(m_quadPos); + m_quad_numVertices = 4; + + float topLevel = .85f; + + // eventually should be display, not button + makeDisplayElement(profile, "bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_bg.png", glm::vec2(0.f), glm::vec2(1.0f)); + makeDisplayElement(profile, "profileDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse_profile.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT); + makeButtonElement(profile, "closeButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/close_icon.png", glm::vec2(0.f), glm::vec2(.05f), AspectRatio::LAND_FILL, true, CornerPosition::TOPRIGHT); + profile->screenElements.at("closeButton")->getComponent<UIButton>()->setWindowToClose("profile"); + + profile->elementsDepthOrder.push_back("bg"); + profile->elementsDepthOrder.push_back("profileDisplay"); + profile->elementsDepthOrder.push_back("closeButton"); + + m_all_screens.insert({"profile", profile}); +} + +void UISystem::initializeInventory(){ + std::shared_ptr<UIScreen> inv = std::make_shared<UIScreen>(); + inv->isActive = false; + inv->screenVAOID = Global::graphics.makeVAO(m_quadPos); + m_quad_numVertices = 4; + + makeDisplayElement(inv, "bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_bg.png", glm::vec2(0.f), glm::vec2(1.0f)); + makeDisplayElement(inv, "inventoryDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_page.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT); + makeButtonElement(inv, "closeButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/close_icon.png", glm::vec2(0.f), glm::vec2(.05f), AspectRatio::LAND_FILL, true, CornerPosition::TOPRIGHT); + inv->screenElements.at("closeButton")->getComponent<UIButton>()->setWindowToClose("inventory"); + inv->elementsDepthOrder.push_back("bg"); + inv->elementsDepthOrder.push_back("inventoryDisplay"); + inv->elementsDepthOrder.push_back("closeButton"); + + m_all_screens.insert({"inventory", inv}); +} + +void UISystem::initializeStartScreen(){ + + std::shared_ptr<UIScreen> start = std::make_shared<UIScreen>(); + start->isActive = true; + start->screenVAOID = Global::graphics.makeVAO(m_quadPos); + + float topLevel = .85f; + + // eventually should be display, not button + makeDisplayElement(start, "startDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/title.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT); + makeButtonElement(start, "startButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/enterbutton.png", glm::vec2(0.f, -.57f), glm::vec2(.19f), AspectRatio::LAND_FIT, true); + start->screenElements.at("startButton")->getComponent<UIButton>()->setWindowToClose("start"); + + start->elementsDepthOrder.push_back("startDisplay"); + start->elementsDepthOrder.push_back("startButton"); + + m_all_screens.insert({"start", start}); + m_shownScreens.insert("start"); +} + +glm::vec2 UISystem::drawAspect(AspectRatio aspectType, float textureAspect){ + switch(aspectType){ + case FIT_SCREEN: + return glm::vec2(1.f); + break; + case LAND_FIT:case PORTRAIT_FILL: + return glm::vec2(1.f, textureAspect); + break; + case LAND_FILL: case PORTRAIT_FIT: + return glm::vec2(1.f/textureAspect, 1.f); + break; + } +} + + + +void UISystem::makeButtonElement(std::shared_ptr<UIScreen> &screen, + std::string elementName, const char* filename, + const glm::vec2 pos, const glm::vec2 scale, + AspectRatio aspectRatio, + bool isCloseButton, + CornerPosition corner){ + TextureData tex = Global::graphics.loadTextureFromFile(filename); + + std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>(); + + uiElement->addComponent<UIButton>(std::make_unique<UIButton>(tex, pos, scale, m_shownScreens, isCloseButton, corner, aspectRatio)); + screen->screenElements.insert({elementName, uiElement}); +} + +void UISystem::makeDisplayElement(std::shared_ptr<UIScreen> &screen, + std::string elementName, const char* filename, + const glm::vec2 pos, const glm::vec2 scale, + AspectRatio aspectRatio){ + TextureData tex = Global::graphics.loadTextureFromFile(filename); + + std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>(); + uiElement->addComponent<UIDisplay>(std::make_unique<UIDisplay>(tex, pos, scale, m_shownScreens, aspectRatio)); + screen->screenElements.insert({elementName, uiElement}); +} + +void UISystem::makeDisplayElement(std::shared_ptr<UIScreen> &screen, + std::string elementName, TextureData &tex, + const glm::vec2 pos, const glm::vec2 scale, + AspectRatio aspectRatio){ + + std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>(); + uiElement->addComponent<UIDisplay>(std::make_unique<UIDisplay>(tex, pos, scale, m_shownScreens, aspectRatio)); + screen->screenElements.insert({elementName, uiElement}); +} + +void UISystem::renderScreen(){ + // bind shader + Global::graphics.bindShader("ui"); + + // for window resizing + Global::graphics.setCameraData(m_camera); + + // enable alpha blending + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // disable depth testing + glDisable(GL_DEPTH_TEST); + + for (auto &screenID : m_shownScreens){ + // bind quad + glBindVertexArray(m_all_screens[screenID]->screenVAOID); + glEnableVertexAttribArray(0); + + // loop through inventory ui elements + + // loop through ui elements + for (auto &gui: m_all_screens[screenID]->elementsDepthOrder){ + if (m_all_screens[screenID]->screenElements[gui]->hasComponent<UIDisplay>()){ + GLuint texID; + if (gui == "reflection"){ + //std::cout << "rendering reflection" << std::endl; + texID = Global::graphics.getReflectionTexture(); + } else if (gui == "refract"){ + texID = Global::graphics.getRefractionTexture(); + } else { + texID = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTexID(); + } + glm::mat4 transMat = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTransformationMat(); + float texAspect = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTextureScaleAspect(); + AspectRatio ratio = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getAspectRatio(); + + glActiveTexture(GL_TEXTURE5); + glBindTexture(GL_TEXTURE_2D, texID); + + glm::vec2 texScale = drawAspect(ratio, texAspect); + + glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("ui"), "textureScale"), texScale.x, texScale.y); + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("ui"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0])); + glDrawArrays(GL_TRIANGLE_STRIP, 0, m_quad_numVertices); + } + if (m_all_screens[screenID]->screenElements[gui]->hasComponent<UIButton>()){ + GLuint texID = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTexID(); + glm::mat4 transMat = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTransformationMat(); + float texAspect = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTextureScaleAspect(); + AspectRatio ratio = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getAspectRatio(); + + glActiveTexture(GL_TEXTURE5); + glBindTexture(GL_TEXTURE_2D, texID); + + glm::vec2 texScale = drawAspect(ratio, texAspect); + + glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("ui"), "textureScale"), texScale.x, texScale.y); + glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("ui"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0])); + glDrawArrays(GL_TRIANGLE_STRIP, 0, m_quad_numVertices); + + + } + + } + glDisableVertexAttribArray(0); + glBindVertexArray(0); + } + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); +} + + + +void UISystem::draw(){ + renderScreen(); +} + +glm::mat4 UISystem::getScaleMatrix(glm::vec2 scale) { + glm::mat4 M = glm::mat4(1.f); + M[0][0] = scale.x * (m_aspectRatio); + M[1][1] = scale.y; + M[2][2] = 0.f; + return M; +} + +glm::mat4 UISystem::makeTransformationMat(glm::vec2 translation, glm::vec2 scale){ + glm::mat4 transMat = glm::mat4(1.f); + transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f); + + glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale)); + + return transMat*scaleMat; +} + +void UISystem::update(double deltaTime){ + // allow for one more update cycle before deactivating click + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isClicked){ + // check if clicked inside gui + // only act on the front-most gui being clicked + std::set<std::string>::iterator it = m_shownScreens.begin(); + while(it != m_shownScreens.end()) { + std::set<std::string>::iterator current = it++; + std::string screenID = *current; + // render all active screens + if (m_all_screens[screenID]->isActive){ + // loop through ui elements + for (auto &gui: m_all_screens[screenID]->screenElements){ + if (gui.second->hasComponent<UIButton>()){ + bool isInside = false; + Bounds2f buttonBounds = gui.second->getComponent<UIButton>()->getBounds(); + isInside = checkInsideGUI(m_mousepos, buttonBounds); + if (isInside){ + bool toClose = gui.second->getComponent<UIButton>()->onButtonPress(); + if (toClose){ + m_shownScreens.erase(current); + + } + } + } + } + } + } + + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].checkClickTime > 1){ + m_input_map[GLFW_MOUSE_BUTTON_LEFT].isClicked = false; + } else { + m_input_map[GLFW_MOUSE_BUTTON_LEFT].checkClickTime ++; + } + } +} + +bool UISystem::checkInsideGUI(glm::vec2 mouseClickPos, Bounds2f guiBounds){ + if (mouseClickPos.x < guiBounds.max.x + && mouseClickPos.x > guiBounds.min.x + && mouseClickPos.y > guiBounds.max.y + && mouseClickPos.y < guiBounds.min.y){ + return true; + } + + return false; +} + + +void UISystem::scrollEvent(double distance){} + +void UISystem::mousePosEvent(double xpos, double ypos){ + m_mousepos = glm::vec2(xpos, ypos); + + for (auto &screenID : m_shownScreens){ + Global::graphics.bindShader("ui"); + //glUniform1i(glGetUniformLocation(Global::graphics.getShaderID("ui"), "hovering"), false); + // render all active screens + if (m_all_screens[screenID]->isActive){ + // loop through ui elements + for (auto &gui: m_all_screens[screenID]->screenElements){ + if (gui.second->hasComponent<UIButton>()){ + bool isInside; + Bounds2f buttonBounds = gui.second->getComponent<UIButton>()->getBounds(); + isInside = checkInsideGUI(m_mousepos, buttonBounds); + if (isInside){ + //glfwSetCursor(window, m_pointerCursor); + // hover effect + //glUniform1i(glGetUniformLocation(Global::graphics.getShaderID("ui"), "hovering"), true); + } + } + } + } + } +} + +void UISystem::onWindowResize(int width, int height){ + m_windowWidth = width; + m_windowHeight = height; + m_aspectRatio = static_cast<float>(m_windowHeight)/static_cast<float>(m_windowWidth); + + for (auto &screen : m_all_screens){ + // loop through ui elements + for (auto &gui: screen.second->screenElements){ + if (gui.second->hasComponent<UIButton>()){ + gui.second->getComponent<UIButton>()->setWindowPos(width, height); + } + if (gui.second->hasComponent<UIDisplay>()){ + gui.second->getComponent<UIDisplay>()->setWindowPos(width, height); + } + } + } +} diff --git a/engine-ocean/Game/Systems/UI/uisystem.h b/engine-ocean/Game/Systems/UI/uisystem.h new file mode 100644 index 0000000..1094861 --- /dev/null +++ b/engine-ocean/Game/Systems/UI/uisystem.h @@ -0,0 +1,89 @@ +#ifndef UISYSTEM_H +#define UISYSTEM_H +#include "Game/GameWorld.h" +#include "Game/Systems/UI/UITextures/UIButton.h" +#include "Game/Systems/UI/UITextures/uitexture.h" +#include "Game/Systems/UI/uielement.h" +#include "Graphics/global.h" +#include <GLFW/glfw3.h> +#include "Game/Systems/system.h" + +struct UIScreen{ + bool isActive = false; + GLuint screenVAOID; + std::map<std::string, std::shared_ptr<UIElement>> screenElements; + std::vector<std::string> elementsDepthOrder; +}; + + +class UISystem : public System +{ +public: + UISystem(std::shared_ptr<Camera> camera, + std::map<int, Input>& input_map, + std::set<std::string>& shownScreens); + ~UISystem(); + + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + void onWindowResize(int width, int height); + GLuint makeVAO(std::vector<float> positions); + +private: + + int m_quad_numVertices = 4; + + void initializeScreenMap(); + void initializeScreen(); + void initializeStartScreen(); + void initializeInventory(); + + + void renderScreen(); + glm::mat4 makeTransformationMat(glm::vec2 translation, glm::vec2 scale); + glm::mat4 getScaleMatrix(glm::vec2 scale); + bool checkInsideGUI(glm::vec2 mouseClickPos, Bounds2f guiBounds); + void initializeProfileScreen(); + + + void makeButtonElement(std::shared_ptr<UIScreen> &screen, std::string elementName, const char* filename, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio, bool isCloseButton = false, CornerPosition corner = NONE); + void makeDisplayElement(std::shared_ptr<UIScreen> &screen, std::string elementName, const char* filename, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio = FIT_SCREEN); + void makeDisplayElement(std::shared_ptr<UIScreen> &screen, std::string elementName, TextureData &tex, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio = FIT_SCREEN); + + + + std::shared_ptr<Camera> m_camera; + float m_windowWidth = 640; + float m_windowHeight = 480; + float m_aspectRatio = 480.f/640.f; + + glm::vec2 m_mousepos = glm::vec2(0.f); + std::map<int, Input>& m_input_map; + + std::map<std::string, std::shared_ptr<UIScreen>> m_all_screens; + + GLFWcursor* m_pointerCursor; + + std::shared_ptr<ButtonAction> showProfileAction; + + std::set<std::string>& m_shownScreens; + float m_showStartScreen = true; + + + float dim = 1.0f; + std::vector<float> m_quadPos = { + -1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f + }; + + glm::vec2 drawAspect(AspectRatio aspectType, float textureAspect); + + + +}; + +#endif // UISYSTEM_H diff --git a/engine-ocean/Game/Systems/aisystem.cpp b/engine-ocean/Game/Systems/aisystem.cpp new file mode 100644 index 0000000..e3328ed --- /dev/null +++ b/engine-ocean/Game/Systems/aisystem.cpp @@ -0,0 +1,6 @@ +#include "aisystem.h" + +AISystem::AISystem() +{ + +} diff --git a/engine-ocean/Game/Systems/aisystem.h b/engine-ocean/Game/Systems/aisystem.h new file mode 100644 index 0000000..fe0b958 --- /dev/null +++ b/engine-ocean/Game/Systems/aisystem.h @@ -0,0 +1,36 @@ +#ifndef AISYSTEM_H +#define AISYSTEM_H + + +// where is player? +#include "Game/GameObjects/GameObject.h" +#include <map> +#include <memory> +#include <glm/glm.hpp> + + +struct PosData{ + glm::vec3 currPos; + glm::vec3 setToPos; +}; + +// did player jump? did player slash? +struct ConditionData{ + bool conditionTrue = false; +}; + +// BLACKBOARD +struct BlackboardData{ + PosData locationData; + std::map<std::string, ConditionData> conditionData; + std::shared_ptr<GameObject> environment; +}; + + +class AISystem +{ +public: + AISystem(); +}; + +#endif // AISYSTEM_H diff --git a/engine-ocean/Game/Systems/camerasystem.cpp b/engine-ocean/Game/Systems/camerasystem.cpp new file mode 100644 index 0000000..7951e35 --- /dev/null +++ b/engine-ocean/Game/Systems/camerasystem.cpp @@ -0,0 +1,210 @@ +#include "camerasystem.h" +#include "Game/Components/TransformComponent.h" +#include "Game/GameWorld.h" +#include <memory> +#include <math.h> + + +CameraSystem::CameraSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::shared_ptr<Camera>& camera, + std::map<int, Input>& input_map): + m_gameobjects(gameobjects), + m_camera(camera), + m_input_map(input_map), + first_person(false), + third_person(true), + m_player(m_gameobjects["player"]) +{ + camera->setPos(glm::vec3(0.f, 15.f, 0.f)); + camera->setLook(glm::vec3(-28.6761,5.40863,46.5823)); + + +} + +glm::vec3 CameraSystem::calculateIdealOffset(glm::vec3 initial){ + //glm::quat playerRotation = glm::quat( +// float y_rotate = m_player->getComponent<TransformComponent>()->getYRotationAngle(); +// glm::quat playerRot = glm::angleAxis(y_rotate, glm::vec3(0.f, 1.f, 0.f)); + glm::vec4 idealOffset = glm::vec4(initial, 0.f); + + glm::vec4 rotatedOffset = m_player->getComponent<TransformComponent>()->getMT()->getRotation() * idealOffset * .2f; + glm::vec3 rotated = glm::vec3(rotatedOffset) + m_player->getComponent<TransformComponent>()->getPos(); + + return rotated; +} + +void CameraSystem::update(double deltaTime){ + if (m_gameobjects["player"]->getComponent<TransformComponent>()->movingLaterally){ + glm::vec3 player_pos = m_gameobjects["player"]->getComponent<TransformComponent>()->getPos(); + + + glm::vec4 movement = m_distance*glm::vec4(1.f,0.f,0.f, 0.f); + glm::vec4 transl = m_gameobjects["player"]->getComponent<TransformComponent>()->getMT()->getRotation()*movement; + transl.y = 0.f; + + glm::vec3 offset = glm::vec3(0.f, 5.f, 0.f); + glm::vec3 newPos = player_pos + glm::vec3(transl) + offset; + + // arcballRotation(newPos.x, newPos.z); + m_camera->setPos(newPos); + + if (glm::cross(m_camera->getUp(), player_pos) != glm::vec3(0.f)){ + m_camera->setLook(player_pos); + } + } +} + + +void CameraSystem::draw(){ + Global::graphics.bindShader("phong"); + Global::graphics.setCameraData(m_camera); +} + +void CameraSystem::firstPersonMode(){ + first_person = true; + third_person = false; + m_camera->setPos(m_gameobjects["player"]->getComponent<TransformComponent>()->getPos()); +} + +void CameraSystem::thirdPersonMode(glm::vec3 curr_cam_pos){ + first_person = false; + third_person = true; + //camera->setPos(curr_cam_pos); +} + +void CameraSystem::scrollEvent(double distance){ + // calculateZoom(distance); +// m_distance += distance; +// if (m_distance < 5.f) m_distance = 5.f; +// if (m_distance > 40.f) m_distance = 40.f; +} + +void CameraSystem::mousePosEvent(double xpos, double ypos){ + + // if right mouse button is pressed, calculate change of the new input x and y pos + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){ + float deltaX = xpos - prev_mouse_pos.x; + float deltaY = ypos - prev_mouse_pos.y; + + // upate prev mouse pos + prev_mouse_pos = glm::vec2(xpos, ypos); + + arcballRotation(deltaX, deltaY); + + } +} + +void CameraSystem::calculateZoom(float scrollDistance){ + float zoomLevel = scrollDistance*.1f; + m_distanceFromPlayer -= zoomLevel; +} + +void CameraSystem::calculatePitch(double deltaY){ + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){ + float pitchChange = deltaY*.1f; + m_pitch -= pitchChange; + } +} + +void CameraSystem::calculateAngleAroundPlayer(double deltaX){ + if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){ + float angleChange = deltaX*.3f; + m_angleAroundPlayer -= angleChange; + } +} + +void CameraSystem::arcballRotation(float deltaX, float deltaY){ + glm::vec4 cam_pos = glm::vec4(m_camera->getPos(), 1.f); + glm::vec4 pivot = glm::vec4(m_player->getComponent<TransformComponent>()->getPos(), 1.f); + + // calculate rotation amount given mouse movement + float deltaAngleX = (2*M_PI / static_cast<float>(m_camera->getWidth())); + float deltaAngleY = (M_PI / static_cast<float>(m_camera->getHeight())); + + float xAngle = deltaX * deltaAngleX; + float yAngle = deltaY * deltaAngleY; + + // handles when camera dir is same as up vector + float cosAngle = glm::dot(m_camera->getViewDirection(), m_camera->getUp()); + float sign = 1.f; + if (yAngle < 0) sign = -1.f; + if (cosAngle * sign > .99f) yAngle = 0; + + // rotate camera around pivtor point + glm::mat4 rotX(1.f); + rotX = glm::rotate(rotX, xAngle, m_camera->getUp()); + cam_pos = (rotX * (cam_pos - pivot)) + pivot; + + glm::mat4 rotY(1.f); + rotY = glm::rotate(rotY, yAngle, m_camera->getRight()); + glm::vec3 final_pos = (rotY * (cam_pos - pivot)) + pivot; + + // update camera view + m_camera->setPos(final_pos); + +} + +void CameraSystem::setCameraPos(){ +// float horiz_distance = m_distanceFromPlayer*glm::cos(glm::radians(m_pitch)); +// float vert_distance = m_distanceFromPlayer*glm::sin(glm::radians(m_pitch)); + +// glm::vec3 player_pos = m_gameobjects["player"]->getComponent<TransformComponent>()->getPos(); +// float y_camPos = player_pos.y + vert_distance; + +// float theta = glm::radians(m_angleAroundPlayer); +// float offsetX = horiz_distance*glm::cos((theta)); +// float offsetZ = horiz_distance*glm::sin((theta)); + +// glm::vec3 camPos = glm::vec3(player_pos.x - offsetX, y_camPos, player_pos.z - offsetZ); + + // m_yaw = glm::radians(180-theta); + +// glm::vec3 lookVector = camPos + +// glm::vec3(glm::cos(pitch)*glm::sin(m_yaw), glm::sin(pitch), glm::cos(pitch)*glm::cos(m_yaw)); + + +// glm::vec4 distanceCamToPlayer = glm::vec4(camPos - player_pos, 0.f); +// glm::vec4 look = m_gameobjects["player"]->getComponent<TransformComponent>()->getMT()->getRotation() * distanceCamToPlayer; + +// //glm::vec3 idealOffset = (glm::vec3(-7.f, 5.f, -10.f)) + m_player->getComponent<TransformComponent>()->getPos(); +// glm::vec3 idealLookat = calculateIdealOffset(glm::vec3(0.f, -2.f, 40.f)); + +// m_currPos = idealOffset; +// m_currLook = idealLookat; + +// glm::vec3 direction; +// direction.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch)); +// direction.y = sin(glm::radians(m_pitch)); +// direction.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch)); + +// // calculate look +// glm::vec4 rotatedPlayerPoint = m_player->getComponent<TransformComponent>()->getMT()->getRotation()* glm::vec4(player_pos, 1.f); +// float distanceX = glm::distance(rotatedPlayerPoint.x, player_pos.x); +// float distanceY = glm::distance(rotatedPlayerPoint.y, player_pos.y); +// float distanceZ = glm::distance(rotatedPlayerPoint.z, player_pos.z); + + + + //camPos = camPos + glm::vec3(distanceX, distanceY, distanceZ); + //glm::vec3 newLook = camPos - player_pos; + + + + // glm::vec4 lookToPlayer = glm::vec4(camPos - player_pos, 0.f); + // glm::vec4 rotatedLook = m_player->getComponent<TransformComponent>()->getMT()->getRotation() * lookToPlayer; + // float distLookToPlayer = glm::distance(glm::vec3(rotatedLook), player_pos); + + + // m_camera->setPos(camPos); + //m_camera->translate(m_currPos); + //m_camera->rotate(m_yaw, glm::vec3(0.f, 1.f, 0.f)); + //m_camera->setLook(newLook); + + + // m_camera->setPos(glm::vec3(x_camPos, y_camPos, z_camPos)); + + + + +} + diff --git a/engine-ocean/Game/Systems/camerasystem.h b/engine-ocean/Game/Systems/camerasystem.h new file mode 100644 index 0000000..3ee6928 --- /dev/null +++ b/engine-ocean/Game/Systems/camerasystem.h @@ -0,0 +1,74 @@ +#ifndef CAMERASYSTEM_H +#define CAMERASYSTEM_H + + +#include "Game/GameWorld.h" +#include "Graphics/camera.h" +#include <memory> +#include "system.h" + +class CameraSystem : public System +{ +public: + CameraSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::shared_ptr<Camera>& camera, + std::map<int, Input>& input_map); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + +private: + void firstPersonMode(); + void thirdPersonMode(glm::vec3 curr_cam_pos); + + void setCameraPos(); + void calculateAngleAroundPlayer(double deltaX); + void calculatePitch(double deltaY); + void calculateZoom(float scrollDistance); + + glm::vec3 calculateIdealOffset(glm::vec3 initial); + void arcballRotation(float deltaX, float deltaY); + float m_distance = -10.f; + + + + + + + + + + + std::shared_ptr<Camera>& m_camera; + std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects; + std::map<int, Input>& m_input_map; + bool first_person = false; + bool third_person = true; + float first_person_offset = 0.01f; + glm::vec2 prev_mouse_pos = glm::vec2(0.f); + float horiz_velocity = .005f; + + std::shared_ptr<GameObject> m_player; + float m_distanceFromPlayer = 50.f; + float m_angleAroundPlayer = 0.f; + float m_pitch = 20.f; + float m_yaw = 0.f; + + bool m_isInverted = false; + float m_angle = 0.f; + float m_height = 0.f; + int m_invertY = 1; + + glm::vec3 m_currPos; + glm::vec3 m_currLook; + + float m_currentTurnSpeed = 0.f; + + float TURN_SPEED = 2.f; + float snapshot_time = 0.f; + + +}; + +#endif // CAMERASYSTEM_H diff --git a/engine-ocean/Game/Systems/charactercontrollersystem.cpp b/engine-ocean/Game/Systems/charactercontrollersystem.cpp new file mode 100644 index 0000000..c5e7174 --- /dev/null +++ b/engine-ocean/Game/Systems/charactercontrollersystem.cpp @@ -0,0 +1,132 @@ +#include "charactercontrollersystem.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/CylinderCollider.h" +#include "Game/Components/TransformComponent.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include <glm/gtx/quaternion.hpp> + +CharacterControllerSystem::CharacterControllerSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::shared_ptr<Camera>& camera_param, + std::map<int, Input>& input_map, + std::map<std::string, BlackboardData>& global_blackboard): + m_gameobjects(gameobjects), + camera(camera_param), + m_input_map(input_map), + m_global_blackboard(global_blackboard) +{ +} + +void CharacterControllerSystem::draw(){ +} + +TransformComponent* CharacterControllerSystem::getPlayerTransform(){ + return m_gameobjects.at("player")->getComponent<TransformComponent>(); +} + +glm::vec3 CharacterControllerSystem::getPlayerPos(){ + return m_gameobjects.at("player")->getComponent<TransformComponent>()->getPos(); +} + + +float CharacterControllerSystem::jumpPlayer(float &initial_v, double deltaTime, float snapshot_time, float gravity){ + float t = deltaTime-snapshot_time; + float delta_y = initial_v*t + (.5f)*gravity*t*t; + return delta_y; +} + +bool CharacterControllerSystem::movePlayerLaterally(glm::vec3 dir, glm::vec3 perp, glm::vec3 &m_pos, float dt){ + glm::vec3 translationDir; + bool moving_laterally = false; + std::shared_ptr<ModelTransform> temp_mt = getPlayerTransform()->getMT(); + + if (m_input_map[GLFW_KEY_W].isActive){ + m_currentSpeed = RUN_SPEED; + moving_laterally = true; + } else if (m_input_map[GLFW_KEY_S].isActive){ + m_currentSpeed = -RUN_SPEED; + moving_laterally = true; + } else { + m_currentSpeed = 0.f; + } + + + glm::mat4 rot = glm::mat4(1.f); + // player turning + if (m_input_map[GLFW_KEY_D].isActive){ + m_currentTurnSpeed = -TURN_SPEED; + moving_laterally = true; + } else if (m_input_map[GLFW_KEY_A].isActive){ + m_currentTurnSpeed = TURN_SPEED; + moving_laterally = true; + } else { + m_currentTurnSpeed = 0.f; + } + + // rotate player + getPlayerTransform()->getMT()->rotate(m_currentTurnSpeed*dt, glm::vec3(0.f, 1.f, 0.f)); + + + //translate player based on rotation + float distance = m_currentSpeed*dt; + glm::vec4 movement = distance*glm::vec4(1.f,0.f,0.f, 0.f); + glm::vec4 transl = getPlayerTransform()->getMT()->getRotation()*movement; + + translationDir = glm::vec3(transl.x, 0.f, transl.z); + temp_mt->translate(translationDir); + glm::vec3 potential_pos = temp_mt->getPos(); + m_pos = potential_pos; + + + return moving_laterally; +} + +void CharacterControllerSystem::handlePlayerMovement(double deltaTime){ + // timing + float dt = deltaTime - snapshot_time; + snapshot_time = deltaTime; + + // get player positions + m_pos = getPlayerPos(); + getPlayerTransform()->old_pos = m_pos; + + // movement + getPlayerTransform()->movingLaterally = false; + float speedFactor = horiz_velocity * deltaTime; + glm::vec3 look = camera->getLook(); + glm::vec3 dir = glm::normalize(glm::vec3(look.x, 0.f, look.z)) * speedFactor; + glm::vec3 perp = glm::vec3(look.z, 0.f, -look.x) * speedFactor; + + // updates m_pos + if (movePlayerLaterally(dir, perp, m_pos, dt)){ + getPlayerTransform()->movingLaterally = true; + } + + if (m_input_map[GLFW_KEY_SPACE].isActive && (getPlayerTransform()->onGround)){ + getPlayerTransform()->gravity = -25.f; + getPlayerTransform()->yVelocity = 20.f; + getPlayerTransform()->onGround = false; + //if (!gravity) gravity = true; + m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = true; + } else if (!m_input_map[GLFW_KEY_SPACE].isActive && getPlayerTransform()->onGround){ + m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = false; + } + + // PLAYER-SPECIFIC GRAVITY (comment these two lines to keep player still) + //if (gravity){ + m_pos.y += jumpPlayer(getPlayerTransform()->yVelocity, dt, 0, getPlayerTransform()->gravity); + getPlayerTransform()->yVelocity = getPlayerTransform()->yVelocity + getPlayerTransform()->gravity*(dt); + //} + + // store m_pos as estimated final_pos + m_global_blackboard["player"].locationData.setToPos = m_pos; + + getPlayerTransform()->estimated_final_pos = m_pos; +} + + +void CharacterControllerSystem::update(double deltaTime){ + handlePlayerMovement(deltaTime); +} + +void CharacterControllerSystem::scrollEvent(double distance){} +void CharacterControllerSystem::mousePosEvent(double xpos, double ypos){} diff --git a/engine-ocean/Game/Systems/charactercontrollersystem.h b/engine-ocean/Game/Systems/charactercontrollersystem.h new file mode 100644 index 0000000..04dd02f --- /dev/null +++ b/engine-ocean/Game/Systems/charactercontrollersystem.h @@ -0,0 +1,62 @@ +#ifndef CHARACTERCONTROLLERSYSTEM_H +#define CHARACTERCONTROLLERSYSTEM_H + + +#include "Game/Components/TransformComponent.h" +#include "Game/GameObjects/GameObject.h" +#include "Game/GameWorld.h" +#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h" +#include <map> + + + +class CharacterControllerSystem : public System +{ +public: + CharacterControllerSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::shared_ptr<Camera>& camera_param, + std::map<int, Input>& input_map, + std::map<std::string, BlackboardData>& global_blackboard); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + +private: + bool movePlayerLaterally(glm::vec3 dir, glm::vec3 perp, glm::vec3 &m_pos, float dt); + void handlePlayerMovement(double deltaTime); + TransformComponent* getPlayerTransform(); + + std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects; + std::shared_ptr<Camera>& camera; + std::map<int, Input>& m_input_map; + + void movePlayer(glm::vec3 direction, int key); + void setPlayerPos(glm::vec3 new_pos); + glm::vec3 getPlayerPos(); + float jumpPlayer(float &initial_v, double deltaTime, float snapshot_time, float gravity); + + + glm::vec3 m_pos = glm::vec3(0.f); + float horiz_velocity = .005f; + float snapshot_time = 0.f; + + std::map<std::string, BlackboardData>& m_global_blackboard; + + float m_currentSpeed = 0.f; + float m_currentTurnSpeed = 0.f; + + float RUN_SPEED = 8.f; + float TURN_SPEED = 2.f; + + glm::quat m_quat; + glm::vec3 m_axis; + + float HALFPI = 0.78539f; + bool gravity = false; + + + +}; + +#endif // CHARACTERCONTROLLERSYSTEM_H diff --git a/engine-ocean/Game/Systems/drawsystem.cpp b/engine-ocean/Game/Systems/drawsystem.cpp new file mode 100644 index 0000000..ad6e17b --- /dev/null +++ b/engine-ocean/Game/Systems/drawsystem.cpp @@ -0,0 +1,60 @@ +#include "drawsystem.h" +#include "Game/Components/DrawComponent.h" +#include "Game/Components/TransformComponent.h" + +DrawSystem::DrawSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects): + m_gameobjects(gameobjects) +{ + + +} + +void DrawSystem::update(double deltaTime){} +// store all game objects and get draw components, draw + +void DrawSystem::draw(){ + Global::graphics.bindShader("phong"); + //std::cout << "IN DRAW SYSTEM" << std::endl; + + for (auto &pair: m_gameobjects){ + if (pair.second->hasComponent<DrawComponent>()){ + + DrawComponent *draw_comp = pair.second->getComponent<DrawComponent>(); + TransformComponent *transform_comp = pair.second->getComponent<TransformComponent>(); + if (transform_comp->hasMultipleMT()){ + if (draw_comp->objHasMaterial()){ + for (const std::shared_ptr<ModelTransform> &mt : transform_comp->getAllMT()){ + Global::graphics.drawShape(draw_comp->getShape(), mt, draw_comp->getMaterial()); + } + } else { + for (const std::shared_ptr<ModelTransform> &mt : transform_comp->getAllMT()){ + Global::graphics.drawShape(draw_comp->getShape(), mt); + } + } + } else { + // case: object is seperated by material + if (draw_comp->objHasMultipleShapes()){ + for (auto &shape : draw_comp->getShapesWithMaterials()){ + if (shape->hasMaterial()){ + Global::graphics.drawShape(shape, transform_comp->getMT(), shape->getShapeMaterial()); + } else { + Global::graphics.drawShape(shape, transform_comp->getMT()); + } + } + + } else { + if (draw_comp->objHasMaterial()){ + Global::graphics.drawShape(draw_comp->getShape(), transform_comp->getMT(), draw_comp->getMaterial()); + } else { + //std::cout << "draw shape: " << pair.first << std::endl; + Global::graphics.drawShape(draw_comp->getShape(), transform_comp->getMT()); + } + } + } + } + } + +} + +void DrawSystem::scrollEvent(double distance){} +void DrawSystem::mousePosEvent(double xpos, double ypos){} diff --git a/engine-ocean/Game/Systems/drawsystem.h b/engine-ocean/Game/Systems/drawsystem.h new file mode 100644 index 0000000..d1c8eb9 --- /dev/null +++ b/engine-ocean/Game/Systems/drawsystem.h @@ -0,0 +1,23 @@ +#ifndef DRAWSYSTEM_H +#define DRAWSYSTEM_H + + +#include "Game/GameObjects/GameObject.h" +#include <vector> +#include "system.h" + +class DrawSystem : public System +{ +public: + DrawSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + + +private: + std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects; +}; + +#endif // DRAWSYSTEM_H diff --git a/engine-ocean/Game/Systems/objectcreationsystem.cpp b/engine-ocean/Game/Systems/objectcreationsystem.cpp new file mode 100644 index 0000000..85241fe --- /dev/null +++ b/engine-ocean/Game/Systems/objectcreationsystem.cpp @@ -0,0 +1,161 @@ +#include "objectcreationsystem.h" +#include "Game/Components/CollisionComponents/CollisionComponent.h" +#include "Game/Components/CollisionComponents/boundingtriangle.h" +#include "Game/Components/DrawComponent.h" +#include "Game/Components/PathfindComponent.h" +#include "Game/Components/TransformComponent.h" +#include "Game/Ocean/ocean.h" + +#include <random> + +ObjectCreationSystem::ObjectCreationSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, BlackboardData>& global_blackboard, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables): + m_gameobjects(gameobjects), + m_dynamic_gameobjects(dynamic_gameobjects), + m_rigid_gameobjects(rigid_gameobjects), + m_global_blackboard(global_blackboard), + m_lootables(lootables) + +{ + initializeAllObjects(); +} + +void ObjectCreationSystem::initializeAllObjects(){ + + m_ground_level = -.5f; + initializePlayerObject(); + // initializeSlopedGround(); +// initializeGround(); +// initializeBackground(); + initOcean(); + + addLight(); +} + +void ObjectCreationSystem::initializeSlopedGround(){ + std::shared_ptr<GameObject> sloped_ground = std::make_shared<GameObject>(); + std::vector<glm::vec3> obj_data = Global::graphics.addShape("sloped_ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/floor.obj"); + + std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>(); + mt->setScale(1.f); + mt->setPos(glm::vec3(0.f)); + + sloped_ground->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShape("sloped_ground"))); + sloped_ground->getComponent<DrawComponent>()->addMaterial("grass_tedxxx", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mossyground.png"); + sloped_ground->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "sloped_ground", m_global_blackboard)); + sloped_ground->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt)); + + insertRigidObject("sloped_ground", sloped_ground); +} + +void ObjectCreationSystem::insertAnyObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){ + m_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj)); +} + +void ObjectCreationSystem::insertRigidObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){ + m_rigid_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj)); + insertAnyObject(name, game_obj); +} + +void ObjectCreationSystem::insertDynamicObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){ + m_dynamic_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj)); + insertAnyObject(name, game_obj); +} + +void ObjectCreationSystem::initializePlayerObject(){ + //std::shared_ptr<Shape> shape = Global::graphics.getShape("sphere"); + std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/mouse2-4.obj", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/mouse2-4.mtl", true); + std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>(); + mt->setScale(glm::vec3(.5f)); + mt->setPos(glm::vec3(0.f)); + + std::shared_ptr<GameObject> player = std::make_shared<GameObject>(); + + player->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("mouse"))); + player->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "player", m_global_blackboard, true)); + player->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("dynamic_mesh", mt, mt->getPos(), obj_data)); + + insertDynamicObject("player", player); +} + +void ObjectCreationSystem::initializeGround(){ + std::shared_ptr<GameObject> ground = std::make_shared<GameObject>(); + std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/meadow_ground.obj", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/meadow_ground.mtl", true); + + //std::vector<glm::vec3> obj_data = Global::graphics.addShape("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/testplane.obj"); + std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>(); + mt->setPos(glm::vec3(0.f, 0.f, 0.f)); + ground->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("ground"))); + ground->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "ground", m_global_blackboard)); + ground->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true)); + + insertRigidObject("ground", ground); +} + +void ObjectCreationSystem::initializeBackground(){ + std::shared_ptr<GameObject> bg = std::make_shared<GameObject>(); + + // "Snowy Mountain - Terrain" (https://skfb.ly/6RzJV) by artfromheath is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/). + std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_background.obj", + "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_background.mtl", true); + + //std::vector<glm::vec3> obj_data = Global::graphics.addShape("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/testplane.obj"); + std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>(); + mt->setPos(glm::vec3(0.f, 0.f, 0.f)); + bg->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("bg"))); + bg->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "bg", m_global_blackboard)); + bg->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true)); + + insertRigidObject("bg", bg); + +} + +void ObjectCreationSystem::initOcean(){ + m_ocean_shape = std::make_shared<GameObject>(); + + std::vector<glm::vec3> obj_data = Global::graphics.addShape_manual("ocean", m_ocean.get_vertices(), m_ocean.get_faces(), true); + + + std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>(); + mt->setScale(1.f); + mt->setPos(glm::vec3(0.f, 0.f, 0.f)); + m_ocean_shape->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShape("ocean"))); + m_ocean_shape->getComponent<DrawComponent>()->addMaterial("grass_tedxxx", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mossyground.png"); + + m_ocean_shape->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "ocean", m_global_blackboard)); + m_ocean_shape->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true)); + + insertRigidObject("ocean", m_ocean_shape); + + +} + + +void ObjectCreationSystem::addLight(){ + std::shared_ptr<Light> light1 = std::make_shared<Light>(LightType::DIRECTIONAL, glm::vec3(0,20,6.5)); + std::vector<std::shared_ptr<Light>> lights; + lights.push_back(light1); + + Global::graphics.bindShader("phong"); + Global::graphics.setLights(lights); +} + + +void ObjectCreationSystem::draw(){} +void ObjectCreationSystem::update(double deltaTime){ + std::cout << "update" << std::endl; + m_ocean.fft_prime(m_time); + Global::graphics.getShape("ocean")->updateVAO(m_ocean.get_vertices(), m_ocean.get_faces()); + m_time += m_timestep; + +} +void ObjectCreationSystem::scrollEvent(double distance){} +void ObjectCreationSystem::mousePosEvent(double xpos, double ypos){} + + + diff --git a/engine-ocean/Game/Systems/objectcreationsystem.h b/engine-ocean/Game/Systems/objectcreationsystem.h new file mode 100644 index 0000000..ce30cde --- /dev/null +++ b/engine-ocean/Game/Systems/objectcreationsystem.h @@ -0,0 +1,82 @@ +#ifndef OBJECTCREATIONSYSTEM_H +#define OBJECTCREATIONSYSTEM_H + + +#include "Game/GameObjects/GameObject.h" +#include "Game/Systems/aisystem.h" +#include "Game/Ocean/ocean.h" + +#include "system.h" + + +class ObjectCreationSystem : public System +{ +public: + ObjectCreationSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects, + std::map<std::string, BlackboardData>& global_blackboard, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + +private: + void initializeAllObjects(); + void initializePlayerObject(); + void initializeGroundObject(); + void initializeObstacle(); + void generateBamboo(); + void generateBall(glm::vec3 scale, glm::vec3 pos, int number); + void addObject_NoTransform(std::string shape_name, std::string obj_name, std::string filename); + void makeBVHDemo(); + void initializeBackground(); + void initOcean(); + + + + void makeLootable(std::string shapename, std::string filename, int count, glm::vec3 scale); + + + + + + void initializeCeilingMesh(); + void initializeSlopedGround(); + void initializeGround(); + void addLight(); + void makeNavMesh(); + + + + + void insertAnyObject(const std::string name, const std::shared_ptr<GameObject> &game_obj); + void insertDynamicObject(const std::string name, const std::shared_ptr<GameObject> &game_obj); + void insertRigidObject(const std::string name, const std::shared_ptr<GameObject> &game_obj); + + + + + std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects; + + std::map<std::string, BlackboardData>& m_global_blackboard; + + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables; + + + float m_groundBounds = 0.f; + float m_ground_level = 0.f; + + + ocean m_ocean; + std::shared_ptr<GameObject> m_ocean_shape; + double m_time = 0.0; + double m_timestep = .01; + + +}; + +#endif // OBJECTCREATIONSYSTEM_H diff --git a/engine-ocean/Game/Systems/physicssystem.cpp b/engine-ocean/Game/Systems/physicssystem.cpp new file mode 100644 index 0000000..cd70933 --- /dev/null +++ b/engine-ocean/Game/Systems/physicssystem.cpp @@ -0,0 +1,72 @@ +#include "physicssystem.h" +#include "Game/Components/TransformComponent.h" + +PhysicsSystem::PhysicsSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, BlackboardData>& global_blackboard, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables) : + m_dynamic_gameobjects(dynamic_gameobjects), + m_global_blackboard(global_blackboard), + m_lootables(lootables) + +{ + +} + +TransformComponent* PhysicsSystem::getTransform(std::shared_ptr<GameObject> &go){ + return go->getComponent<TransformComponent>(); +} + +float PhysicsSystem::gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity){ + float t = deltaTime-snapshot_time; + float delta_y = initial_v*t + (.5f)*gravity*t*t; + return delta_y; +} + + +void PhysicsSystem::update(double deltaTime){ + //std::cout << "physics" << std::endl; + float dt = deltaTime - snapshot_time; + snapshot_time = deltaTime; + + for (auto &go : m_dynamic_gameobjects){ + // player has its own physics + if (go.first != "player"){ + // position + glm::vec3 m_pos = getTransform(go.second)->getPos(); + getTransform(go.second)->old_pos = m_pos; + + // effect it by gravity + m_pos.y += gravitySimulation(getTransform(go.second)->yVelocity, dt, 0, getTransform(go.second)->gravity); + getTransform(go.second)->yVelocity = getTransform(go.second)->yVelocity + getTransform(go.second)->gravity*(dt); + + m_global_blackboard[go.first].locationData.setToPos = m_pos; + // store m_pos as estimated final_pos + getTransform(go.second)->estimated_final_pos = m_pos; + } + } + +// for (auto &lootGroup : m_lootables){ +// for (auto &loot : lootGroup.second){ +// // position +// glm::vec3 m_pos = getTransform(loot)->getPos(); +// getTransform(loot)->old_pos = m_pos; + +// // effect it by gravity +// m_pos.y += gravitySimulation(getTransform(loot)->yVelocity, dt, 0, getTransform(loot)->gravity); +// getTransform(loot)->yVelocity = getTransform(loot)->yVelocity + getTransform(loot)->gravity*(dt); + +// // store m_pos as estimated final_pos +// getTransform(loot)->estimated_final_pos = m_pos; +// } + +// } + +} + + + + +void PhysicsSystem::draw(){} +void PhysicsSystem::scrollEvent(double distance){} +void PhysicsSystem::mousePosEvent(double xpos, double ypos){} + diff --git a/engine-ocean/Game/Systems/physicssystem.h b/engine-ocean/Game/Systems/physicssystem.h new file mode 100644 index 0000000..fc9abbb --- /dev/null +++ b/engine-ocean/Game/Systems/physicssystem.h @@ -0,0 +1,30 @@ +#ifndef PHYSICSSYSTEM_H +#define PHYSICSSYSTEM_H +#include "Game/Components/TransformComponent.h" +#include "system.h" + + +class PhysicsSystem : public System +{ +public: + PhysicsSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects, + std::map<std::string, BlackboardData>& global_blackboard, + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables); + void draw() override; + void update(double deltaTime) override; + void scrollEvent(double distance) override; + void mousePosEvent(double xpos, double ypos) override; + +private: + float gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity); + TransformComponent* getTransform(std::shared_ptr<GameObject> &go); + + std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects; + std::map<std::string, BlackboardData>& m_global_blackboard; + std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables; + + float horiz_velocity = .005f; + float snapshot_time = 0.f; +}; + +#endif // PHYSICSSYSTEM_H diff --git a/engine-ocean/Game/Systems/system.cpp b/engine-ocean/Game/Systems/system.cpp new file mode 100644 index 0000000..764114c --- /dev/null +++ b/engine-ocean/Game/Systems/system.cpp @@ -0,0 +1,6 @@ +#include "system.h" + +System::System() +{ + +} diff --git a/engine-ocean/Game/Systems/system.h b/engine-ocean/Game/Systems/system.h new file mode 100644 index 0000000..4abca3b --- /dev/null +++ b/engine-ocean/Game/Systems/system.h @@ -0,0 +1,17 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + + +#include "Game/GameObjects/GameObject.h" +#include <map> +class System +{ +public: + System(); + virtual void draw() = 0; + virtual void update(double deltaTime) = 0; + virtual void scrollEvent(double distance) = 0; + virtual void mousePosEvent(double xpos, double ypos) = 0; +}; + +#endif // SYSTEM_H diff --git a/engine-ocean/Game/TypeMap.h b/engine-ocean/Game/TypeMap.h new file mode 100644 index 0000000..add3367 --- /dev/null +++ b/engine-ocean/Game/TypeMap.h @@ -0,0 +1,54 @@ +#ifndef TYPEMAP_H +#define TYPEMAP_H +#include <unordered_map> +#include <atomic> + +template <class ValueType> +class TypeMap { + typedef std::unordered_map<int, ValueType> InternalMap; + +public: + typedef typename InternalMap::iterator iterator; + typedef typename InternalMap::const_iterator const_iterator; + typedef typename InternalMap::value_type value_type; + + const_iterator begin() const { return m_map.begin(); } + const_iterator end() const { return m_map.end(); } + + iterator begin() { return m_map.begin(); } + iterator end() { return m_map.end(); } + + // finds the value associated with type "Key" in the typemap + template <class Key> + iterator find() { return m_map.find(getTypeId<Key>()); } + + template <class Key> + const_iterator find() const { return m_map.find(getTypeId<Key>()); } + + template <class Key> + bool contains() { return m_map.count(getTypeId<Key>()); } + + // associates a value with the type "Key" + template <class Key> + void put(ValueType &&value){ + m_map[getTypeId<Key>()] = std::forward<ValueType>(value); + } + + template <class Key> + void remove() { m_map.erase(getTypeId<Key>()); } + +private: + template <class Key> + inline static int getTypeId(){ + static const int id = LastTypeId++; + return id; + } + + static std::atomic_int LastTypeId; + InternalMap m_map; +}; + +template <class ValueType> +std::atomic_int TypeMap<ValueType>::LastTypeId(0); + +#endif // TYPEMAP_H diff --git a/engine-ocean/Game/menuscreen.h b/engine-ocean/Game/menuscreen.h new file mode 100644 index 0000000..77ecd2c --- /dev/null +++ b/engine-ocean/Game/menuscreen.h @@ -0,0 +1,27 @@ +#ifndef MENUSCREEN_H +#define MENUSCREEN_H +#include "Game/GameWorld.h" +#include "screen.h" +#include <map> + + +class MenuScreen: public Screen +{ +public: + MenuScreen(std::map<int, Input>& input_map); + ~MenuScreen(); + + + void update(double deltaTime) override; + void draw() override; + void keyEvent(int key, int action) override; + void mousePosEvent(double xpos, double ypos) override; + void mouseButtonEvent(int button, int action) override; + void scrollEvent(double distance) override; + void windowResizeEvent(int width, int height) override; + void framebufferResizeEvent(int width, int height) override; +private: + std::map<int, Input>& m_input_map; +}; + +#endif // MENUSCREEN_H diff --git a/engine-ocean/Game/screen.cpp b/engine-ocean/Game/screen.cpp new file mode 100644 index 0000000..525e009 --- /dev/null +++ b/engine-ocean/Game/screen.cpp @@ -0,0 +1,6 @@ +#include "screen.h" + +Screen::Screen() +{ + +} diff --git a/engine-ocean/Game/screen.h b/engine-ocean/Game/screen.h new file mode 100644 index 0000000..0a4ebb1 --- /dev/null +++ b/engine-ocean/Game/screen.h @@ -0,0 +1,20 @@ +#ifndef SCREEN_H +#define SCREEN_H + + +class Screen +{ +public: + Screen(); + + virtual void update(double deltaTime) = 0; + virtual void draw() = 0; + virtual void keyEvent(int key, int action) = 0; + virtual void mousePosEvent(double xpos, double ypos) = 0; + virtual void mouseButtonEvent(int button, int action) = 0; + virtual void scrollEvent(double distance) = 0; + virtual void windowResizeEvent(int width, int height) = 0; + virtual void framebufferResizeEvent(int width, int height) = 0; +}; + +#endif // SCREEN_H |