Crafter.Debug/examples/Basic/implementations/Basic.World.cpp

65 lines
2.3 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
module Basic.World;
import std;
import Basic.DebugShim;
namespace Debug = Crafter::Debug;
void Basic::World::Reset() {
Clear();
constexpr std::array<float, 5> heights = { 1, 3, 8, 20, 60 };
for (std::size_t i = 0; i < heights.size(); ++i) {
Spawn(static_cast<float>(i) - 2.0f, heights[i], 0, 0.1f);
}
}
void Basic::World::Clear() {
balls.clear();
time = 0;
fastest = 0;
}
std::int32_t Basic::World::Spawn(float x, float y, float vy, float radius) {
const std::int32_t id = nextId++;
balls.push_back({ .id = id, .x = x, .y = y, .vy = vy, .radius = radius });
Debug::Log("world", "ball {} dropped from {:.1f} m", id, y);
return id;
}
void Basic::World::Tick(float dt) {
const std::int32_t steps = std::max(1, physics.substeps);
const float h = dt / static_cast<float>(steps);
const float bottom = floor.top - floor.thickness;
fastest = 0;
for (Ball& ball : balls) {
for (std::int32_t step = 0; step < steps; ++step) {
ball.vy += physics.gravity * h;
ball.x += ball.vx * h;
ball.y += ball.vy * h;
if (ball.lost) continue;
// A falling ball that overlaps the slab bounces off its top.
if (ball.vy < 0 && ball.y - ball.radius < floor.top && ball.y + ball.radius > bottom) {
const float speed = -ball.vy;
ball.y = floor.top + ball.radius;
ball.vy = speed * physics.restitution;
if (speed > 1) Debug::Emit("Bounce", BounceEvent{ .ball = ball.id, .speed = speed });
}
}
if (!ball.lost && !Debug::Check(ball.y + ball.radius >= bottom, "physics", "ball {} is below the floor: y {:.2f} m, vy {:.1f} m/s", ball.id, ball.y, ball.vy)) {
ball.lost = true;
}
fastest = std::max(fastest, std::hypot(ball.vx, ball.vy));
}
Debug::Sample("solver.fastest", fastest);
time += dt;
}
const Basic::Ball* Basic::World::Find(std::int32_t id) const {
const auto found = std::ranges::find(balls, id, &Ball::id);
return found == balls.end() ? nullptr : &*found;
}
std::int32_t Basic::World::Lost() const {
return static_cast<std::int32_t>(std::ranges::count(balls, true, &Ball::lost));
}