#include "collectable_sim_ground.hpp" #include #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 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 CollectableSimGround::createSegment(float leftCorner, float rightCorner, std::shared_ptr 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(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; }