From acd16970bc93712e7c8c3996816242a04999818b Mon Sep 17 00:00:00 2001
From: Dan Goodliffe <dan@randomdan.homeip.net>
Date: Sat, 6 Mar 2021 18:53:22 +0000
Subject: Introduce the Train concept as a literal collection of rail vehicles

---
 game/vehicles/railloco.cpp | 59 +++++++++++++++++-----------------------------
 game/vehicles/railloco.h   | 51 +++++++++++++++++----------------------
 game/vehicles/vehicle.h    |  7 +++---
 3 files changed, 47 insertions(+), 70 deletions(-)

(limited to 'game')

diff --git a/game/vehicles/railloco.cpp b/game/vehicles/railloco.cpp
index 2650120..6745c8f 100644
--- a/game/vehicles/railloco.cpp
+++ b/game/vehicles/railloco.cpp
@@ -6,6 +6,7 @@
 #include <array>
 #include <cache.h>
 #include <filesystem>
+#include <functional>
 #include <glm/glm.hpp>
 #include <iterator>
 #include <lib/resource.h>
@@ -52,8 +53,9 @@ RailVehicleClass::bogieOffset(ObjParser & o)
 	float wheelBase {0};
 	// offset bogie positions so they can be set directly
 	for (auto & object : o.objects) { // bogie object index
-		if (!object.first.starts_with("Bogie"))
+		if (!object.first.starts_with("Bogie")) {
 			continue;
+		}
 		std::set<std::pair<float, int>> vertexIds;
 		for (const auto & face : object.second) {
 			for (const auto & faceElement : face) {
@@ -85,13 +87,13 @@ RailVehicle::render(const Shader & shader) const
 }
 
 void
-RailLoco::move(TickDuration dur)
+Train::move(TickDuration dur)
 {
 	static std::mt19937 gen(std::random_device {}());
 	linkDist += dur.count() * speed;
 	auto curLink {linkHist.getCurrent()};
 	while (linkDist > curLink.first->length) {
-		location = curLink.first->positionAt(curLink.first->length, curLink.second);
+		const auto location = curLink.first->positionAt(curLink.first->length, curLink.second);
 		auto nexts {curLink.first->nexts[1 - curLink.second]};
 		auto last = std::remove_if(nexts.begin(), nexts.end(), [ang = location.rot.y](const Link::Next & n) {
 			return std::abs(normalize(n.first.lock()->ends[n.second].second - ang)) > 0.1F;
@@ -108,8 +110,14 @@ RailLoco::move(TickDuration dur)
 	}
 }
 
+void
+Train::render(const Shader & shader) const
+{
+	apply(&Renderable::render, shader);
+}
+
 Location
-RailLoco::getBogiePosition(float linkDist, float dist) const
+Train::getBogiePosition(float linkDist, float dist) const
 {
 	float b2linkDist {};
 	const auto b2Link = linkHist.getAt(dist - linkDist, &b2linkDist);
@@ -117,45 +125,22 @@ RailLoco::getBogiePosition(float linkDist, float dist) const
 }
 
 void
-RailLoco::updateRailVehiclePosition(RailVehicle * w, float trailBy) const
+RailVehicle::move(const Train * t, float & trailBy)
 {
-	const auto overhang {(w->rvClass->length - w->rvClass->wheelBase) / 2};
-	const auto & b1Pos = w->bogies[0] = getBogiePosition(linkDist, trailBy += overhang);
-	const auto & b2Pos = w->bogies[1] = getBogiePosition(linkDist, trailBy + rvClass->wheelBase);
+	const auto overhang {(rvClass->length - rvClass->wheelBase) / 2};
+	const auto & b1Pos = bogies[0] = t->getBogiePosition(t->linkDist, trailBy += overhang);
+	const auto & b2Pos = bogies[1] = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase);
 	const auto diff = glm::normalize(b2Pos.pos - b1Pos.pos);
-	w->location.pos = (b1Pos.pos + b2Pos.pos) / 2.F;
-	w->location.rot = {-vector_pitch(diff), vector_yaw(diff), 0};
+	location.pos = (b1Pos.pos + b2Pos.pos) / 2.F;
+	location.rot = {-vector_pitch(diff), vector_yaw(diff), 0};
+	trailBy += 0.6F + overhang;
 }
 
 void
-RailLoco::tick(TickDuration dur)
+Train::tick(TickDuration dur)
 {
 	move(dur);
-	updateRailVehiclePosition(this, 0);
-	updateWagons();
-}
-
-void
-RailLoco::updateWagons() const
-{
-	// Drag wagons
-	float trailBy {rvClass->length + 0.6F};
-	for (const auto & wagon : wagons) {
-		const auto w {wagon.lock()};
-		updateRailVehiclePosition(w.get(), trailBy);
-		trailBy += w->rvClass->length + 0.6F;
-	}
-}
-
-void RailWagon::tick(TickDuration) { }
 
-Brush47::Brush47(const LinkPtr & l) : RailLoco(std::make_shared<RailVehicleClass>("brush47"), l, 0)
-{
-	speed = 33.6F;
-	linkDist = rvClass->wheelBase;
-}
-
-Brush47Wagon::Brush47Wagon(const LinkPtr & l) : RailWagon(std::make_shared<RailVehicleClass>("brush47"), l, 0)
-{
-	linkDist = rvClass->wheelBase;
+	float trailBy {0.F};
+	apply(&RailVehicle::move, this, std::ref(trailBy));
 }
diff --git a/game/vehicles/railloco.h b/game/vehicles/railloco.h
index 1bc0a51..0f240e2 100644
--- a/game/vehicles/railloco.h
+++ b/game/vehicles/railloco.h
@@ -2,7 +2,9 @@
 #include "game/vehicles/vehicle.h"
 #include "game/worldobject.h"
 #include "gfx/models/mesh.h"
+#include "gfx/renderable.h"
 #include <array>
+#include <collection.hpp>
 #include <location.hpp>
 #include <memory>
 #include <string>
@@ -32,47 +34,36 @@ private:
 };
 using RailVehicleClassPtr = std::shared_ptr<RailVehicleClass>;
 
-class RailVehicle : public Vehicle {
+class Train;
+class RailVehicle : public Renderable {
 public:
-	explicit RailVehicle(RailVehicleClassPtr rvc, const LinkPtr & link, float linkDist = 0) :
-		Vehicle {link, linkDist}, rvClass {std::move(rvc)}
-	{
-	}
+	explicit RailVehicle(RailVehicleClassPtr rvc) : rvClass {std::move(rvc)} { }
+
+	void move(const Train *, float & trailBy);
+
 	void render(const Shader & shader) const override;
 
+	Location location;
+
 	RailVehicleClassPtr rvClass;
 	std::array<Location, 2> bogies;
-
-	friend class RailLoco;
 };
+using RailVehiclePtr = std::unique_ptr<RailVehicle>;
 
-class RailWagon : public RailVehicle {
+class Train : public Vehicle, public Collection<RailVehicle, false> {
 public:
-	using RailVehicle::RailVehicle;
-	void tick(TickDuration elapsed) override;
-};
-using RailWagonPtr = std::weak_ptr<RailWagon>;
+	explicit Train(const LinkPtr & link, float linkDist = 0) : Vehicle {link, linkDist} { }
 
-class RailLoco : public RailVehicle {
-public:
-	using RailVehicle::RailVehicle;
-	void tick(TickDuration elapsed) override;
+	[[nodiscard]] const Location &
+	getLocation() const override
+	{
+		return objects.front()->location;
+	}
 
-	std::vector<RailWagonPtr> wagons;
+	void render(const Shader & shader) const override;
+
+	void tick(TickDuration elapsed) override;
 
-private:
 	void move(TickDuration dur);
 	[[nodiscard]] Location getBogiePosition(float linkDist, float dist) const;
-	void updateRailVehiclePosition(RailVehicle *, float trailBy) const;
-	void updateWagons() const;
-};
-
-class Brush47 : public RailLoco {
-public:
-	explicit Brush47(const LinkPtr & p);
-};
-
-class Brush47Wagon : public RailWagon {
-public:
-	explicit Brush47Wagon(const LinkPtr & p);
 };
diff --git a/game/vehicles/vehicle.h b/game/vehicles/vehicle.h
index a511d3c..89a6901 100644
--- a/game/vehicles/vehicle.h
+++ b/game/vehicles/vehicle.h
@@ -4,11 +4,12 @@
 #include <game/network/link.h>
 #include <game/worldobject.h>
 #include <gfx/renderable.h>
-#include <location.hpp>
 #include <memory>
 #include <utility>
 #include <vector>
 
+class Location;
+
 class LinkHistory {
 public:
 	using WEntry = std::pair<LinkWPtr, unsigned char /*dir*/>;
@@ -25,10 +26,10 @@ private:
 class Vehicle : public WorldObject, public Renderable {
 public:
 	explicit Vehicle(const LinkPtr & link, float linkDist = 0);
-	float linkDist; // distance long current link
+	float linkDist; // distance along current link
 	float speed {50}; // speed in m/s (~75 km/h)
 
-	Location location;
+	[[nodiscard]] virtual const Location & getLocation() const = 0;
 
 protected:
 	LinkHistory linkHist;
-- 
cgit v1.2.3