Working on taxi car

This commit is contained in:
Vladislav Khorev committed 2026-07-14 14:07:53 +03:00
1 parent 38e45d67b8
commit 35a2a91178
21 files changed
+26446 -45

No files matched your search

+115 -16
View File
@@ -230,8 +230,20 @@ namespace ZL
// so it stays a single synchronous function rather than being split into
// per-location queue steps; it's queued here as one coarse step.
loadSteps.push([this]() {
createLocations();
createLocationsStep1();
});
loadSteps.push([this]() {
createLocationsStep2();
});
loadSteps.push([this]() {
createLocationsStep3();
});
loadSteps.push([this]() {
createLocationsStep4();
});
loadSteps.push([this]() {
createLocationsStep5();
});
loadSteps.push([this]() {
// Wire inventory callbacks: tutorial tracking + toast notifications.
@@ -392,7 +404,11 @@ namespace ZL
}
gameState.inventory.clear();
gameState.questJournal.loadFromFile(localizedConfigPath("resources/config/quests.json", g_currentLanguage), CONST_ZIP_FILE);
createLocations();
createLocationsStep1();
createLocationsStep2();
createLocationsStep3();
createLocationsStep4();
createLocationsStep5();
// Developer workflow: uncomment to (re)generate resources/config/start_state.json
// from this freshly-rebuilt state after changing gameplay/content JSON or Lua.
@@ -432,25 +448,30 @@ namespace ZL
void Game::saveInitialState() {
nlohmann::json root;
gameState.save(root);
const std::string path = "resources/config/start_state.json";
/*
const std::string path = "start_state.json";
std::cout << "[reset] saveInitialState called, to " << path << std::endl;
std::ofstream file(path);
if (file.is_open()) {
file << root.dump(2);
std::cout << "[reset] Saved initial state snapshot to " << path << std::endl;
} else {
std::cerr << "[reset] Could not open " << path << " for writing" << std::endl;
}*/
}
saveJsonToFile(root, path);
}
void Game::createLocations()
void Game::createLocationsStep1()
{
gameState.locations.clear();
gameState.globalFloats["player_hp"] = 200;
}
void Game::createLocationsStep2()
{
LocationSetup uniInteriorParams;
uniInteriorParams.gameObjectsJsonPath = "resources/config/gameobjects_uni_interior_x.json";
uniInteriorParams.npcsJsonPath = "resources/config/npcs_uni_interior.json";
@@ -553,17 +574,33 @@ namespace ZL
gameState.locations["uni_interior"]->requestDarklandsPlayNormalMusic = [this]() {
audioPlayer->crossFadeMusicFromPositionAsync("audio/bishkek fight calm.ogg");
};
}
void Game::createLocationsStep3()
{
LocationSetup uniInteriorParams;
LocationSetup uniExteriorParams = uniInteriorParams;
uniExteriorParams.gameObjectsJsonPath = "resources/config/gameobjects_uni_exterior_x.json";
uniExteriorParams.interactiveObjectsJsonPath = "resources/config/interactive_objects_uni_exterior_x.json";
//uniExteriorParams.navigationJsonPaths = {"resources/navigation/uni_exterior3_all.json"};
/*
uniExteriorParams.navigationJsonPaths = {
"resources/navigation/uni_exterior3_trees_car.json",
"resources/navigation/uni_exterior3_trees.json",
"resources/navigation/uni_exterior0.json",
"resources/navigation/uni_exterior0.json"
};*/
//uni_exterior0
/*uniExteriorParams.navigationJsonPaths = {
"resources/navigation/uni_exterior3_all.json",
"resources/navigation/uni_exterior3_all.json"
};*/
/*
uniExteriorParams.navigationJsonPaths = {
"resources/navigation/uni_exterior3_trees_car.json",
"resources/navigation/uni_exterior3_trees.json",
};*/
uniExteriorParams.navigationJsonPaths = {
"resources/navigation/uni_exterior3_trees_car.txt",
"resources/navigation/uni_exterior3_trees.txt",
@@ -585,7 +622,7 @@ namespace ZL
gameState.locations["uni_exterior"]->requestNightDayTransition = [this](bool isNight, bool isDawn) {
gameState.isNight = isNight;
gameState.isDawn = isDawn;
};
};
gameState.locations["uni_exterior"]->requestDarklandsTransition = [this]() { return startDarklandsTransition(); };
gameState.locations["uni_exterior"]->requestClosePhone = [this]() { menuManager.closePhoneEntirely(); };
gameState.locations["uni_exterior"]->requestReturnToMainMenu = [this]() { menuManager.showMainMenu(); };
@@ -595,6 +632,34 @@ namespace ZL
if (gameState.locations["uni_exterior"]->player)
gameState.locations["uni_exterior"]->player->state.onDeathAnimComplete = [this]() { startDarklandsTransition(); };
//Exterior set up taxi:
gameState.locations["uni_exterior"]->state.taxiCarTriggerPosition = Eigen::Vector3f(-17.6, 0.05, -45);
gameState.locations["uni_exterior"]->state.taxiCarWaypoints = {
Vector3f(-17.6, 0.05, -90.0),
Vector3f(-17.6, 0.05, -75.0),
Vector3f(-17.6, 0.05, -55.0)
};
gameState.locations["uni_exterior"]->state.taxiCarInitialState.position = /*Vector3f(-17.6, 0.05, -40);*/ Vector3f(-17.6, 0.05, -100);
gameState.locations["uni_exterior"]->state.taxiCarInitialState.rotation = 180.f;
gameState.locations["uni_exterior"]->state.taxiCarInitialState.mode = NpcCar::Mode::NONE;
gameState.locations["uni_exterior"]->state.taxiCarInitialState.velocity = 0.f;
gameState.locations["uni_exterior"]->state.taxiCarInitialState.steeringAngle = 0.f;
gameState.locations["uni_exterior"]->state.taxiCarInitialState.waypointReachRadius = 5.f;
gameState.locations["uni_exterior"]->state.taxiCar = gameState.locations["uni_exterior"]->state.taxiCarInitialState;
//Exterior set up taxi end
}
void Game::createLocationsStep4()
{
LocationSetup params_dorm;
//params_dorm.gameObjectsJsonPath = "resources/config/gameobjects_dorm.json";
//params_dorm.gameObjectsJsonPath = "resources/config/gameobjects_dorm_trees001.json";
@@ -621,7 +686,7 @@ namespace ZL
"resources/navigation/dorm3_b.txt",
"resources/navigation/dorm3_all_open.txt", //5
};
/*
params_dorm.navigationJsonPaths = {
"resources/navigation/dorm0_large.json",
@@ -654,6 +719,35 @@ namespace ZL
gameState.locations["location_dorm"]->state.tutorialInteractiveObjectsLocked = true;
//Dorm set up taxi:
gameState.locations["location_dorm"]->state.taxiCarTriggerPosition = Eigen::Vector3f(-19.0, 0, 0);
gameState.locations["location_dorm"]->state.taxiCarWaypoints = {
Vector3f(-20.85, 0, 30.0),
Vector3f(-19.35, 0, 24.0),
Vector3f(-19.35, 0, 14.0)
};
gameState.locations["location_dorm"]->state.taxiCarInitialState.position = Vector3f(-20.85, 0, 64);
gameState.locations["location_dorm"]->state.taxiCarInitialState.rotation = 0.f;
gameState.locations["location_dorm"]->state.taxiCarInitialState.mode = NpcCar::Mode::NONE;
gameState.locations["location_dorm"]->state.taxiCarInitialState.velocity = 0.f;
gameState.locations["location_dorm"]->state.taxiCarInitialState.steeringAngle = 0.f;
gameState.locations["location_dorm"]->state.taxiCarInitialState.waypointReachRadius = 5.f;
gameState.locations["location_dorm"]->state.taxiCar = gameState.locations["location_dorm"]->state.taxiCarInitialState;
//Dorm set up taxi end
}
void Game::createLocationsStep5()
{
rearmDormOneShotCallbacks();
menuManager.callTaxiFunc = [this]()
@@ -665,7 +759,7 @@ namespace ZL
if (currentLocation())
{
currentLocation()->scriptEngine.callCallTaxiCallback();
currentLocation()->onTaxiCalled();
}
};
@@ -697,6 +791,11 @@ namespace ZL
loc->state.isDawn = gameState.isDawn;
loc->scriptEngine.callLocationEnterCallback();
//Reset taxi
loc->state.taxiCar = loc->state.taxiCarInitialState;
loc->state.taxiArrivedCallbackCalled = false;
gameState.taxiIsCalled = false;
menuManager.onLocationChanged(destName);
};
@@ -1251,7 +1350,7 @@ namespace ZL
break;
case SDLK_o:
x = x + 1;
x = x + 0.05;
std::cout << "current x: " << x << std::endl;
//y = y + 0.002;
//currentLocation->player->hp = 200;
@@ -1260,7 +1359,7 @@ namespace ZL
break;
case SDLK_k:
x = x - 1;
x = x - 0.05;
std::cout << "current x: " << x << std::endl;
std::cout << "Player pos: " << currentLocation()->player->state.position.transpose() << std::endl;
std::cout << "Player rotation: " << currentLocation()->player->state.facingAngle*180.0/M_PI << std::endl;
+5 -1
View File
@@ -118,7 +118,11 @@ namespace ZL {
void saveGame(int slot);
void loadGame(int slot);
SaveSlotInfo readSlotInfo(int slot) const;
void createLocations();
void createLocationsStep1();
void createLocationsStep2();
void createLocationsStep3();
void createLocationsStep4();
void createLocationsStep5();
void createShadowMapAndProparateToLocations();
void destroyShadowMapAndProparateToLocations();
+5
View File
@@ -77,6 +77,8 @@ void GameState::save(nlohmann::json& out) const
}
}
out["locations"] = std::move(locsJson);
out["taxiIsCalled"] = taxiIsCalled;
}
void GameState::load(const nlohmann::json& in)
@@ -149,6 +151,9 @@ void GameState::load(const nlohmann::json& in)
}
}
}
// --- Taxi ---
taxiIsCalled = in.value("taxiIsCalled", taxiIsCalled);
}
} // namespace ZL
+2
View File
@@ -69,6 +69,8 @@ struct GameState : public ISaveable {
std::string chatPreviewMsg[3];
std::vector<StoredChatMessage> chatHistory[3];
bool taxiIsCalled = false;
void save(nlohmann::json& out) const override;
void load(const nlohmann::json& in) override;
};
+199
View File
@@ -20,6 +20,9 @@ namespace ZL
{
extern const char* CONST_ZIP_FILE;
extern float x;
constexpr float CONST_TAXI_CAR_SCALE = 0.6f;
static constexpr float CAMERA_FOV_Y = 1.0f / 1.5f;
@@ -212,6 +215,18 @@ namespace ZL
}
});
carTexture = renderer.textureManager.LoadFromPng("resources/e/car4096_v002.png", CONST_ZIP_FILE);
carMesh.data = LoadFromTextFile02("resources/e/car004.txt", CONST_ZIP_FILE);
carMesh.data.Scale(CONST_TAXI_CAR_SCALE);
carMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
carMesh.RefreshVBO();
carWheelTexture = renderer.textureManager.LoadFromPng("resources/w/exterior/Wheel_base003.png", CONST_ZIP_FILE);
carWheelMesh.data = LoadFromTextFile02("resources/e/car_wheel001.txt", CONST_ZIP_FILE);
carWheelMesh.data.Scale(CONST_TAXI_CAR_SCALE);
carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
carWheelMesh.RefreshVBO();
}
void Location::loadTeleportZones(const std::string& jsonPath, const char* zipFile)
@@ -273,6 +288,7 @@ namespace ZL
}
std::cout << "[TELEPORT] Loaded " << teleportZones.size() << " teleport(s) from " << jsonPath << std::endl;
}
void Location::loadTriggerZones(const std::string& jsonPath, const char* zipFile)
@@ -693,6 +709,8 @@ namespace ZL
if (player) player->draw(renderer);
for (auto& npc : npcs) npc->draw(renderer);
drawNpcCar();
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
if (editorMode == EditorMode::Navigation) {
@@ -784,6 +802,8 @@ namespace ZL
if (player) player->drawShadowDepth(renderer);
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
drawNpcCar();
renderer.PopMatrix(); // light view
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
@@ -883,6 +903,7 @@ namespace ZL
}
if (player) player->draw(renderer);
for (auto& npc : npcs) npc->draw(renderer);
drawNpcCar();
#else
// Characters use their own shadow-aware shaders
CheckGlError(__FILE__, __LINE__);
@@ -896,6 +917,8 @@ namespace ZL
for (auto& npc : npcs) npc->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera);
drawNpcCar();
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
#endif
@@ -972,6 +995,8 @@ namespace ZL
if (player) player->draw(renderer);
for (auto& npc : npcs) npc->draw(renderer);
//drawNpcCar();
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
if (editorMode == EditorMode::Navigation) {
@@ -1029,6 +1054,8 @@ namespace ZL
if (player) player->drawShadowDepth(renderer);
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
drawNpcCar();
renderer.PopMatrix(); // light view
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
@@ -1037,6 +1064,44 @@ namespace ZL
shadowMap->unbind();
}
void Location::drawNpcCar()
{
renderer.PushMatrix();
renderer.TranslateMatrix(state.taxiCar.position);
renderer.TranslateMatrix({ 0, 0.7f - 0.25f +x, 0 });
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.taxiCar.rotation, Eigen::Vector3f::UnitY())).toRotationMatrix());
glBindTexture(GL_TEXTURE_2D, carTexture->getTexID());
renderer.DrawVertexRenderStruct(carMesh);
if (carWheelTexture) {
constexpr float track_width = 1.28f * CONST_TAXI_CAR_SCALE;
constexpr float wheel_base = 2.25f * CONST_TAXI_CAR_SCALE;
constexpr float shift = 0.6f * CONST_TAXI_CAR_SCALE;
const Eigen::Vector3f wheelPositions[4] = {
Eigen::Vector3f(track_width, 0.f - 0.21f, -(wheel_base + shift) + 1.25f * CONST_TAXI_CAR_SCALE),
Eigen::Vector3f(-track_width, 0.f - 0.21f, -(wheel_base + shift) + 1.25f * CONST_TAXI_CAR_SCALE),
Eigen::Vector3f(track_width, 0.f - 0.21f, (wheel_base - shift) + 1.1f * CONST_TAXI_CAR_SCALE),
Eigen::Vector3f(-track_width, 0.f - 0.21f, (wheel_base - shift) + 1.1f * CONST_TAXI_CAR_SCALE)
};
const bool isFront[4] = { true, true, false, false };
glBindTexture(GL_TEXTURE_2D, carWheelTexture->getTexID());
for (int i = 0; i < 4; ++i) {
renderer.PushMatrix();
renderer.TranslateMatrix(wheelPositions[i]);
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.taxiCar.wheelAngle, -Eigen::Vector3f::UnitX())).toRotationMatrix());
if (isFront[i]) {
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.taxiCar.steeringAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
}
renderer.DrawVertexRenderStruct(carWheelMesh);
renderer.PopMatrix();
}
}
renderer.PopMatrix();
}
void Location::drawGameNight()
{
// --- Determine which lights are active this frame ---
@@ -1216,6 +1281,8 @@ namespace ZL
plWorldXZ, plLimitXZ, cameraViewInverse, ambientColor, fogColor);
}
drawNpcCar();
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
if (editorMode == EditorMode::Navigation) {
@@ -1651,6 +1718,132 @@ namespace ZL
}
}
}
updateNpcCar(delta);
}
void Location::updateNpcCar(int64_t deltaMs)
{
const float dt = static_cast<float>(deltaMs) / 1000.0f;
NpcCar& car = state.taxiCar;
Eigen::Vector3f target = car.position;
float throttle = 0.f;
bool hasTarget = false;
bool waypointsOver = false;
if (car.mode == NpcCar::Mode::FOLLOW_WAYPOINTS) {
if (!car.waypoints.empty()) {
if (car.currentWaypoint >= car.waypoints.size()) {
car.currentWaypoint = 0;
}
Eigen::Vector3f toTarget = car.waypoints[car.currentWaypoint] - car.position;
toTarget.y() = 0.f;
if (toTarget.norm() < car.waypointReachRadius) {
car.currentWaypoint = car.currentWaypoint + 1;
std::cout << "Waypoint current: " << car.currentWaypoint << std::endl;
if (car.currentWaypoint == car.waypoints.size())
{
std::cout << "waypointsOver" << std::endl;
waypointsOver = true;
}
}
if (waypointsOver) {
throttle = 0.f;
hasTarget = false;
car.mode = NpcCar::Mode::NONE;
}
else
{
target = car.waypoints[car.currentWaypoint];
throttle = 1.0f;
hasTarget = true;
}
}
}
else
{
throttle = 0.f;
}
float targetHeading = car.rotation;
if (hasTarget) {
Eigen::Vector3f toTarget = target - car.position;
toTarget.y() = 0.f;
if (toTarget.squaredNorm() > 1e-4f) {
targetHeading = std::atan2(-toTarget.x(), -toTarget.z());
}
}
float angleDiff = targetHeading - car.rotation;
while (angleDiff > M_PI) angleDiff -= 2.0f * static_cast<float>(M_PI);
while (angleDiff < -M_PI) angleDiff += 2.0f * static_cast<float>(M_PI);
const float turnIntent = max(-1.0f, min(1.0f, angleDiff * 2.0f));
const float targetSteer = turnIntent * NpcCar::maxSteerAngle;
const float steerLerp = min(1.f, dt * 8.f);
car.steeringAngle += (targetSteer - car.steeringAngle) * steerLerp;
if (throttle > 0.f) {
car.velocity += NpcCar::acceleration * dt * throttle;
}
else if (throttle < 0.f) {
const float brakeForce = NpcCar::acceleration * dt * (-throttle);
if (car.velocity > 0.f) {
car.velocity = max(0.f, car.velocity - brakeForce);
}
else {
car.velocity = min(0.f, car.velocity + brakeForce);
}
}
else {
const float resistance = NpcCar::friction * dt;
if (car.velocity > 0.f) {
car.velocity = max(0.f, car.velocity - resistance);
}
else if (car.velocity < 0.f) {
car.velocity = min(0.f, car.velocity + resistance);
}
}
car.velocity = max(-NpcCar::maxReverseSpeed, min(NpcCar::maxSpeed, car.velocity));
const float oldRotation = car.rotation;
if (std::abs(car.velocity) > 0.01f) {
const float speedFactor = car.velocity / NpcCar::maxSpeed;
car.rotation += turnIntent * NpcCar::turnRate * dt * speedFactor;
}
/*
if (navigation.isReady() && !isCarFootprintWalkable(car.position, car.rotation)) {
car.rotation = oldRotation;
}
*/
const Eigen::Vector3f forward(-std::sin(car.rotation), 0.f, -std::cos(car.rotation));
const Eigen::Vector3f totalDelta = forward * car.velocity * dt;
const float totalDist = totalDelta.norm();
const float maxSubstep = 0.2f;
const int substeps = max(1, static_cast<int>(std::ceil(totalDist / maxSubstep)));
const Eigen::Vector3f stepDelta = totalDelta / static_cast<float>(substeps);
for (int s = 0; s < substeps; ++s) {
Eigen::Vector3f candidate = car.position + stepDelta;
car.position = candidate;
}
state.taxiCar.wheelAngle += car.velocity * 4.f * dt;
while (state.taxiCar.wheelAngle > 2.0f * static_cast<float>(M_PI)) {
state.taxiCar.wheelAngle -= 2.0f * static_cast<float>(M_PI);
}
if (state.taxiArrivedCallbackCalled == false)
{
Eigen::Vector3f toTarget = state.taxiCar.position - state.taxiCarTriggerPosition;
if (toTarget.squaredNorm() < 9.f) {
scriptEngine.callCallTaxiCallback();
state.taxiArrivedCallbackCalled = true;
}
}
}
void Location::handleDown(int64_t fingerId, int eventX, int eventY, int mx, int my)
@@ -1874,6 +2067,12 @@ namespace ZL
return dialogueSystem.getFlag(flag);
}
void Location::onTaxiCalled()
{
state.taxiCar.waypoints = state.taxiCarWaypoints;
state.taxiCar.mode = NpcCar::Mode::FOLLOW_WAYPOINTS;
}
// ---- Save / Load ----
void Location::save(nlohmann::json& out) const
+15
View File
@@ -19,6 +19,7 @@
#include <functional>
#include <cstdint>
#include <unordered_map>
namespace ZL
{
@@ -133,6 +134,16 @@ namespace ZL
bool playBattleMusic = false;
std::shared_ptr<Texture> carTexture;
VertexRenderStruct carMesh;
std::shared_ptr<Texture> carWheelTexture;
VertexRenderStruct carWheelMesh;
void setup(const LocationSetup& params, Quest::QuestJournal* journal, AudioPlayerAsync* audioPlayer);
void setupNavigation(const std::vector<std::string>& paths);
bool switchNavigation(int index);
@@ -145,10 +156,12 @@ namespace ZL
void drawGameDarklands();
void drawGameNight();
void drawNightShadowDepthPass(const PointLight& light);
void drawNpcCar();
bool setNavigationAreaAvailable(const std::string& areaName, bool available);
void update(int64_t deltaMs);
void updateNpcCar(int64_t deltaMs);
void handleDown(int64_t fingerId, int eventX, int eventY, int mx, int my);
void handleUp(int64_t fingerId, int mx, int my);
@@ -160,6 +173,8 @@ namespace ZL
void setDialogueFlag(const std::string& flag, int value);
int getDialogueFlag(const std::string& flag) const;
void onTaxiCalled();
// ---- Save / Load ----
// Serialises LocationState + all Character/InteractiveObject sub-states + Lua globals.
void save(nlohmann::json& out) const override;
+185
View File
@@ -18,6 +18,91 @@ void LocationState::save(nlohmann::json& out) const
out["isDawn"] = isDawn;
out["tutorialInteractiveObjectsLocked"] = tutorialInteractiveObjectsLocked;
// Taxi stuff:
nlohmann::json taxiJson;
taxiJson["taxiCar"] = {
{"positionX", taxiCar.position.x()},
{"positionY", taxiCar.position.y()},
{"positionZ", taxiCar.position.z()},
{"rotation", taxiCar.rotation},
{"velocity", taxiCar.velocity},
{"steeringAngle", taxiCar.steeringAngle},
{"mode", static_cast<int>(taxiCar.mode)},
{"waypoints", nlohmann::json::array()},
{"currentWaypoint", taxiCar.currentWaypoint},
{"waypointReachRadius", taxiCar.waypointReachRadius}
};
nlohmann::json taxiWaypoints = nlohmann::json::array();
for (int i = 0; i < taxiCar.waypoints.size(); ++i) {
taxiWaypoints.push_back({
{"x", taxiCar.waypoints[i].x()},
{"y", taxiCar.waypoints[i].y()},
{"z", taxiCar.waypoints[i].z()}
});
}
taxiJson["taxiCar"]["waypoints"] = std::move(taxiWaypoints);
taxiJson["taxiCarInitialState"] = {
{"positionX", taxiCarInitialState.position.x()},
{"positionY", taxiCarInitialState.position.y()},
{"positionZ", taxiCarInitialState.position.z()},
{"rotation", taxiCarInitialState.rotation},
{"velocity", taxiCarInitialState.velocity},
{"steeringAngle", taxiCarInitialState.steeringAngle},
{"mode", static_cast<int>(taxiCarInitialState.mode)},
{"waypoints", nlohmann::json::array()},
{"currentWaypoint", taxiCarInitialState.currentWaypoint},
{"waypointReachRadius", taxiCarInitialState.waypointReachRadius}
};
nlohmann::json taxiInitialWaypoints = nlohmann::json::array();
for (int i = 0; i < taxiCarInitialState.waypoints.size(); ++i) {
taxiInitialWaypoints.push_back({
{"x", taxiCarInitialState.waypoints[i].x()},
{"y", taxiCarInitialState.waypoints[i].y()},
{"z", taxiCarInitialState.waypoints[i].z()}
});
}
taxiJson["taxiCarInitialState"]["waypoints"] = std::move(taxiInitialWaypoints);
nlohmann::json taxiDefaultWaypoints = nlohmann::json::array();
for (int i = 0; i < taxiCarWaypoints.size(); ++i) {
taxiDefaultWaypoints.push_back({
{"x", taxiCarWaypoints[i].x()},
{"y", taxiCarWaypoints[i].y()},
{"z", taxiCarWaypoints[i].z()}
});
}
taxiJson["taxiDefaultWaypoints"] = taxiDefaultWaypoints;
/* taxiCarTriggerPosition = Eigen::Vector3f(
taxiJson.value("taxiCarTriggerPositionX", 0.f),
taxiJson.value("taxiCarTriggerPositionY", 0.f),
taxiJson.value("taxiCarTriggerPositionZ", 0.f)
);*/
taxiJson["taxiCarTriggerPositionX"] = taxiCarTriggerPosition.x();
taxiJson["taxiCarTriggerPositionY"] = taxiCarTriggerPosition.y();
taxiJson["taxiCarTriggerPositionZ"] = taxiCarTriggerPosition.z();
// {"y", taxiCarTriggerPosition.y()},
// {"z", taxiCarTriggerPosition.z()}
//};
taxiJson["taxiArrivedCallbackCalled"] = taxiArrivedCallbackCalled;
//questJournal.save(questJson);
out["taxi"] = std::move(taxiJson);
}
void LocationState::load(const nlohmann::json& in)
@@ -36,6 +121,106 @@ void LocationState::load(const nlohmann::json& in)
isDawn = in.value("isDawn", false);
tutorialInteractiveObjectsLocked = in.value("tutorialInteractiveObjectsLocked", false);
nlohmann::json taxiJson = in["taxi"];
taxiArrivedCallbackCalled = taxiJson.value("taxiArrivedCallbackCalled", false);
//----- Taxi State ----
nlohmann::json taxiCarJson = taxiJson["taxiCar"];
taxiCar.position = Eigen::Vector3f(
taxiCarJson.value("positionX", 0.f),
taxiCarJson.value("positionY", 0.f),
taxiCarJson.value("positionZ", 0.f)
);
taxiCar.rotation = taxiCarJson.value("rotation", 0.f);
taxiCar.velocity = taxiCarJson.value("velocity", 0.f);
taxiCar.steeringAngle = taxiCarJson.value("steeringAngle", 0.f);
/*taxiCar.acceleration = taxiCarJson.value("acceleration", 20.f);
taxiCar.friction = taxiCarJson.value("friction", 6.f);
taxiCar.maxSpeed = taxiCarJson.value("maxSpeed", 24.f);
taxiCar.maxReverseSpeed = taxiCarJson.value("maxReverseSpeed", 8.f);
taxiCar.turnRate = taxiCarJson.value("turnRate", 1.8f);
taxiCar.maxSteerAngle = taxiCarJson.value("maxSteerAngle", 0.6f);*/
taxiCar.mode = static_cast<NpcCar::Mode>(taxiCarJson.value("mode", 0));
taxiCar.waypoints.clear();
if (taxiCarJson.contains("waypoints") && taxiCarJson["waypoints"].is_array()) {
for (int i = 0; i < static_cast<int>(taxiCarJson["waypoints"].size()); ++i)
taxiCar.waypoints.push_back(Eigen::Vector3f(
taxiCarJson["waypoints"][i].value("x", 0.f),
taxiCarJson["waypoints"][i].value("y", 0.f),
taxiCarJson["waypoints"][i].value("z", 0.f)
));
}
taxiCar.currentWaypoint = taxiCarJson.value("currentWaypoint", 0);
taxiCar.waypointReachRadius = taxiCarJson.value("waypointReachRadius", 3.f);
taxiCar.wheelAngle = taxiCarJson.value("wheelAngle", 0.f);
//--------- Taxi initial state -----
nlohmann::json taxiCarInitialStateJson = taxiJson["taxiCarInitialState"];
taxiCarInitialState.position = Eigen::Vector3f(
taxiCarInitialStateJson.value("positionX", 0.f),
taxiCarInitialStateJson.value("positionY", 0.f),
taxiCarInitialStateJson.value("positionZ", 0.f)
);
taxiCarInitialState.rotation = taxiCarInitialStateJson.value("rotation", 0.f);
taxiCarInitialState.velocity = taxiCarInitialStateJson.value("velocity", 0.f);
taxiCarInitialState.steeringAngle = taxiCarInitialStateJson.value("steeringAngle", 0.f);
/*
taxiCarInitialState.acceleration = taxiCarInitialStateJson.value("acceleration", 20.f);
taxiCarInitialState.friction = taxiCarInitialStateJson.value("friction", 6.f);
taxiCarInitialState.maxSpeed = taxiCarInitialStateJson.value("maxSpeed", 24.f);
taxiCarInitialState.maxReverseSpeed = taxiCarInitialStateJson.value("maxReverseSpeed", 8.f);
taxiCarInitialState.turnRate = taxiCarInitialStateJson.value("turnRate", 1.8f);
taxiCarInitialState.maxSteerAngle = taxiCarInitialStateJson.value("maxSteerAngle", 0.6f);*/
taxiCarInitialState.mode = static_cast<NpcCar::Mode>(taxiCarInitialStateJson.value("mode", 0));
taxiCarInitialState.waypoints.clear();
if (taxiCarInitialStateJson.contains("waypoints") && taxiCarInitialStateJson["waypoints"].is_array()) {
for (int i = 0; i < static_cast<int>(taxiCarInitialStateJson["waypoints"].size()); ++i)
taxiCarInitialState.waypoints.push_back(Eigen::Vector3f(
taxiCarInitialStateJson["waypoints"][i].value("x", 0.f),
taxiCarInitialStateJson["waypoints"][i].value("y", 0.f),
taxiCarInitialStateJson["waypoints"][i].value("z", 0.f)
));
}
taxiCarInitialState.currentWaypoint = taxiCarInitialStateJson.value("currentWaypoint", 0);
taxiCarInitialState.waypointReachRadius = taxiCarInitialStateJson.value("waypointReachRadius", 3.f);
taxiCarInitialState.wheelAngle = taxiCarInitialStateJson.value("wheelAngle", 0.f);
taxiCarWaypoints.clear();
if (taxiJson.contains("taxiDefaultWaypoints") && taxiJson["taxiDefaultWaypoints"].is_array()) {
for (int i = 0; i < static_cast<int>(taxiJson["taxiDefaultWaypoints"].size()); ++i)
taxiCarWaypoints.push_back(Eigen::Vector3f(
taxiJson["taxiDefaultWaypoints"][i].value("x", 0.f),
taxiJson["taxiDefaultWaypoints"][i].value("y", 0.f),
taxiJson["taxiDefaultWaypoints"][i].value("z", 0.f)
));
}
taxiCarTriggerPosition = Eigen::Vector3f(
taxiJson.value("taxiCarTriggerPositionX", 0.f),
taxiJson.value("taxiCarTriggerPositionY", 0.f),
taxiJson.value("taxiCarTriggerPositionZ", 0.f)
);
}
} // namespace ZL
+8
View File
@@ -1,6 +1,7 @@
#pragma once
#include "external/nlohmann/json.hpp"
#include "ISaveable.h"
#include "NpcCar.h"
namespace ZL {
@@ -26,6 +27,13 @@ struct LocationState : public ISaveable {
// ---- Tutorial ----
bool tutorialInteractiveObjectsLocked = false;
NpcCar taxiCarInitialState;
NpcCar taxiCar;
bool taxiArrivedCallbackCalled = false;
Vector3f taxiCarTriggerPosition;
std::vector<Vector3f> taxiCarWaypoints;
// (trigger/teleport zone runtime flags are serialised by id directly in Location::save/load)
// ---- Serialisation ----
+16 -6
View File
@@ -1087,14 +1087,24 @@ namespace ZL {
uiManager.setButtonCallback("mapGo", [this](const std::string&) {
gameState_.tutorialNeedOpenTaxiScreen = false;
if (callTaxiFunc)
if (gameState_.taxiIsCalled == false)
{
callTaxiFunc();
gameState_.taxiIsCalled = true;
if (callTaxiFunc)
{
callTaxiFunc();
}
gameState_.money -= 500;
closePhoneEntirely();
if (startDialogueFunc) startDialogueFunc("dialog_taxi002");
audioPlayer_.playSoundAsync("audio/537061__imafoley__message-pop-sound.ogg");
}
else
{
closePhoneEntirely();
if (startDialogueFunc) startDialogueFunc("dialog_taxi004");
audioPlayer_.playSoundAsync("audio/537061__imafoley__message-pop-sound.ogg");
}
gameState_.money -= 500;
closePhoneEntirely();
if (startDialogueFunc) startDialogueFunc("dialog_taxi002");
audioPlayer_.playSoundAsync("audio/537061__imafoley__message-pop-sound.ogg");
});
audioPlayer_.playSoundAsync("audio/537061__imafoley__message-pop-sound.ogg");
+11
View File
@@ -0,0 +1,11 @@
#include "NpcCar.h"
namespace ZL
{
const float NpcCar::acceleration = 10.0f;
const float NpcCar::friction = 8.0f;
const float NpcCar::maxSpeed = 18.0f;
const float NpcCar::maxReverseSpeed = 8.0f;
const float NpcCar::turnRate = 1.8f;
const float NpcCar::maxSteerAngle = 0.6f;
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "render/Renderer.h"
#include "Environment.h"
namespace ZL {
struct NpcCar
{
enum class Mode { FOLLOW_WAYPOINTS, NONE };
Eigen::Vector3f position = Eigen::Vector3f(-100.f, -100.f, -100.f);
float rotation = 0.f;
float velocity = 0.f;
float steeringAngle = 0.f;
static const float acceleration;
static const float friction;
static const float maxSpeed;
static const float maxReverseSpeed;
static const float turnRate;
static const float maxSteerAngle;
Mode mode = Mode::NONE;
std::vector<Eigen::Vector3f> waypoints;
size_t currentWaypoint = 0;
float waypointReachRadius = 3.0f;
float wheelAngle = 0.f;
};
}