193 lines
5 KiB
C++
193 lines
5 KiB
C++
#include "collectable_sim_ground.hpp"
|
|
|
|
#include <utility>
|
|
#include "../../../../config.h"
|
|
|
|
void CollectableSimGround::closeAllHoles()
|
|
{
|
|
// Create one segment for the ground
|
|
createSegment(-groundWidth / 2.f, groundWidth / 2.f);
|
|
}
|
|
|
|
void CollectableSimGround::createLayout(DepthHoleLayout &layout)
|
|
{
|
|
if (!hasLayoutChanged(layout))
|
|
{
|
|
return;
|
|
}
|
|
currentLayoutHoles = layout.holes;
|
|
segments.clear();
|
|
|
|
if (currentLayoutHoles.empty())
|
|
{
|
|
closeAllHoles();
|
|
return;
|
|
}
|
|
|
|
// Sort holes from left to right
|
|
std::sort(currentLayoutHoles.begin(), currentLayoutHoles.end(),
|
|
[](DepthHoleDescription a, DepthHoleDescription b)
|
|
{
|
|
return a.x < b.x;
|
|
});
|
|
|
|
// Create segments for holes
|
|
float leftCorner = -groundWidth / 2.f;
|
|
float leftHoleId = -1;
|
|
for (auto &hole: currentLayoutHoles)
|
|
{
|
|
auto rightCorner = hole.x - hole.width / 2.f;
|
|
auto segment = createSegment(leftCorner, rightCorner);
|
|
if (segment != nullptr)
|
|
{
|
|
segment->rightHoleId = hole.playerId;
|
|
segment->leftHoleId = leftHoleId;
|
|
}
|
|
|
|
leftHoleId = hole.playerId;
|
|
leftCorner = hole.x + hole.width / 2.f;
|
|
}
|
|
// Create segment for the right side
|
|
auto segment = createSegment(leftCorner, groundWidth / 2.f);
|
|
if (segment != nullptr)
|
|
{
|
|
segment->leftHoleId = leftHoleId;
|
|
}
|
|
}
|
|
|
|
CollectableSimGround::CollectableSimGround(std::shared_ptr<b2World> world, float groundWidth)
|
|
: world(std::move(world)), groundWidth(groundWidth)
|
|
{
|
|
closeAllHoles();
|
|
}
|
|
|
|
void CollectableSimGround::setGroundWidth(float width)
|
|
{
|
|
if (width <= 0)
|
|
{
|
|
throw std::runtime_error("Ground width must be greater than 0");
|
|
}
|
|
|
|
if (width == groundWidth)
|
|
{
|
|
return;
|
|
}
|
|
|
|
groundWidth = width;
|
|
updateOuterSegmentsToWidth();
|
|
}
|
|
|
|
void CollectableSimGround::updateOuterSegmentsToWidth()
|
|
{
|
|
auto outerSegments = getOuterSegments();
|
|
auto borderPoints = groundWidth / 2.f;
|
|
|
|
// Left segment
|
|
if (outerSegments.left != nullptr)
|
|
{
|
|
auto leftSegment = outerSegments.left->body;
|
|
auto leftCenter = leftSegment->getCenter();
|
|
auto leftSize = leftSegment->getSize();
|
|
auto rightPoint = leftCenter.x + leftSize.x / 2.f;
|
|
|
|
createSegment(-borderPoints, rightPoint, outerSegments.left);
|
|
}
|
|
|
|
// Right segment
|
|
if (outerSegments.right != nullptr)
|
|
{
|
|
auto rightSegment = outerSegments.right->body;
|
|
auto rightCenter = rightSegment->getCenter();
|
|
auto rightSize = rightSegment->getSize();
|
|
auto leftPoint = rightCenter.x - rightSize.x / 2.f;
|
|
|
|
createSegment(leftPoint, borderPoints, outerSegments.right);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<CollectableSimGroundSegment> CollectableSimGround::createSegment(float leftCorner, float rightCorner,
|
|
std::shared_ptr<CollectableSimGroundSegment> segment)
|
|
{
|
|
if (leftCorner > rightCorner)
|
|
{
|
|
// Segment would have negative width, don't create it and leave empty instead
|
|
return segment;
|
|
}
|
|
|
|
if (segment == nullptr)
|
|
{
|
|
segment = std::make_shared<CollectableSimGroundSegment>(world);
|
|
segments.push_back(segment);
|
|
}
|
|
|
|
auto center = sf::Vector2f((leftCorner + rightCorner) / 2.f, -COLLECTABLES_SIM_GROUND_THICKNESS / 2.f);
|
|
auto size = sf::Vector2f(rightCorner - leftCorner, COLLECTABLES_SIM_GROUND_THICKNESS);
|
|
|
|
segment->body->createSquare(b2_kinematicBody, center, size);
|
|
|
|
return segment;
|
|
}
|
|
|
|
CollectableSimGround::SideSegments CollectableSimGround::getOuterSegments()
|
|
{
|
|
SideSegments sideSegments;
|
|
|
|
for (const auto &segment: segments)
|
|
{
|
|
if (segment->rightHoleId < 0)
|
|
{
|
|
sideSegments.right = segment;
|
|
}
|
|
|
|
if (segment->leftHoleId < 0)
|
|
{
|
|
sideSegments.left = segment;
|
|
}
|
|
|
|
if (sideSegments.left != nullptr && sideSegments.right != nullptr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sideSegments;
|
|
}
|
|
|
|
bool CollectableSimGround::hasLayoutChanged(DepthHoleLayout &layout)
|
|
{
|
|
if (layout.holes.size() != currentLayoutHoles.size())
|
|
{
|
|
// Number of holes changed
|
|
return true;
|
|
}
|
|
|
|
// Below here: Number of holes is the same
|
|
if (currentLayoutHoles.empty())
|
|
{
|
|
// Both are empty, so no change
|
|
return false;
|
|
}
|
|
|
|
// Sort holes from left to right
|
|
std::sort(layout.holes.begin(), layout.holes.end(),
|
|
[](DepthHoleDescription a, DepthHoleDescription b)
|
|
{
|
|
return a.x < b.x;
|
|
});
|
|
|
|
// Compare holes
|
|
for (int i = 0; i < layout.holes.size(); i++)
|
|
{
|
|
auto currentHole = currentLayoutHoles[i];
|
|
auto newHole = layout.holes[i];
|
|
|
|
if (newHole.x != currentHole.x ||
|
|
newHole.width != currentHole.width)
|
|
{
|
|
// Hole changed
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|