#include "collectable_sim_ground.hpp" #include #include "../../../../config.h" #include "../layouts/depth_hole_layout.hpp" void CollectableSimGround::closeAllHoles() { // Create one segment for the ground createSegment(-groundWidth / 2.f, groundWidth / 2.f); } void CollectableSimGround::createLayout(DepthHoleLayout &layout) { // TODO: Check if layout changed at all before clearing segments segments.clear(); if (layout.holes.empty()) { closeAllHoles(); return; } // Sort holes from left to right std::sort(layout.holes.begin(), layout.holes.end(), [](DepthHoleDescription a, DepthHoleDescription b) { return a.x < b.x; }); // Create segments for holes float leftCorner = -groundWidth / 2.f; for (auto &hole: layout.holes) { auto rightCorner = hole.x - hole.width / 2.f; createSegment(leftCorner, rightCorner); leftCorner = hole.x + hole.width / 2.f; } // Create segment for the right side createSegment(leftCorner, groundWidth / 2.f); } CollectableSimGround::CollectableSimGround(std::shared_ptr world, float groundWidth) : world(std::move(world)), groundWidth(0) { setGroundWidth(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); } } void 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; } 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); } CollectableSimGround::SideSegments CollectableSimGround::getOuterSegments(int holeId) { SideSegments sideSegments; for (const auto &segment: segments) { // If valid holeId, match left hole id // If invalid holeId, get outer segment if ((segment->leftHoleId == holeId && holeId >= 0) || (segment->rightHoleId < 0 && holeId < 0)) { sideSegments.right = segment; } if ((segment->rightHoleId == holeId && holeId >= 0) || (segment->leftHoleId < 0 && holeId < 0)) { sideSegments.left = segment; } } return sideSegments; }