Skip to content

Commit

Permalink
first pass rope system
Browse files Browse the repository at this point in the history
  • Loading branch information
fallahn committed Nov 11, 2024
1 parent 977d1ef commit 1e36caf
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 0 deletions.
2 changes: 2 additions & 0 deletions samples/golf/golf.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@
<ClCompile Include="src\golf\ProgressIcon.cpp" />
<ClCompile Include="src\golf\PropFollowSystem.cpp" />
<ClCompile Include="src\golf\RayResultCallback.cpp" />
<ClCompile Include="src\golf\RopeSystem.cpp" />
<ClCompile Include="src\golf\server\EightballDirector.cpp" />
<ClCompile Include="src\golf\server\NineballDirector.cpp" />
<ClCompile Include="src\golf\server\Server.cpp" />
Expand Down Expand Up @@ -826,6 +827,7 @@
<ClInclude Include="src\golf\PuttingState.hpp" />
<ClInclude Include="src\golf\RandNames.hpp" />
<ClInclude Include="src\golf\RayResultCallback.hpp" />
<ClInclude Include="src\golf\RopeSystem.hpp" />
<ClInclude Include="src\golf\ScoreStrings.hpp" />
<ClInclude Include="src\golf\ScoreType.hpp" />
<ClInclude Include="src\golf\server\BilliardsDirector.hpp" />
Expand Down
6 changes: 6 additions & 0 deletions samples/golf/golf.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,9 @@
<ClCompile Include="src\golf\TimeOfDay.cpp">
<Filter>Source Files\golf\client\time of day</Filter>
</ClCompile>
<ClCompile Include="src\golf\RopeSystem.cpp">
<Filter>Source Files\golf\client\systems</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\ErrorCheck.hpp">
Expand Down Expand Up @@ -1040,6 +1043,9 @@
<ClInclude Include="src\golf\TimeOfDay.hpp">
<Filter>Header Files\golf\client\time of day</Filter>
</ClInclude>
<ClInclude Include="src\golf\RopeSystem.hpp">
<Filter>Header Files\golf\client\systems</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="src\golf\OptionsEnum.inl">
Expand Down
1 change: 1 addition & 0 deletions samples/golf/src/golf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ set(GOLF_SRC
#${PROJECT_DIR}/golf/PuttingState.cpp
#${PROJECT_DIR}/golf/PuttingStateUI.cpp
${PROJECT_DIR}/golf/RayResultCallback.cpp
${PROJECT_DIR}/golf/RopeSystem.cpp
${PROJECT_DIR}/golf/SharedStateData.cpp
${PROJECT_DIR}/golf/SoundEffectsDirector.cpp
${PROJECT_DIR}/golf/SpectatorSystem.cpp
Expand Down
192 changes: 192 additions & 0 deletions samples/golf/src/golf/RopeSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*-----------------------------------------------------------------------
Matt Marchant 2024
http://trederia.blogspot.com
Super Video Golf - zlib licence.
This software is provided 'as-is', without any express or
implied warranty.In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions :
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
-----------------------------------------------------------------------*/

#include "RopeSystem.hpp"

#include <crogine/ecs/Scene.hpp>
#include <crogine/ecs/components/Transform.hpp>

namespace
{
constexpr glm::vec3 Gravity(0.f, -9.f, 0.f);
}

RopeSystem::RopeSystem(cro::MessageBus& mb)
: cro::System(mb, typeid(RopeSystem))
{
requireComponent<cro::Transform>();
requireComponent<RopeNode>();
}

//public
void RopeSystem::process(float dt)
{
for (auto& rope : m_ropes)
{
rope.simulate(dt);
}
}

std::size_t RopeSystem::addRope(glm::vec3 start, glm::vec3 end, float slack)
{
auto ret = m_ropes.size();
m_ropes.emplace_back(start, end, slack, *getScene());

return ret;
}

//private
void RopeSystem::onEntityAdded(cro::Entity e)
{
const auto& node = e.getComponent<RopeNode>();
if (node.ropeID < m_ropes.size())
{
m_ropes[node.ropeID].addNode(e);
}
else
{
LogW << "Tried adding node to rope " << node.ropeID << " which doesn't exist." << std::endl;
getScene()->destroyEntity(e);
}
}

void RopeSystem::onEntityRemoved(cro::Entity e)
{
const auto& node = e.getComponent<RopeNode>();
CRO_ASSERT(node.ropeID < m_ropes.size());

m_ropes[node.ropeID].removeNode(e);
}


//-------rope class-------//
Rope::Rope(glm::vec3 start, glm::vec3 end, float /*slack*/, cro::Scene& scene)
: m_nodeSpacing(0.f)
{
auto ent = scene.createEntity();
ent.addComponent<cro::Transform>();
ent.addComponent<RopeNode>().position = start;
ent.getComponent<RopeNode>().prevPosition = start;
m_nodes.push_back(ent);

ent = scene.createEntity();
ent.addComponent<cro::Transform>();
ent.addComponent<RopeNode>().position = end;
ent.getComponent<RopeNode>().prevPosition = end;
m_nodes.push_back(ent);

//this always pins the first and last point
//as it's possible that the entities may get removed
recalculate();
}

//public
void Rope::addNode(cro::Entity e)
{
m_nodes.push_back(e);
recalculate();
}

void Rope::removeNode(cro::Entity e)
{
m_nodes.erase(std::remove_if(m_nodes.begin(), m_nodes.end(),
[e](cro::Entity ent)
{
return e == ent;
}), m_nodes.end());
recalculate();
}

void Rope::simulate(float dt)
{
if (m_nodes.size() > 2)
{
integrate(dt);
constrain();
}
}

//private
void Rope::recalculate()
{
if (!m_nodes.empty())
{
if (m_nodes.size() > 1)
{
auto position = m_nodes.front().getComponent<RopeNode>().position;
auto stride = m_nodes.back().getComponent<RopeNode>().position - position;

if (glm::length2(stride) != 0)
{
float len = glm::length(stride) + 0.001f;

//TODO add any slack we want to stride
//which should be a RATIO not a fixed length
m_nodeSpacing = len;

stride = glm::normalize(stride) * (len / (m_nodes.size() - 1));
}

for (auto node : m_nodes)
{
auto& n = node.getComponent<RopeNode>();
n.position = position;
n.prevPosition = position;
n.force = glm::vec3(0.f);
n.fixed = false;
}
}

m_nodes.front().getComponent<RopeNode>().fixed = true;
m_nodes.back().getComponent<RopeNode>().fixed = true;
}
}

void Rope::integrate(float dt)
{
for (auto node : m_nodes)
{
auto& n = node.getComponent<RopeNode>();
//this means we're delayed one frame, but it has to happen
//after we apply the constraints from the previous integration
node.getComponent<cro::Transform>().setPosition(n.position);

if (!n.fixed)
{
auto old = n.position;
n.position = 2.f * n.position - n.prevPosition + ((n.force + Gravity) * dt * dt);
n.prevPosition = old;
}
}
}

void Rope::constrain()
{
static constexpr std::size_t MaxIterations = 30;
}
103 changes: 103 additions & 0 deletions samples/golf/src/golf/RopeSystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*-----------------------------------------------------------------------
Matt Marchant 2024
http://trederia.blogspot.com
Super Video Golf - zlib licence.
This software is provided 'as-is', without any express or
implied warranty.In no event will the authors be held
liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions :
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but
is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any
source distribution.
-----------------------------------------------------------------------*/

#pragma once

#include <crogine/ecs/System.hpp>

//component on an entity, used to
//update the entity final position
struct RopeNode final
{
glm::vec3 position = glm::vec3(0.f);
glm::vec3 prevPosition = glm::vec3(0.f);
bool fixed = false;

//ID of the rope to which this node
//will belong. Must be valid when ent
//is created, editing afterwards has
//no effect. ID is returned from
//RopeSystem::addRope();
std::size_t ropeID = std::numeric_limits<std::size_t>::max();

//any external force added to this node
glm::vec3 force = glm::vec3(0.f);
};

//represents a collection of nodes in
//a single verlet simulation. Multiple of
//these may exist in the system
class Rope final
{
public:
Rope(glm::vec3 start, glm::vec3 end, float slack, cro::Scene&);

void addNode(cro::Entity);

//TODO it's possible to destroy entities outside
//of this system - this func just tidies up loose
//references - I have no idea how it'll behave though...
void removeNode(cro::Entity);

void simulate(float);

private:

//we iterate over these in he simaultion rather than the system's entity list
std::vector<cro::Entity> m_nodes;
float m_nodeSpacing;
void recalculate(); //called when adding a new node

void integrate(float dt);
void constrain();
};

class RopeSystem final : public cro::System
{
public:
explicit RopeSystem(cro::MessageBus&);

void process(float) override;

//creates a new rope between the given fixed points.
//returns an ID to use with components when assigning
//those entities to a specific rope.
//increase slack for a looser rope between fixed points
std::size_t addRope(glm::vec3, glm::vec3, float slack = 0.f);

private:
std::vector<Rope> m_ropes;

//validates the rope in the component ID
//exists and adds it to the rop if it does
void onEntityAdded(cro::Entity) override;

//removes the entity from a rope
void onEntityRemoved(cro::Entity) override;
};

0 comments on commit 1e36caf

Please sign in to comment.