250 lines
8.6 KiB
C++
250 lines
8.6 KiB
C++
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
|
|
#include "physics/Body.h"
|
|
#include "physics/Body3D.h"
|
|
#include "physics/Physics.h"
|
|
#include "physics/World.h"
|
|
#include "physics/World3D.h"
|
|
#include "vehicle/Vehicle.h"
|
|
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
using namespace eve::vehicle;
|
|
|
|
TEST_CASE("vehicle.physics2d.wheelDrivesAndSteers") {
|
|
eve::physics::Physics ph;
|
|
eve::physics::World* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
CHECK_EQ(mod.registerVehiclesFromJson("[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":120,"
|
|
"\"accel\":100,\"turnRate\":120,\"radius\":18}]"),
|
|
1);
|
|
VehicleEntity* v = mod.newVehicle("car", 0.f, 0.f, 0.f);
|
|
REQUIRE(v != nullptr);
|
|
CHECK(mod.attachPhysics2D(v, world));
|
|
CHECK(mod.hasPhysics(v));
|
|
CHECK_EQ(mod.getPhysicsSpace(v), std::string("2d"));
|
|
|
|
mod.setInput(v, 1.f, 0.f, 0.f);
|
|
for (int i = 0; i < 60; ++i) {
|
|
mod.update(1.f / 60.f);
|
|
world->update(1.f / 60.f);
|
|
}
|
|
CHECK_GT(mod.getX(v), 30.f);
|
|
CHECK_GT(mod.getSpeed(v), 60.f);
|
|
|
|
mod.setInput(v, 0.7f, 1.f, 0.f);
|
|
const float h0 = mod.getHeading(v);
|
|
for (int i = 0; i < 60; ++i) {
|
|
mod.update(1.f / 60.f);
|
|
world->update(1.f / 60.f);
|
|
}
|
|
CHECK_GT(mod.getHeading(v), h0 + 10.f);
|
|
}
|
|
|
|
TEST_CASE("vehicle.physics2d.trackRotatesInPlace") {
|
|
eve::physics::Physics ph;
|
|
eve::physics::World* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
CHECK_EQ(mod.registerVehiclesFromJson("[{\"id\":\"tank\",\"mobility\":\"track\",\"maxSpeed\":100,"
|
|
"\"accel\":80,\"turnRate\":150,\"radius\":20}]"),
|
|
1);
|
|
VehicleEntity* v = mod.newVehicle("tank", 100.f, 100.f, 0.f);
|
|
REQUIRE(v != nullptr);
|
|
CHECK(mod.attachPhysics2D(v, world));
|
|
|
|
mod.setInput(v, 0.f, 1.f, 0.f);
|
|
for (int i = 0; i < 60; ++i) {
|
|
mod.update(1.f / 60.f);
|
|
world->update(1.f / 60.f);
|
|
}
|
|
CHECK_GT(std::fabs(mod.getHeading(v)), 40.f);
|
|
CHECK_LT(std::fabs(mod.getX(v) - 100.f), 8.f);
|
|
CHECK_LT(std::fabs(mod.getY(v) - 100.f), 8.f);
|
|
}
|
|
|
|
TEST_CASE("vehicle.physics3d.suspensionDrives") {
|
|
eve::physics::Physics ph;
|
|
eve::physics::World3D* world3 = ph.newWorld3D(0.f, -9.8f, 0.f, true);
|
|
REQUIRE(world3 != nullptr);
|
|
eve::physics::Body3D* ground = world3->newBody("static", 0.f, -0.5f, 0.f);
|
|
REQUIRE(ground != nullptr);
|
|
ground->newBoxShape(60.f, 0.5f, 60.f, 1.f, 0.8f, 0.f);
|
|
|
|
const char* suv = R"JSON(
|
|
[{"id":"suv","mobility":"suspension","maxSpeed":16,"turnRate":60,"radius":1.0,
|
|
"suspension":{"maxTravel":0.25,"driveForce":3000,"lateralGrip":10,
|
|
"wheels":[
|
|
{"x":-0.9,"y":-0.35,"z":-1.2,"radius":0.3,"rest":0.35,"stiffness":30000,"damping":3000,"drive":true,"steer":true},
|
|
{"x":0.9,"y":-0.35,"z":-1.2,"radius":0.3,"rest":0.35,"stiffness":30000,"damping":3000,"drive":true,"steer":true},
|
|
{"x":-0.9,"y":-0.35,"z":1.2,"radius":0.3,"rest":0.35,"stiffness":30000,"damping":3000,"drive":false,"steer":false},
|
|
{"x":0.9,"y":-0.35,"z":1.2,"radius":0.3,"rest":0.35,"stiffness":30000,"damping":3000,"drive":false,"steer":false}]}}]
|
|
)JSON";
|
|
Vehicle mod;
|
|
CHECK_EQ(mod.registerVehiclesFromJson(suv), 1);
|
|
VehicleEntity* v = mod.newVehicle("suv", 0.f, 0.f, 0.f);
|
|
REQUIRE(v != nullptr);
|
|
CHECK(mod.attachPhysics3D(v, world3, 2.0f));
|
|
CHECK_EQ(mod.getPhysicsSpace(v), std::string("3d"));
|
|
|
|
mod.setInput(v, 0.8f, 0.f, 0.f);
|
|
for (int i = 0; i < 240; ++i) {
|
|
mod.update(1.f / 60.f);
|
|
world3->update(1.f / 60.f);
|
|
}
|
|
CHECK_GT(mod.getY(v), 5.f);
|
|
CHECK_GT(mod.getHeight(v), 0.15f);
|
|
CHECK_LT(mod.getHeight(v), 2.5f);
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.detachInvalidatesBodyAndProjection") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
REQUIRE_EQ(mod.registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod.newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod.attachPhysics2D(vehicle, world));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
CHECK(mod.detachPhysics(vehicle));
|
|
CHECK(!mod.hasPhysics(vehicle));
|
|
CHECK_EQ(mod.getPhysicsSpace(vehicle), std::string{});
|
|
CHECK(!body->isValid());
|
|
|
|
delete body;
|
|
delete world;
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.externalBodyDestructionBecomesStale") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
REQUIRE_EQ(mod.registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod.newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod.attachPhysics2D(vehicle, world));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
body->destroy();
|
|
CHECK(!mod.hasPhysics(vehicle));
|
|
CHECK_EQ(mod.getPhysicsSpace(vehicle), std::string{});
|
|
mod.update(1.f / 60.f);
|
|
CHECK(mod.detachPhysics(vehicle));
|
|
CHECK_EQ(mod.getPhysicsSpace(vehicle), std::string{});
|
|
|
|
delete body;
|
|
delete world;
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.worldFirstDestructionIsSafe") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
REQUIRE_EQ(mod.registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod.newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod.attachPhysics2D(vehicle, world));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
delete world;
|
|
CHECK(!mod.hasPhysics(vehicle));
|
|
CHECK_EQ(mod.getPhysicsSpace(vehicle), std::string{});
|
|
mod.update(1.f / 60.f);
|
|
CHECK(mod.detachPhysics(vehicle));
|
|
CHECK(!body->isValid());
|
|
delete body;
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.vehicleFirstDestructionReleasesBody") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld(0.f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
auto mod = std::make_unique<Vehicle>();
|
|
REQUIRE_EQ(mod->registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod->newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod->attachPhysics2D(vehicle, world));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
mod.reset();
|
|
CHECK(!body->isValid());
|
|
CHECK(world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u)) == nullptr);
|
|
|
|
delete body;
|
|
delete world;
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.worldFirstDestructionIsSafe3D") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld3D(0.f, -9.8f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
Vehicle mod;
|
|
REQUIRE_EQ(mod.registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod.newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod.attachPhysics3D(vehicle, world, 2.f));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
delete world;
|
|
CHECK(!mod.hasPhysics(vehicle));
|
|
CHECK_EQ(mod.getPhysicsSpace(vehicle), std::string{});
|
|
CHECK_EQ(mod.getHeight(vehicle), 0.f);
|
|
mod.update(1.f / 60.f);
|
|
CHECK(mod.detachPhysics(vehicle));
|
|
CHECK(!body->isValid());
|
|
delete body;
|
|
}
|
|
|
|
TEST_CASE("vehicle.physicsLink.vehicleFirstDestructionReleasesBody3D") {
|
|
eve::physics::Physics ph;
|
|
auto* world = ph.newWorld3D(0.f, -9.8f, 0.f, true);
|
|
REQUIRE(world != nullptr);
|
|
|
|
auto mod = std::make_unique<Vehicle>();
|
|
REQUIRE_EQ(mod->registerVehiclesFromJson(
|
|
"[{\"id\":\"car\",\"mobility\":\"wheel\",\"maxSpeed\":20,\"radius\":2}]"),
|
|
1);
|
|
auto* vehicle = mod->newVehicle("car", 0.f, 0.f);
|
|
REQUIRE(vehicle != nullptr);
|
|
REQUIRE(mod->attachPhysics3D(vehicle, world, 2.f));
|
|
auto* body = world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u));
|
|
REQUIRE(body != nullptr);
|
|
|
|
mod.reset();
|
|
CHECK(!body->isValid());
|
|
CHECK(world->findBody(eve::physics::PhysicsBodyHandle(1u, 1u)) == nullptr);
|
|
|
|
delete body;
|
|
delete world;
|
|
}
|