Working on taxi car
This commit is contained in:
1 parent
38e45d67b8
commit
35a2a91178
21 files changed
+26446
-45
No files matched your search
@@ -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
|
||||
|
||||
Reference in new issue
Block a user