-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
304 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |