...
 
Commits (3)
......@@ -14,5 +14,6 @@
#include "components/animation.hpp"
#include "components/ai_player.hpp"
#include "components/player_component.hpp"
#include "components/character_design.hpp"
#endif // !COMPONENTS_HPP_INCLUDED
#ifndef COMPONENTS_AI_PLAYER_HPP_INCLUDED
#define COMPONENTS_AI_PLAYER_HPP_INCLUDED
#include "vcl/vcl.hpp"
#include "ECS/Component.hpp"
struct AIPlayer
......
#ifndef COMPONENTS_CHARACTER_DESIGN_COMPONENT_HPP_INCLUDED
#define COMPONENTS_CHARACTER_DESIGN_COMPONENT_HPP_INCLUDED
#include "ECS/Component.hpp"
struct CharacterDesign
{
CharacterDesign(float maxHealth_, float damage_) : maxHealth{ maxHealth_ }, damage{ damage_ } {currentHealth = maxHealth; };
float maxHealth;
float damage;
float currentHealth;
};
using CharacterDesignComponent = ecs::Component<CharacterDesign>;
#endif // !COMPONENTS_CHARACTER_DESIGN_COMPONENT_HPP_INCLUDED
......@@ -7,14 +7,19 @@
struct Ray
{
Ray(vcl::vec3 const& shootOrigin, vcl::vec3 const& shootDirection, float const& m_speed, ecs::Entity const& shooter, vcl::vec3 const& end) : position{ shootOrigin }, direction{ shootDirection }, speed{ m_speed }, srcEntity{ shooter }, endTrajectory{ end }{};
Ray(vcl::vec3 const& shootOrigin, vcl::vec3 const& shootDirection, float const& m_speed, ecs::Entity const& shooter) : position{ shootOrigin }, direction{ shootDirection }, speed{ m_speed }, srcEntity{ shooter }{};
Ray(vcl::vec3 const& shootOrigin, vcl::vec3 const& shootDirection, float const& m_speed, ecs::Entity const& shooter, vcl::vec3 const& end) : position{ shootOrigin }, direction{ shootDirection }, speed{ m_speed }, srcEntity{ shooter }, endTrajectory{ end }, damage{}{};
Ray(vcl::vec3 const& shootOrigin, vcl::vec3 const& shootDirection, float const& m_speed, ecs::Entity const& shooter, float damage_) : position{ shootOrigin }, direction{ shootDirection }, speed{ m_speed }, srcEntity{ shooter }, damage{ damage_ }{};
Ray(vcl::vec3 const& shootOrigin, vcl::vec3 const& shootDirection, float const& m_speed, ecs::Entity const& shooter) : position{ shootOrigin }, direction{ shootDirection }, speed{ m_speed }, srcEntity{ shooter }, damage{}{};
Ray() = default;
vcl::vec3 position;
vcl::vec3 direction;
float speed;
ecs::Entity srcEntity;
std::optional<ecs::Entity> endEntity;
std::optional<vcl::vec3> endTrajectory{ std::nullopt };
float damage;
};
using RayComponent = ecs::Component<Ray>;
......
......@@ -41,6 +41,12 @@ void scene_model::frame_draw(std::map<std::string,GLuint>& shaders, scene_struct
{
set_gui();
logicLoop(shaders, scene, gui);
if (m_gameOver)
{
std::cout << "Game Over" << std::endl;
glfwSetWindowShouldClose(gui.window, GLFW_TRUE);
return;
}
renderLoop(shaders, scene);
}
......@@ -54,6 +60,8 @@ void scene_model::createResources()
setupAimCursor();
buildAIHierarchyPool(m_resources);
m_resources.collisionGrid = CollisionGrid(gridResolution, gridResolution, &m_resources.terrainGeometry);
m_ecs.subscribeToEntityDestroyedEvent("removeFromCollisionGrid", [&grid = m_resources.collisionGrid](ecs::Entity entity) { grid.removeEntity(entity); });
m_ecs.subscribeToEntityDestroyedEvent("GameOver", [&b = m_gameOver, &playerEntity = m_player](ecs::Entity entity) {if (playerEntity == entity) { b = true; } });
m_resources.meshes["collision_box"] = mesh_primitive_cylinder(1.f, vec3{}, vec3{ 0.f, 0.f, 1.f });
setupCollisionRates();
}
......@@ -82,6 +90,8 @@ void scene_model::buildEntities(std::map<std::string,GLuint>& shaders)
vec3 AIPosition = m_resources.terrainGeometry.evaluate(0.4, 0.6) + vec3{ 0, 0, 5 };
builder.buildAICharacter(m_player, AIPosition, shaders);
AIPosition = m_resources.terrainGeometry.evaluate(0.2, 0.3) + vec3{ 0, 0, 5 };
builder.buildAICharacter(m_player, AIPosition, shaders);
m_aimCursor = m_ecs.createEntity();
m_ecs.add<TransformComponent>(m_aimCursor, vec3(0,0,2));
......@@ -102,6 +112,7 @@ void scene_model::set_gui()
void scene_model::logicLoop(std::map<std::string,GLuint>& shaders, scene_structure& scene, gui_structure& gui)
{
const float dt = m_timer.update();
const bool timerEvent = m_timer.event;
......@@ -138,6 +149,9 @@ void scene_model::logicLoop(std::map<std::string,GLuint>& shaders, scene_structu
m_ecs.update<BillboardOrientationSystem>(scene.camera.orientation);
m_ecs.update<HierarchyPositionUpdater::Transform2Collision>();
m_ecs.update<LockdownSystem>();
m_ecs.update<HealthSystem>(m_ecs);
m_ecs.getSystem<HealthSystem>().destroyDeadCharacter(m_ecs);
}
void scene_model::renderLoop(std::map<std::string,GLuint>& shaders, scene_structure& scene)
......
......@@ -74,6 +74,8 @@ private:
MyEcs m_ecs;
CommonSceneResources m_resources;
bool m_gameOver = false;
Skybox m_skybox;
ecs::Entity m_player;
ecs::Entity m_aimCursor;
......
......@@ -6,7 +6,7 @@
#include "components.hpp"
#include "systems.hpp"
struct MyEcs : ecs::ecs<ecs::Components<HierarchyCollisionBoxComponent, TransformComponent, DerivedTransformComponent, RenderComponent, ArticulatedHierarchyComponent, CollisionComponent, ForceComponent, PhysicsComponent, PlayerControlComponent, RayComponent, AnimationComponent, AIPlayerComponent, PlayerComponent>
struct MyEcs : ecs::ecs<ecs::Components<HierarchyCollisionBoxComponent, TransformComponent, DerivedTransformComponent, RenderComponent, ArticulatedHierarchyComponent, CollisionComponent, ForceComponent, PhysicsComponent, PlayerControlComponent, RayComponent, AnimationComponent, AIPlayerComponent, PlayerComponent, CharacterDesignComponent>
, ecs::Systems<RayRender, RayTrajectory,
GravitySystem, PhysicsSystem, DeadEntityCollector,
PositionUpdater::Collision2Transform, PositionUpdater::Transform2Collision, HierarchyPositionUpdater::Collision2Transform, HierarchyPositionUpdater::Transform2Collision,
......@@ -14,7 +14,7 @@ struct MyEcs : ecs::ecs<ecs::Components<HierarchyCollisionBoxComponent, Transfor
BillboardOrientationSystem, RenderSystem, HierarchyRenderSystem, CollisionBoxesRenderer,
AnimationInterpolator, AnimationApplier, AnimationChooser,
ControlHandlingSystem, AIHandlingSystem,
CameraHandlingSystem, LockdownSystem>>
CameraHandlingSystem, LockdownSystem, HealthSystem>>
{};
#endif // !MY_ECS_HPP_INCLUDED
\ No newline at end of file
......@@ -87,6 +87,14 @@ void CollisionGrid::updateWith(CollisionComponent& collisionComponent)
}
}
void CollisionGrid::removeEntity(ecs::Entity entity)
{
for (auto cell = m_grid.begin(); cell != m_grid.end(); cell++)
{
cell->erase(entity);
}
}
std::size_t CollisionGrid::xIdxAt(float x) const
{
assert(m_terrain);
......@@ -116,4 +124,5 @@ std::size_t CollisionGrid::flattenIdx(std::size_t xIdx, std::size_t yIdx) const
std::pair<std::size_t, std::size_t> CollisionGrid::unflattenIdx(std::size_t idx) const
{
return { idx / m_ySize, idx % m_ySize };
}
\ No newline at end of file
}
......@@ -46,6 +46,8 @@ public:
std::size_t ySize() const { return m_ySize; }
AABB getBoundingBox(size_t const xIdx, size_t const y_Idx) const;
void removeEntity(ecs::Entity entity);
private:
std::size_t xIdxAt(float x) const;
std::size_t yIdxAt(float y) const;
......
......@@ -88,6 +88,7 @@ ecs::Entity EntityBuilder::buildPlayer(vcl::vec3 const& position, std::map<std::
{
auto& hierarchy = m_resources.AIHierarchyPool.getFreeElement().first;
auto playerEntity = buildCharacter(m_resources.standardCharacter, hierarchy, position, shaders);
m_ecs.add<CharacterDesignComponent>(playerEntity, 10.0f, 1.0f);
m_ecs.add<PlayerComponent>(playerEntity);
return playerEntity;
}
......@@ -95,8 +96,8 @@ ecs::Entity EntityBuilder::buildPlayer(vcl::vec3 const& position, std::map<std::
ecs::Entity EntityBuilder::buildAICharacter(ecs::Entity const target, vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
{
auto& hierarchy = m_resources.AIHierarchyPool.getFreeElement().first;
ecs::Entity ai = buildCharacter(m_resources.standardCharacter, hierarchy, position, shaders);
m_ecs.add<CharacterDesignComponent>(ai, 3.0f, 1.0f);
m_ecs.add<AIPlayerComponent>(ai, target);
return ai;
}
......@@ -27,5 +27,6 @@
#include "systems/camera_handling.hpp"
#include "systems/ai_handling.hpp"
#include "systems/lockdown_system.hpp"
#include "systems/health_system.hpp"
#endif // !SYSTEMS_HPP_INCLUDED
......@@ -19,7 +19,7 @@ static void NewDirection(PlayerControlComponent& controls)
}
}
void AIHandlingSystem::update(const MyEcs& m_ecs, const bool AIEvent, PlayerControlComponent& controls, TransformComponent& transform, AIPlayerComponent const& player)
void AIHandlingSystem::update(MyEcs& m_ecs, const bool AIEvent, PlayerControlComponent& controls, TransformComponent& transform, AIPlayerComponent const& player)
{
controls.currentControls[PlayerControlInfos::Control::Jump] = false;
controls.currentControls[PlayerControlInfos::Control::Shoot] = false;
......@@ -30,13 +30,13 @@ void AIHandlingSystem::update(const MyEcs& m_ecs, const bool AIEvent, PlayerCont
const float shoot = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
const float jump = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
if (changeDirection < changeDirectionProba)
if (changeDirection < m_changeDirectionProba)
NewDirection(controls);
if (shoot < shootProba)
controls.currentControls[PlayerControlComponent::Control::Shoot] = true;
if (shoot < m_shootProba)
createRay(m_ecs, transform.entity(), m_ecs.get<TransformComponent>(player.target), transform);
if (jump < jumpProba)
if (jump < m_jumpProba)
controls.currentControls[PlayerControlComponent::Control::Jump] = true;
}
......@@ -44,5 +44,26 @@ void AIHandlingSystem::update(const MyEcs& m_ecs, const bool AIEvent, PlayerCont
const vec3 verticalAxis = vec3(0, 0, 1);
vec3 targetDirection = normalize(m_ecs.get<TransformComponent>(player.target).position - transform.position);
targetDirection = normalize(targetDirection - dot(verticalAxis, targetDirection) * verticalAxis);
transform.rotation = transform.rotation * rotation_between_vector_mat3(currentAxis, targetDirection);
mat3 rot = rotation_between_vector_mat3(currentAxis, targetDirection);
rot.zz = 1.0f;
transform.rotation = transform.rotation * rot;
}
void AIHandlingSystem::createRay(MyEcs& m_ecs, ecs::Entity const& AIEntity, TransformComponent const& targetTransform, TransformComponent const& AITransform)
{
std::mt19937 gen(m_rd());
std::uniform_real_distribution<float> dis(.0f, 1.0f);
auto realRayEntity = m_ecs.createEntity();
float const speed = 50.0f;
vec3 const position = AITransform.position + vec3(0, 0, 1) * 0.4;
vec3 direction = normalize(targetTransform.position - position);
const float theta = 3.1415 * dis(gen);
const float lambda = m_noise * dis(gen);
const vec3 noise = rotation_between_vector_mat3(vec3(0, 0, 1), direction) * vec3(cos(theta), sin(theta), 0);
direction = normalize(lambda * noise + direction);
auto& realRay = m_ecs.add<RayComponent>(realRayEntity, position, direction, speed, AIEntity, m_ecs.get<CharacterDesignComponent>(AIEntity).damage);
m_ecs.getSystem<RayTrajectory>().computeRayTrajectory(realRay, m_ecs);
}
\ No newline at end of file
......@@ -11,14 +11,18 @@ struct MyEcs;
struct AIHandlingSystem
{
public :
void update(const MyEcs& m_ecs, const bool AIEvent, PlayerControlComponent& controls, TransformComponent& transform, AIPlayerComponent const& player);
void update(MyEcs& m_ecs, const bool AIEvent, PlayerControlComponent& controls, TransformComponent& transform, AIPlayerComponent const& player);
void createRay(MyEcs& m_ecs, ecs::Entity const& AIEntity, TransformComponent const& targetTransform, TransformComponent const& AITransform);
using Requirements = ecs::Requirements<ecs::Auto>;
using UpdatePolicy = ecs::OncePerEntity;
private :
const float changeDirectionProba = .2f;
const float shootProba = 0.1f;
const float jumpProba = 0.1f;
const float m_changeDirectionProba = .2f;
const float m_shootProba = .3f;
const float m_jumpProba = 0.1f;
const float m_noise = 0.2f;
std::random_device m_rd;
};
#endif // !SYSTEMS_AI_HANDLING_HPP_INCLUDED
......@@ -33,7 +33,7 @@ void CameraHandlingSystem::createRay(MyEcs& m_ecs, ecs::Entity const& playerEnti
{
auto toolRayEntity = m_ecs.createEntity();
vcl::ray const shootInfos = vcl::picking_ray(camera, m_cursorPosition);
auto& toolRay = m_ecs.add<RayComponent>(toolRayEntity, shootInfos.p + shootInfos.u*camera.scale ,shootInfos.u, 0.0f, playerEntity);
auto& toolRay = m_ecs.add<RayComponent>(toolRayEntity, shootInfos.p + shootInfos.u * camera.scale, shootInfos.u, 0.0f, playerEntity);// , 0.0f);
m_ecs.getSystem<RayTrajectory>().computeRayTrajectory(toolRay, m_ecs);
m_ecs.getSystem<RayTrajectory>().addDeadRay(toolRay);
......@@ -44,6 +44,6 @@ void CameraHandlingSystem::createRay(MyEcs& m_ecs, ecs::Entity const& playerEnti
float const speed = 50.0f;
vec3 const position = playerTransform.position + vec3(0, 0, 1) * 0.4;
vec3 const direction = (*toolRay.endTrajectory - position) / norm(*toolRay.endTrajectory - position);
auto& realRay = m_ecs.add<RayComponent>(realRayEntity, position, direction, speed, playerEntity);
auto& realRay = m_ecs.add<RayComponent>(realRayEntity, position, direction, speed, playerEntity, m_ecs.get<CharacterDesignComponent>(playerEntity).damage);
m_ecs.getSystem<RayTrajectory>().computeRayTrajectory(realRay, m_ecs);
}
\ No newline at end of file
......@@ -37,7 +37,6 @@ void CollisionResolver::handleOneCollision(CollisionRateMap const& collisionRate
auto aCanMove = dTransforms.has(a.entity);
auto bCanMove = dTransforms.has(b.entity);
std::cout << collisionComponentA.material << collisionComponentB.material << std::endl;
auto collisionRates = collisionRateMap.find({ collisionComponentA.material, collisionComponentB.material });
assert(collisionRates != std::end(collisionRateMap));
auto slowdownRate = collisionRates->second.bounceSlowdown;
......
#include "health_system.hpp"
#include "../my_ecs.hpp"
void HealthSystem::update(MyEcs& myEcs, RayComponent& ray)
{
if (ray.endEntity.has_value() && myEcs.has<CharacterDesignComponent>(*ray.endEntity))
{
auto& target = myEcs.get<CharacterDesignComponent>(*ray.endEntity);
target.currentHealth -= ray.damage;
ray.damage = 0;
std::cout << "Ray endEntityHealth = " << target.currentHealth << std::endl;
if (target.currentHealth <= 0)
m_deadCharacters.push_back(*ray.endEntity);
}
}
void HealthSystem::destroyDeadCharacter(MyEcs& myEcs)
{
for (auto entity = m_deadCharacters.begin(); entity != m_deadCharacters.end(); entity++)
{
myEcs.destroy(*entity);
}
m_deadCharacters.clear();
}
#ifndef SYSTEMS_HEALTH_SYSTEM_HPP_INCLUDED
#define SYSTEMS_HEALTH_SYSTEM_HPP_INCLUDED
#include "ECS.hpp"
#include "../components.hpp"
struct MyEcs;
struct HealthSystem
{
public:
void update(MyEcs& myEcs, RayComponent& ray);
void destroyDeadCharacter(MyEcs& myEcs);
using Requirements = ecs::Requirements<ecs::Auto>;
using UpdatePolicy = ecs::OncePerEntity;
private:
std::vector<ecs::Entity> m_deadCharacters;
};
#endif // !SYSTEMS_HEALTH_SYSTEM_HPP_INCLUDED
......@@ -37,7 +37,7 @@ static std::optional<vcl::vec3> getBulletImpact(RayComponent const& ray, Collisi
//Check if the ray is intersecting with the cylinder
if (std::max(z1, cylinder.center.z) > std::min(z2, cylinder.center.z + cylinder.height))
return {};
//std::cout << ray.direction << cylinder.center << ray.position << cylinder.radius << " "<< lambdaMoins << std::endl;
//Different scenarios to get the intersection point
vec3 res;
if (lambdaMoins > 0 && cylinder.center.z <= intersect1.z && intersect1.z <= cylinder.center.z + cylinder.height)
......@@ -57,10 +57,11 @@ static std::optional<vcl::vec3> getBulletImpact(RayComponent const& ray, Collisi
return res;
}
static std::optional<vcl::vec3> bulletCollisionInCell(CollisionGrid::Cell const& cell, RayComponent& ray, MyEcs const& m_ecs)
static std::pair<std::optional<vcl::vec3>,std::optional<ecs::Entity>> bulletCollisionInCell(CollisionGrid::Cell const& cell, RayComponent& ray, MyEcs const& m_ecs)
{
float distanceMin = infinity;
std::optional<vcl::vec3> rayEnd{ std::nullopt };
std::optional<ecs::Entity> endEntity{ std::nullopt };
for (auto entity = cell.begin(); entity != cell.end(); entity++)
for(size_t cylIdx = 0; cylIdx<m_ecs.get<CollisionComponent>(*entity).shape.cylinders.size(); cylIdx++)
{
......@@ -68,35 +69,37 @@ static std::optional<vcl::vec3> bulletCollisionInCell(CollisionGrid::Cell const&
auto collisionPoint = getBulletImpact(ray, cylinder);
if (*entity != ray.srcEntity && collisionPoint && norm(ray.position - collisionPoint.value()) < distanceMin)
{
//std::cout << "Shooter entity = " << ray.srcEntity << ", colliding entity = " << *entity << std::endl;
distanceMin = norm(ray.position - collisionPoint.value());
rayEnd = collisionPoint;
endEntity = *entity;
}
}
return rayEnd;
return { rayEnd, endEntity };
}
static std::optional<vcl::vec3> getBulletFirstCollision(CollisionGrid const& collisionGrid, RayComponent& ray, MyEcs const& m_ecs)
static std::pair<std::optional<vcl::vec3>, std::optional<ecs::Entity>> getBulletFirstCollision(CollisionGrid const& collisionGrid, RayComponent& ray, MyEcs const& m_ecs)
{
vec2 const positionPlan{ ray.position.x,ray.position.y };
vec2 const directionPlan{ ray.direction.x, ray.direction.y };
float distanceMin = infinity;
std::optional< vcl::vec3 > rayEnd{ std::nullopt };
std::optional<ecs::Entity> endEntity{ std::nullopt };
for(size_t xIdx=0; xIdx<collisionGrid.xSize(); xIdx++)
for (size_t yIdx = 0; yIdx < collisionGrid.ySize(); yIdx++)
{
if (collisionGrid.getBoundingBox(xIdx, yIdx).intersect(positionPlan, directionPlan))
{
auto end = bulletCollisionInCell(collisionGrid.at(xIdx * collisionGrid.ySize() + yIdx), ray, m_ecs);
if (end && norm(ray.position-end.value())<distanceMin)
auto endInfo = bulletCollisionInCell(collisionGrid.at(xIdx * collisionGrid.ySize() + yIdx), ray, m_ecs);
if (endInfo.first && norm(ray.position- endInfo.first.value())<distanceMin)
{
distanceMin = norm(ray.position - end.value());
rayEnd = end;
distanceMin = norm(ray.position - endInfo.first.value());
rayEnd = endInfo.first;
endEntity = endInfo.second;
}
}
}
return rayEnd;
return { rayEnd, endEntity };
}
static vcl::vec3 collisionByDichotomy(TerrainGeometry const& terrainGeometry, vec3 const& position, vec3 const& direction, float const step)
......@@ -148,20 +151,25 @@ void RayTrajectory::computeRayTrajectory(RayComponent& ray, MyEcs const& m_ecs)
{
auto firstEntityCollision = getBulletFirstCollision(*collisionGrid, ray, m_ecs);
auto firstGroundCollision = getBulletGroundCollision(*terrainGeometry, ray);
if (firstEntityCollision.has_value() && firstGroundCollision.has_value())
if (firstEntityCollision.first.has_value() && firstGroundCollision.has_value())
{
if (norm(*firstEntityCollision - ray.position) < norm(*firstGroundCollision - ray.position))
ray.endTrajectory = *firstEntityCollision;
if (norm(*firstEntityCollision.first - ray.position) < norm(*firstGroundCollision - ray.position))
{
ray.endTrajectory = *firstEntityCollision.first;
ray.endEntity = firstEntityCollision.second;
}
else
ray.endTrajectory = *firstGroundCollision;
}
else if (firstEntityCollision.has_value())
ray.endTrajectory = *firstEntityCollision;
else if (firstEntityCollision.first.has_value())
{
ray.endTrajectory = *firstEntityCollision.first;
ray.endEntity = firstEntityCollision.second;
}
else if (firstGroundCollision.has_value())
ray.endTrajectory = *firstGroundCollision;
else
ray.endTrajectory = ray.position + infinity * ray.direction;
std::cout << "Rayon cree, start = " << ray.position << ", end = " << *ray.endTrajectory << std::endl;
}
}
......