...
 
Commits (12)
......@@ -12,5 +12,7 @@
#include "components/render.hpp"
#include "components/ray.hpp"
#include "components/animation.hpp"
#include "components/ai_player.hpp"
#include "components/player_component.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
{
AIPlayer(ecs::Entity target_) : target { target_ }{};
ecs::Entity target;
};
using AIPlayerComponent = ecs::Component<AIPlayer>;
#endif // !COMPONENTS_AI_PLAYER_HPP_INCLUDED
#ifndef COMPONENTS_PLAYER_COMPONENT_HPP_INCLUDED
#define COMPONENTS_PLAYER_COMPONENT_HPP_INCLUDED
#include "ECS/Component.hpp"
struct Player{};
using PlayerComponent = ecs::Component<Player>;
#endif // !COMPONENTS_PLAYER_COMPONENT_HPP_INCLUDED
#include "simple_debug_tools.hpp"
#include <iostream>
using namespace vcl;
void printHierarchy(hierarchy_mesh_drawable const& h)
{
for(auto const& elem : h.name_map)
std::cout << elem.first << ' ';
std::cout << std::endl;
}
#ifndef SIMPLE_DEBUG_TOOLS_HPP_INCLUDED
#define SIMPLE_DEBUG_TOOLS_HPP_INCLUDED
#include "vcl/vcl.hpp"
void printHierarchy(vcl::hierarchy_mesh_drawable const& h);
#endif // !SIMPLE_DEBUG_TOOLS_HPP_INCLUDED
\ No newline at end of file
......@@ -20,6 +20,8 @@ using namespace vcl;
It is used to initialize all part-specific data */
void scene_model::setup_data(std::map<std::string,GLuint>& shaders, scene_structure& scene, gui_structure&)
{
srand(static_cast<unsigned> (time(0)));
createResources();
setupCamera(scene);
setupSystems();
......@@ -29,6 +31,8 @@ void scene_model::setup_data(std::map<std::string,GLuint>& shaders, scene_struct
auto& pointDrawer = PointDrawer::get();
pointDrawer.scene = &scene;
pointDrawer.shader = shaders["mesh"];
m_timer.periodic_event_time_step = .3f;
}
/** This function is called at each frame of the animation loop.
......@@ -48,6 +52,7 @@ void scene_model::createResources()
setupSkybox();
setupPlayerEntity();
setupAimCursor();
buildAIHierarchyPool(m_resources);
m_resources.collisionGrid = CollisionGrid(gridResolution, gridResolution, &m_resources.terrainGeometry);
m_resources.meshes["collision_box"] = mesh_primitive_cylinder(1.f, vec3{}, vec3{ 0.f, 0.f, 1.f });
setupCollisionRates();
......@@ -75,6 +80,9 @@ void scene_model::buildEntities(std::map<std::string,GLuint>& shaders)
vec3 playerPosition = m_resources.terrainGeometry.evaluate(0.5, 0.5) + vec3 { 0, 0, 5 };
m_player = builder.buildPlayer(playerPosition, shaders);
vec3 AIPosition = m_resources.terrainGeometry.evaluate(0.4, 0.6) + 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));
auto& renderComponent = m_ecs.add<RenderComponent>(m_aimCursor, m_resources.meshes["aim_cursor_billboard"], shaders["mesh"]);
......@@ -89,13 +97,13 @@ void scene_model::set_gui()
ImGui::Checkbox("Collision Boxes", &m_gui_scene.collisionBoxes); ImGui::SameLine();
ImGui::Spacing();
ImGui::SliderFloat("Time", &m_timer.t, m_timer.t_min, m_timer.t_max);
ImGui::SliderFloat("Time scale", &m_timer.scale, 0.1f, 3.0f);
}
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;
auto& playerTransform = m_ecs.get<TransformComponent>(m_player);
const vec3 cameraAxis { 1, 0, 0 };
......@@ -121,6 +129,7 @@ void scene_model::logicLoop(std::map<std::string,GLuint>& shaders, scene_structu
//m_ecs.update<PositionUpdater::Collision2Transform>();
m_ecs.update<HierarchyPositionUpdater::Collision2Transform>();
m_ecs.update<AIHandlingSystem>(m_ecs, timerEvent);
m_ecs.update<CameraHandlingSystem>(scene.camera, m_ecs, m_player, m_aimCursor);
m_ecs.update<RayTrajectory>(dt);
m_ecs.getSystem<RayTrajectory>().destroyAll(m_ecs);
......@@ -128,6 +137,7 @@ 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>();
}
void scene_model::renderLoop(std::map<std::string,GLuint>& shaders, scene_structure& scene)
......@@ -147,11 +157,6 @@ void scene_model::renderLoop(std::map<std::string,GLuint>& shaders, scene_struct
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
m_ecs.update<RenderSystem>(scene, wireShader, true);
glDepthMask(true);
auto& playerTransform = m_ecs.get<TransformComponent>(m_player);
m_skybox.translate(playerTransform.position);
......@@ -162,6 +167,12 @@ void scene_model::renderLoop(std::map<std::string,GLuint>& shaders, scene_struct
draw(side, scene.camera, shaders["wireframe"]);
}
}
glDepthMask(false);
m_ecs.update<RenderSystem>(scene, wireShader, true);
glDepthMask(true);
}
void scene_model::setupTerrainGeometry()
......@@ -247,7 +258,7 @@ void scene_model::setupPlayerEntity()
{ GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE}
};
auto cylinderRadius = 0.5f;
auto cylinderRadius = 0.3f;
const vec3 vertebraShape { 0.3, 0.15, 0.05 };
auto& playerMesh = m_resources.meshes["player"] = createVertebra(vertebraShape, { 0, 0, vertebraShape.z }, 30, 30);
playerMesh.uniform.color = { 0.3f, 0.25f, 0.09f };
......@@ -263,7 +274,6 @@ void scene_model::setupPlayerEntity()
acceleration,
maxSpeed,
jumpImpulsion,
createPlayerMeshHierarchy()
};
setupPlayerAnimation();
......@@ -272,7 +282,8 @@ void scene_model::setupPlayerEntity()
void scene_model::setupAimCursor()
{
mesh billboard_cpu{};
billboard_cpu.position = { {-0.1f,-0.1f,0}, { 0.1f,-0.1f,0}, { 0.1f, 0.1f,0}, {-0.1f, 0.1f,0} };
float cursorSize = 0.05f;
billboard_cpu.position = { {-cursorSize,-cursorSize,0}, {cursorSize,-cursorSize,0}, { cursorSize,cursorSize,0}, {-cursorSize,cursorSize,0} };
billboard_cpu.texture_uv = { {0,1}, {1,1}, {1,0}, {0,0} };
billboard_cpu.connectivity = { {0,1,2}, {0,2,3} };
......@@ -290,8 +301,9 @@ void scene_model::setupPlayerAnimation()
void scene_model::setupCollisionRates()
{
m_resources.collisionRates = {
{ std::make_pair(CollisionMaterial::Tree, CollisionMaterial::Character), CollisionRates { 0.1f, 0.1f } }
, { std::make_pair(CollisionMaterial::Ground, CollisionMaterial::Character), CollisionRates { 0.f, 0.1f } }
{ std::make_pair(CollisionMaterial::Tree, CollisionMaterial::Character), CollisionRates { 0.1f, 0.9f } }
, { std::make_pair(CollisionMaterial::Ground, CollisionMaterial::Character), CollisionRates { 0.f, 0.2f } }
, { std::make_pair(CollisionMaterial::Character, CollisionMaterial::Character), CollisionRates { 0.8f, 1.0f } }
};
completeWithDefaults(m_resources.collisionRates);
completeWithSymetricals(m_resources.collisionRates);
......@@ -300,7 +312,7 @@ void scene_model::setupCollisionRates()
void scene_model::setupCamera(scene_structure& scene)
{
scene.camera.camera_type = camera_control_spherical_coordinates;
scene.camera.scale = 10.0f;
scene.camera.scale = 2.0f;
scene.camera.apply_rotation(0,0,0,1.2f);
}
......@@ -322,6 +334,8 @@ void scene_model::setupSystems()
m_ecs.getSystem<RayTrajectory>().collisionGrid = &m_resources.collisionGrid;
m_ecs.getSystem<RayTrajectory>().terrainGeometry = &m_resources.terrainGeometry;
m_ecs.getSystem<LockdownSystem>().terrainGeometry = &m_resources.terrainGeometry;
}
#endif
......@@ -2,6 +2,7 @@
#include <vector>
#include <string>
#include <ctime>
#include "main/scene_base/base.hpp"
......@@ -67,6 +68,7 @@ private:
void setupPlayerAnimation();
void setupCollisionRates();
void setupAI();
private:
MyEcs m_ecs;
......@@ -82,7 +84,7 @@ private:
gui_scene_structure m_gui_scene;
vcl::timer_interval m_timer;
vcl::timer_event m_timer;
};
#endif
......
......@@ -6,15 +6,15 @@
#include "components.hpp"
#include "systems.hpp"
struct MyEcs : ecs::ecs<ecs::Components<HierarchyCollisionBoxComponent, TransformComponent, DerivedTransformComponent, RenderComponent, ArticulatedHierarchyComponent, CollisionComponent, ForceComponent, PhysicsComponent, PlayerControlComponent, RayComponent, AnimationComponent>
struct MyEcs : ecs::ecs<ecs::Components<HierarchyCollisionBoxComponent, TransformComponent, DerivedTransformComponent, RenderComponent, ArticulatedHierarchyComponent, CollisionComponent, ForceComponent, PhysicsComponent, PlayerControlComponent, RayComponent, AnimationComponent, AIPlayerComponent, PlayerComponent>
, ecs::Systems<RayRender, RayTrajectory,
GravitySystem, PhysicsSystem, DeadEntityCollector,
PositionUpdater::Collision2Transform, PositionUpdater::Transform2Collision, HierarchyPositionUpdater::Collision2Transform, HierarchyPositionUpdater::Transform2Collision,
GroundCollisionDetector, GroundCollisionResolver, CollisionGridInitializer, CollisionGridUpdater, CollisionDetector, CollisionResolver,
BillboardOrientationSystem, RenderSystem, HierarchyRenderSystem, CollisionBoxesRenderer,
AnimationInterpolator, AnimationApplier, AnimationChooser,
ControlHandlingSystem,
CameraHandlingSystem>>
ControlHandlingSystem, AIHandlingSystem,
CameraHandlingSystem, LockdownSystem>>
{};
#endif // !MY_ECS_HPP_INCLUDED
\ No newline at end of file
......@@ -6,6 +6,9 @@
#include "../components.hpp"
#include "collision_grid.hpp"
#include "pool.hpp"
using KeyboardMapping = std::unordered_map<int, PlayerControlComponent::Control>;
using KeyboardState = std::unordered_map<int, int>;
......@@ -23,8 +26,6 @@ struct CharacterDescription
float acceleration;
float maxSpeed;
float jumpImpulsion;
CompletedMeshHierarchy meshHierarchy;
};
struct CommonSceneResources
......@@ -44,6 +45,7 @@ struct CommonSceneResources
KeyboardMapping mouseMapping;
CharacterDescription standardCharacter;
Pool<CompletedMeshHierarchy> AIHierarchyPool{ 5 };
};
#endif // !OTHERS_COMMON_SCENE_RESOURCES_HPP_INCLUDED
\ No newline at end of file
#include "entity_builder.hpp"
using namespace vcl;
#include "../debugging/simple_debug_tools.hpp"
std::tuple<vcl::hierarchy_mesh_drawable, std::string, HierarchyCollisionBoxInfos::CollectionType> createPlayerMeshHierarchy();
using namespace vcl;
EntityBuilder::EntityBuilder(MyEcs& ecs, CommonSceneResources& resources)
: m_ecs { ecs }
......@@ -57,22 +57,22 @@ ecs::Entity EntityBuilder::buildGrassBillboard(vcl::vec3 const& position, std::m
return billboard;
}
ecs::Entity EntityBuilder::buildCharacter(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
ecs::Entity EntityBuilder::buildCharacter(CharacterDescription& characterInfo, CompletedMeshHierarchy& meshHierarchy, vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
{
auto character = m_ecs.createEntity();
m_ecs.add<TransformComponent>(character, position);
m_ecs.add<DerivedTransformComponent>(character);
m_ecs.add<PhysicsComponent>(character, m_resources.standardCharacter.mass);
m_ecs.add<PhysicsComponent>(character, characterInfo.mass);
m_ecs.add<ForceComponent>(character);
auto& hierarchyBoxComponent = m_ecs.add<HierarchyCollisionBoxComponent>(character);
hierarchyBoxComponent.boundaries = m_resources.standardCharacter.meshHierarchy.boundaries;
m_ecs.add<ArticulatedHierarchyComponent>(character, m_resources.standardCharacter.meshHierarchy.rootName, m_resources.standardCharacter.meshHierarchy.hierarchy, shaders["mesh"]);
auto& playerMeshHierarchy = m_resources.standardCharacter.meshHierarchy.hierarchy;
hierarchyBoxComponent.boundaries = meshHierarchy.boundaries;
m_ecs.add<ArticulatedHierarchyComponent>(character, meshHierarchy.rootName, meshHierarchy.hierarchy, shaders["mesh"]);
auto& playerMeshHierarchy = meshHierarchy.hierarchy;
playerMeshHierarchy.update_local_to_global_coordinates();
auto const& legNode = playerMeshHierarchy["right_leg"];
m_ecs.add<CollisionComponent>(character, CollisionShape { std::vector<CollisionCylinder>{ m_resources.collisionBoxes["player"] }, { 0, 0, 2 * legNode.global_transform.translation.z } }, CollisionMaterial::Character);
m_ecs.add<PlayerControlComponent>(character, m_resources.standardCharacter.acceleration, m_resources.standardCharacter.maxSpeed, m_resources.standardCharacter.jumpImpulsion);
m_ecs.add<PlayerControlComponent>(character, characterInfo.acceleration, characterInfo.maxSpeed, characterInfo.jumpImpulsion);
auto runningAnimation = m_resources.animations.find("running");
assert(runningAnimation != std::end(m_resources.animations) && "Animation not loaded");
......@@ -86,10 +86,17 @@ ecs::Entity EntityBuilder::buildCharacter(vcl::vec3 const& position, std::map<st
ecs::Entity EntityBuilder::buildPlayer(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
{
return buildCharacter(position, shaders);
auto& hierarchy = m_resources.AIHierarchyPool.getFreeElement().first;
auto playerEntity = buildCharacter(m_resources.standardCharacter, hierarchy, position, shaders);
m_ecs.add<PlayerComponent>(playerEntity);
return playerEntity;
}
ecs::Entity EntityBuilder::buildIACharacter(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
ecs::Entity EntityBuilder::buildAICharacter(ecs::Entity const target, vcl::vec3 const& position, std::map<std::string,GLuint>& shaders)
{
return buildCharacter(position, shaders);
auto& hierarchy = m_resources.AIHierarchyPool.getFreeElement().first;
ecs::Entity ai = buildCharacter(m_resources.standardCharacter, hierarchy, position, shaders);
m_ecs.add<AIPlayerComponent>(ai, target);
return ai;
}
......@@ -2,7 +2,7 @@
#define OTHERS_ENTITY_BUILDER_HPP_INCLUDED
#include "../my_ecs.hpp"
#include "common_scene_resources.hpp"
#include "scene_elements.hpp"
class EntityBuilder
{
......@@ -15,9 +15,9 @@ public:
ecs::Entity buildMushroom(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildGrassBillboard(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildCharacter(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildCharacter(CharacterDescription& characterInfo, CompletedMeshHierarchy& meshHierarchy, vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildPlayer(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildIACharacter(vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
ecs::Entity buildAICharacter(ecs::Entity const target, vcl::vec3 const& position, std::map<std::string,GLuint>& shaders);
private:
MyEcs& m_ecs;
......
#ifndef OTHERS_POOL_HPP_INCLUDED
#define OTHERS_POOL_HPP_INCLUDED
#include <vector>
#include <stack>
#include <algorithm>
template<typename T, typename Container = std::vector<T>>
class Pool
{
public:
using size_type = typename Container::size_type;
using Handle = size_type;
public:
template<typename ... Args>
Pool(size_type numElems, Args&&... args)
: m_elements{}
{
for(size_type i = 0; i < numElems; ++i)
{
m_elements.emplace_back(std::forward<Args>(args)...);
m_freeElems.push(i);
}
}
template<typename Func>
void map(Func&& f)
{
using std::begin;
using std::end;
std::for_each(begin(m_elements), end(m_elements), std::forward<Func>(f));
}
bool hasFreeElements() const
{
return !std::empty(m_freeElems);
}
std::pair<T&, Handle> getFreeElement()
{
assert(hasFreeElements() && "No free elements left");
auto idx = m_freeElems.top();
m_freeElems.pop();
return { m_elements[idx], idx };
}
void freeElement(Handle h)
{
assert(!isFree(h) && "Element already free");
m_freeElems.push(h);
}
size_t size() { return m_elements.size(); }
private:
bool isFree(Handle h)
{
return std::any_of(std::begin(m_freeElems), std::end(m_freeElems), [h](size_type idx) { return idx == h; });
}
private:
Container m_elements;
std::stack<size_type> m_freeElems;
};
#endif // !OTHERS_POOL_HPP_INCLUDED
\ No newline at end of file
......@@ -35,57 +35,69 @@ std::vector<vec3> getForest(TerrainGeometry const& terrainGeometry, int num_tree
return forest;
}
CompletedMeshHierarchy createPlayerMeshHierarchy()
static void createPlayerMeshInPlace(CompletedMeshHierarchy& completedHierarchy)
{
vcl::hierarchy_mesh_drawable playerMeshHierarchy{};
vcl::hierarchy_mesh_drawable& playerMeshHierarchy = completedHierarchy.hierarchy;
const vec3 vertebraShape { 0.3f, 0.15f, 0.05f };
const vec3 vertebraShape{ 0.3f, 0.15f, 0.05f };
auto vertebra = createVertebra(vertebraShape, vec3{ 0, 0, vertebraShape.z }, 30, 30);
auto vertebraName = [](int i)
{
std::ostringstream oss { "vertebra" };
oss << i;
return oss.str();
};
const vec3 vertebraTranslation { 0, 0, 2.f * vertebraShape.z };
{
std::ostringstream oss{ "vertebra" };
oss << i;
return oss.str();
};
const vec3 vertebraTranslation{ 0, 0, 2.f * vertebraShape.z };
const auto rootName = vertebraName(0);
const auto numVertebrae = 4;
playerMeshHierarchy.add(vertebra, rootName);
for(auto i = 1; i < numVertebrae; ++i)
for (auto i = 1; i < numVertebrae; ++i)
{
playerMeshHierarchy.add(vertebra, vertebraName(i), vertebraName(i-1), vertebraTranslation);
playerMeshHierarchy.add(vertebra, vertebraName(i), vertebraName(i - 1), vertebraTranslation);
}
const auto vertebraSemiWidth = vertebraShape.x;
const auto legRadius = vertebraSemiWidth / 3.f;
const auto legLength = vertebraShape.z * 6.f;
auto legElem = mesh_primitive_cylinder(legRadius, {0, 0, 0}, {0, 0, -legLength});
playerMeshHierarchy.add(legElem, "left_thigh", rootName, {-vertebraSemiWidth + 1.3f * legRadius, 0, -vertebraShape.z});
playerMeshHierarchy.add(legElem, "right_thigh", rootName, {vertebraSemiWidth - 1.3f * legRadius, 0, -vertebraShape.z});
auto legElem = mesh_primitive_cylinder(legRadius, { 0, 0, 0 }, { 0, 0, -legLength });
playerMeshHierarchy.add(legElem, "left_thigh", rootName, { -vertebraSemiWidth + 1.3f * legRadius, 0, -vertebraShape.z });
playerMeshHierarchy.add(legElem, "right_thigh", rootName, { vertebraSemiWidth - 1.3f * legRadius, 0, -vertebraShape.z });
const auto kneeLength = 0.3f * legLength;
playerMeshHierarchy.add(legElem, "left_leg", "left_thigh", { 0, 0, -legLength - kneeLength});
playerMeshHierarchy.add(legElem, "right_leg", "right_thigh", { 0, 0, -legLength - kneeLength});
playerMeshHierarchy.add(legElem, "left_leg", "left_thigh", { 0, 0, -legLength - kneeLength });
playerMeshHierarchy.add(legElem, "right_leg", "right_thigh", { 0, 0, -legLength - kneeLength });
auto footElem = mesh_primitive_sphere(legRadius, {0, 0, 0});
playerMeshHierarchy.add(footElem, "left_foot", "left_leg", {0, 0, - legLength });
playerMeshHierarchy.add(footElem, "right_foot", "right_leg", {0, 0, - legLength });
auto footElem = mesh_primitive_sphere(legRadius, { 0, 0, 0 });
playerMeshHierarchy.add(footElem, "left_foot", "left_leg", { 0, 0, -legLength });
playerMeshHierarchy.add(footElem, "right_foot", "right_leg", { 0, 0, -legLength });
const auto headRadius = 0.6f * vertebraSemiWidth;
auto head = mesh_primitive_sphere(headRadius, { 0, 0, headRadius });
playerMeshHierarchy.add(head, "head", vertebraName(numVertebrae-1), { 0, 0, 2.5f * vertebraShape.z });
playerMeshHierarchy.add(head, "head", vertebraName(numVertebrae - 1), { 0, 0, 2.5f * vertebraShape.z });
const auto armRadius = 0.5f * legRadius;
const auto armLength = 2.f * vertebraSemiWidth;
const auto lateralArmShift = vertebraSemiWidth - 2*armRadius;
const auto lateralArmShift = vertebraSemiWidth - 2 * armRadius;
auto rightArm = mesh_primitive_cylinder(armRadius, { 0, 0, 0 }, { -lateralArmShift, std::sqrt(std::pow(armLength, 2.f) - std::pow(vertebraSemiWidth, 2.f)), 0 });
playerMeshHierarchy.add(rightArm, "right_arm", vertebraName(numVertebrae-1), { vertebraSemiWidth - armRadius, 0, 0 });
playerMeshHierarchy.add(rightArm, "right_arm", vertebraName(numVertebrae - 1), { vertebraSemiWidth - armRadius, 0, 0 });
auto leftArm = mesh_primitive_cylinder(armRadius, { 0, 0, 0 }, { lateralArmShift, std::sqrt(std::pow(armLength, 2.f) - std::pow(vertebraSemiWidth, 2.f)), 0 });
playerMeshHierarchy.add(leftArm, "left_arm", vertebraName(numVertebrae-1), { -vertebraSemiWidth + armRadius, 0, 0 });
playerMeshHierarchy.add(leftArm, "left_arm", vertebraName(numVertebrae - 1), { -vertebraSemiWidth + armRadius, 0, 0 });
HierarchyCollisionBoxInfos::CollectionType boundaries;
HierarchyCollisionBoxInfos::CollectionType& boundaries = completedHierarchy.boundaries;
boundaries.push_back(HierarchyCollisionBoxBoundary{ "left_foot", -legRadius, legRadius });
boundaries.push_back(HierarchyCollisionBoxBoundary{ "right_foot", -legRadius, legRadius });
boundaries.push_back(HierarchyCollisionBoxBoundary{ "head", 0, 2 * headRadius });
return { playerMeshHierarchy, rootName, boundaries };
completedHierarchy.rootName = rootName;
}
CompletedMeshHierarchy createPlayerMeshHierarchy()
{
CompletedMeshHierarchy completedHierarchy{};
createPlayerMeshInPlace(completedHierarchy);
return completedHierarchy;
}
void buildAIHierarchyPool(CommonSceneResources& ressources)
{
ressources.AIHierarchyPool.map(createPlayerMeshInPlace);
}
......@@ -8,6 +8,7 @@
std::vector<vcl::vec3> getForest(TerrainGeometry const& terrain, int num_trees, float min_distance);
CompletedMeshHierarchy createPlayerMeshHierarchy();
void buildAIHierarchyPool(CommonSceneResources& ressources);
constexpr auto trunk_height = 1.f;
constexpr auto trunk_radius = 0.2f;
......
......@@ -25,5 +25,7 @@
#include "systems/animation_applier.hpp"
#include "systems/animation_chooser.hpp"
#include "systems/camera_handling.hpp"
#include "systems/ai_handling.hpp"
#include "systems/lockdown_system.hpp"
#endif // !SYSTEMS_HPP_INCLUDED
#include "ai_handling.hpp"
#include "../my_ecs.hpp"
using namespace vcl;
static void NewDirection(PlayerControlComponent& controls)
{
int newDirectionIdx = rand() % 5;
using Control = PlayerControlComponent::Control;
using IdxType = typename std::underlying_type<Control>::type;
for (auto c = static_cast<IdxType>(Control::First); c < static_cast<IdxType>(Control::First) + 4; c++)
{
Control control = static_cast<Control>(c);
controls.currentControls[control] = false;
if (newDirectionIdx == 0)
controls.currentControls[control] = true;
newDirectionIdx--;
}
}
void AIHandlingSystem::update(const 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;
if (AIEvent)
{
const float changeDirection = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
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)
NewDirection(controls);
if (shoot < shootProba)
controls.currentControls[PlayerControlComponent::Control::Shoot] = true;
if (jump < jumpProba)
controls.currentControls[PlayerControlComponent::Control::Jump] = true;
}
const vec3 currentAxis = transform.rotation * vec3(0, 1, 0);
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);
}
\ No newline at end of file
#ifndef SYSTEMS_AI_HANDLING_HPP_INCLUDED
#define SYSTEMS_AI_HANDLING_HPP_INCLUDED
#include <random>
#include "ECS.hpp"
#include "../components.hpp"
struct MyEcs;
struct AIHandlingSystem
{
public :
void update(const MyEcs& m_ecs, const bool AIEvent, PlayerControlComponent& controls, TransformComponent& transform, AIPlayerComponent const& player);
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;
};
#endif // !SYSTEMS_AI_HANDLING_HPP_INCLUDED
......@@ -19,20 +19,20 @@ void CameraHandlingSystem::update(vcl::camera_scene& camera, MyEcs& m_ecs, ecs::
const auto sagittalAxis = normalize(transform.rotation * vec3{ 0, 1, 0 });
const auto lateralAxis = normalize(transform.rotation * vec3{ 1, 0, 0 });
camera.translation = -transform.position - lateralAxis * 0.5f - verticalAxis * 0.4f;
camera.translation = -transform.position - lateralAxis * 0.5f - verticalAxis * 0.6f;
if (isActive(Control::Shoot))
createRay(m_ecs, playerEntity, aimCursorEntity, /*transform.position + verticalAxis * 0.4f*/ camera, /*camera.orientation * vec3(0,0.15f,-1)*/ transform);
createRay(m_ecs, playerEntity, aimCursorEntity, camera, transform);
vcl::ray const shootInfos = vcl::picking_ray(camera, vec2(0, 0.1f));
vcl::ray const shootInfos = vcl::picking_ray(camera, m_cursorPosition);
auto& cursorPosition = m_ecs.get<TransformComponent>(aimCursorEntity).position;
cursorPosition = shootInfos.p + shootInfos.u * camera.scale;
}
void createRay(MyEcs& m_ecs, ecs::Entity const& playerEntity, ecs::Entity const& aimCursorEntity, vcl::camera_scene const& camera, TransformComponent const& playerTransform)
void CameraHandlingSystem::createRay(MyEcs& m_ecs, ecs::Entity const& playerEntity, ecs::Entity const& aimCursorEntity, vcl::camera_scene const& camera, TransformComponent const& playerTransform)
{
auto toolRayEntity = m_ecs.createEntity();
vcl::ray const shootInfos = vcl::picking_ray(camera, vec2(0, 0.1f));
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);
m_ecs.getSystem<RayTrajectory>().computeRayTrajectory(toolRay, m_ecs);
m_ecs.getSystem<RayTrajectory>().addDeadRay(toolRay);
......@@ -41,7 +41,7 @@ void createRay(MyEcs& m_ecs, ecs::Entity const& playerEntity, ecs::Entity const&
cursorPosition = shootInfos.p + shootInfos.u * camera.scale;
auto realRayEntity = m_ecs.createEntity();
float const speed = 5.0f;
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);
......
......@@ -11,9 +11,14 @@ struct MyEcs;
struct CameraHandlingSystem
{
public:
void update(vcl::camera_scene& camera, MyEcs& myEcs, ecs::Entity const& playerEntity, ecs::Entity const& aimCursorEntity, PlayerControlComponent const& controls, TransformComponent const& transform);
void createRay(MyEcs& m_ecs, ecs::Entity const& playerEntity, ecs::Entity const& aimCursorEntity, vcl::camera_scene const& camera, TransformComponent const& playerTransform);
using Requirements = ecs::Requirements<ecs::Auto>;
using Requirements = ecs::Requirements<ecs::Auto, PlayerComponent>;
using UpdatePolicy = ecs::OncePerEntity;
private:
vcl::vec2 m_cursorPosition{ 0.0f, 0.2f };
};
#endif // !SYSTEMS_CAMERA_HANDLING_HPP_INCLUDED
......@@ -5,6 +5,7 @@ using namespace vcl;
enum CollisionDirection : int { Top, Bottom, Side };
static CollisionDirection getCollisionDirectionWithOneMoving(CollisionCylinder const& cylinderA, DerivedTransformComponent const& dTransformA, CollisionCylinder const& cylinderB);
static CollisionDirection getCollisionDirectionWithBothMoving(CollisionCylinder const& cylinderA, DerivedTransformComponent const& dTransformA, CollisionCylinder const& cylinderB, DerivedTransformComponent const& dTransformB);
constexpr auto EPSILON = 0.001f;
......@@ -36,6 +37,7 @@ 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;
......@@ -91,9 +93,48 @@ struct NotImplementedError : public std::logic_error
{}
};
void CollisionResolver::handleCollisionWithBothMoving(CollisionCylinder const& /*collidingCylinderA*/, CollisionComponent& /*collisionComponentA*/, DerivedTransformComponent& /*dTransformA*/, CollisionCylinder const& /*collidingCylinderB*/, CollisionComponent& /*collisionComponentB*/, DerivedTransformComponent& /*dTransformB*/, float /*slowdownRate*/)
void CollisionResolver::handleCollisionWithBothMoving(CollisionCylinder const& cylinderA, CollisionComponent& collisionComponentA, DerivedTransformComponent& dTransformA, CollisionCylinder const& cylinderB, CollisionComponent& collisionComponentB, DerivedTransformComponent& dTransformB, float slowdownRate)
{
throw NotImplementedError{"Et c'est la panique !! Cette fonctionnalité n'est pas encore implémentée."};
CollisionDirection typeOfCollision = getCollisionDirectionWithBothMoving(cylinderA, dTransformA, cylinderB, dTransformB);
vec3 normal;
float dist;
switch (typeOfCollision)
{
case Top:
normal = vec3(0, 0, 1);// Formula for tilted normal : cylinderB.center - (cylinderA.center + vec3(0, 0, cylinderA.height / 2));
normal = normalize(normal);
dist = cylinderB.height + cylinderB.center.z - cylinderA.center.z + EPSILON;
collisionComponentA.shape.setPosition(collisionComponentA.shape.getPosition() + dist / 2 * normal);
collisionComponentB.shape.setPosition(collisionComponentB.shape.getPosition() - dist / 2 * normal);
break;
case Bottom:
normal = vec3(0, 0, -1);
normal = normal / norm(normal);
dist = cylinderB.height + cylinderB.center.z - cylinderA.center.z + EPSILON;
collisionComponentA.shape.setPosition(collisionComponentA.shape.getPosition() + dist / 2 * normal);
collisionComponentB.shape.setPosition(collisionComponentB.shape.getPosition() - dist / 2 * normal); break;
case Side:
auto positionA = collisionComponentA.shape.getPosition();
auto positionB = collisionComponentB.shape.getPosition();
normal = vec3(positionA.x - positionB.x, positionA.y - positionB.y, 0);
normal = normalize(normal);
vec2 posAHorizontal{ positionA.x, positionA.y };
vec2 posBHorizontal{ positionB.x, positionB.y };
dist = -norm(posAHorizontal - posBHorizontal) + cylinderB.radius + cylinderA.radius + EPSILON;
collisionComponentA.shape.setPosition(collisionComponentA.shape.getPosition() + dist / 2 * normal);
collisionComponentB.shape.setPosition(collisionComponentB.shape.getPosition() - dist / 2 * normal);
}
vec3& speedA = dTransformA.speed;
float dotProduct = dot(speedA, normal);
speedA = slowdownRate * (speedA - 2 * dotProduct * normal);
vec3& speedB = dTransformB.speed;
dotProduct = dot(speedB, normal);
speedB = slowdownRate * (speedB - 2 * dotProduct * normal);
}
static float getTimeAtDistance(vec3 const positionA, vec3 const speedA, vec3 const positionB, const float distance)
......@@ -116,3 +157,15 @@ static CollisionDirection getCollisionDirectionWithOneMoving(CollisionCylinder c
return CollisionDirection::Bottom;
return Side;
}
static CollisionDirection getCollisionDirectionWithBothMoving(CollisionCylinder const& cylinderA, DerivedTransformComponent const& dTransformA, CollisionCylinder const& cylinderB, DerivedTransformComponent const& dTransformB)
{
const float t_0 = getTimeAtDistance(cylinderA.center, dTransformA.speed - dTransformB.speed, cylinderB.center, cylinderA.radius + cylinderB.radius);
const float zAAtT0 = cylinderA.center.z + t_0 * dTransformA.speed.z;
const float zBAtT0 = cylinderB.center.z + t_0 * dTransformB.speed.z;
if (zAAtT0 > zBAtT0 + cylinderB.height)
return CollisionDirection::Top;
if (zAAtT0 + cylinderA.height < zBAtT0)
return CollisionDirection::Bottom;
return Side;
}
#include "lockdown_system.hpp"
#include "../my_ecs.hpp"
void LockdownSystem::update(TransformComponent& transform)
{
assert(terrainGeometry);
float xShift = std::max(transform.position.x - frontierFactor * terrainGeometry->xMax(), .0f) + std::min(transform.position.x - frontierFactor * terrainGeometry->xMin(), .0f);
float yShift = std::max(transform.position.y - frontierFactor * terrainGeometry->yMax(), .0f) + std::min(transform.position.y - frontierFactor * terrainGeometry->yMin(), .0f);
transform.position.x -= xShift;
transform.position.y -= yShift;
}
\ No newline at end of file
#ifndef SYSTEMS_LOCKDOWN_SYSTEM_HPP_INCLUDED
#define SYSTEMS_LOCKDOWN_SYSTEM_HPP_INCLUDED
#include "ECS.hpp"
#include "../components.hpp"
#include "../others/terrain_geometry.hpp"
struct LockdownSystem
{
void update(TransformComponent& transform);
using Requirements = ecs::Requirements<ecs::Auto, PlayerControlComponent>;
using UpdatePolicy = ecs::OncePerEntity;
const TerrainGeometry* terrainGeometry{ nullptr };
float frontierFactor = 0.95f;
};
#endif // !SYSTEMS_LOCKDOWN_SYSTEM_HPP_INCLUDED
......@@ -3,6 +3,7 @@
void RayRender::update(scene_structure& scene, std::map<std::string, GLuint>& shaders, RayComponent const& ray)
{
segment_drawer.uniform_parameter.p1 = ray.position;
segment_drawer.uniform_parameter.p2 = *ray.endTrajectory;
vcl::vec3 shortEnd = ray.position + 2 * vcl::normalize(ray.direction);
segment_drawer.uniform_parameter.p2 = norm(shortEnd - ray.position) < norm(*ray.endTrajectory - ray.position) ? shortEnd : *ray.endTrajectory;
segment_drawer.draw(shaders["segment_im"], scene.camera);
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ static vcl::vec3 getPositionAtZ(vcl::vec3 const& a, vcl::vec3 const& b, float co
if (std::abs(a.z - b.z) < epsilon)
return a;
float const lambda = (z - a.z) / (b.z - a.z);
return a + lambda * b;
return (1 - lambda) * a + lambda * b;
}
......@@ -44,10 +44,15 @@ static std::optional<vcl::vec3> getBulletImpact(RayComponent const& ray, Collisi
res = intersect1;
else if (intersect1.z < cylinder.center.z)
{
res = getPositionAtZ(intersect1, intersect2, cylinder.center.z);
}
else if (intersect1.z > cylinder.center.z + cylinder.height)
{
res = getPositionAtZ(intersect1, intersect2, cylinder.center.z + cylinder.height);
}
return res;
}
......
......@@ -23,9 +23,9 @@ mat3 rotation_between_vector_mat3(const vec3& a, const vec3& b)
const vec3 u0 = normalize(a);
const vec3 u1 = normalize(b);
if( norm(u0-u1)<1e-4f )
if( norm(u0-u1)<5e-4f )
return mat3::identity();
if( norm(u0+u1)<1e-4f )
if( norm(u0+u1)<5e-4f )
return -mat3::identity();
const float d = dot(u0,u1);
......