Working on cutscenes and pathfinding

This commit is contained in:
Vladislav Khorev committed 2026-06-14 22:31:11 +03:00
1 parent 80825e3220
commit 020f31e1e4
17 files changed
+192 -73

No files matched your search

+8 -9
View File
@@ -1,12 +1,11 @@
export const AVAILABLE_IMAGES: string[] = [ export const AVAILABLE_IMAGES: string[] = [
'resources/w/cutscenes/cutscene1/cutscene1_wall_x.png', 'resources/w/cutscenes/cutscene2/cs2_background.png',
'resources/w/cutscenes/cutscene1/cutscene1_aida1_x.png', 'resources/w/cutscenes/cutscene2/cs2_books.png',
'resources/w/cutscenes/cutscene1/cutscene1_aida2_x.png', 'resources/w/cutscenes/cutscene2/cs2_chair.png',
'resources/w/cutscenes/cutscene1/cutscene1_aida3_x.png', 'resources/w/cutscenes/cutscene2/cs2_gg001.png',
'resources/w/cutscenes/cutscene1/cutscene1_heads_x.png', 'resources/w/cutscenes/cutscene2/cs2_gg002.png',
'resources/w/cutscenes/cutscene2/scr1.png', 'resources/w/cutscenes/cutscene2/cs2_gg003.png',
'resources/w/cutscenes/cutscene2/scr2.png', 'resources/w/cutscenes/cutscene2/cs2_gg004.png',
'resources/w/cutscenes/cutscene2/scr3.png', 'resources/w/cutscenes/cutscene2/cs2_foreground.png',
'resources/w/cutscenes/cutscene2/scr4.png',
'resources/black.png', 'resources/black.png',
]; ];
+130 -50
View File
@@ -414,19 +414,19 @@
{ {
"id": "computer_cutscene001", "id": "computer_cutscene001",
"skippable": true, "skippable": true,
"durationMs": 9000, "durationMs": 12000,
"fadeOutMs": 500, "fadeOutMs": 500,
"fadeInMs": 500, "fadeInMs": 500,
"endFadeOutMs": 0, "endFadeOutMs": 0,
"endFadeInMs": 500, "endFadeInMs": 500,
"onFadeInCallback": "on_sleep_cutscene", "onFadeInCallback": "",
"imageSegments": [ "imageSegments": [
{ {
"path": "resources/black.png", "path": "resources/black.png",
"width": 1280, "width": 1280,
"height": 720, "height": 720,
"startMs": 0, "startMs": 0,
"endMs": 9000, "endMs": 13000,
"fadeInMs": 0, "fadeInMs": 0,
"fadeOutMs": 0, "fadeOutMs": 0,
"easing": "Linear", "easing": "Linear",
@@ -442,82 +442,162 @@
} }
}, },
{ {
"path": "resources/w/cutscenes/cutscene2/scr1.png", "path": "resources/w/cutscenes/cutscene2/cs2_background.png",
"width": 1280, "width": 1280,
"height": 720, "height": 720,
"startMs": 0, "startMs": 0,
"endMs": 2510, "endMs": 11984,
"fadeInMs": 500, "fadeInMs": 0,
"fadeOutMs": 0, "fadeOutMs": 1000,
"easing": "Linear", "easing": "Linear",
"from": { "from": {
"centerX": 0.5, "centerX": 0.5,
"centerY": 0.55, "centerY": 0.5,
"scale": 1 "scale": 1
}, },
"to": { "to": {
"centerX": 0.5, "centerX": 0.5,
"centerY": 0.55, "centerY": 0.5,
"scale": 1
}
},
{
"path": "resources/w/cutscenes/cutscene2/cs2_books.png",
"width": 1280,
"height": 720,
"startMs": 0,
"endMs": 11550,
"fadeInMs": 0,
"fadeOutMs": 1000,
"easing": "Linear",
"from": {
"centerX": 0.46,
"centerY": 0.5,
"scale": 1.1
},
"to": {
"centerX": 0.58,
"centerY": 0.5,
"scale": 1.2
}
},
{
"path": "resources/w/cutscenes/cutscene2/cs2_chair.png",
"width": 1280,
"height": 720,
"startMs": 17,
"endMs": 10767,
"fadeInMs": 0,
"fadeOutMs": 300,
"easing": "Linear",
"from": {
"centerX": 0.47,
"centerY": 0.5,
"scale": 1.1
},
"to": {
"centerX": 0.57,
"centerY": 0.5,
"scale": 1.3
}
},
{
"path": "resources/w/cutscenes/cutscene2/cs2_gg001.png",
"width": 1280,
"height": 720,
"startMs": 0,
"endMs": 3083,
"fadeInMs": 0,
"fadeOutMs": 1000,
"easing": "Linear",
"from": {
"centerX": 0.47,
"centerY": 0.5,
"scale": 1.1
},
"to": {
"centerX": 0.5,
"centerY": 0.5,
"scale": 1.15
}
},
{
"path": "resources/w/cutscenes/cutscene2/cs2_gg002.png",
"width": 1280,
"height": 720,
"startMs": 1850,
"endMs": 4883,
"fadeInMs": 1000,
"fadeOutMs": 1000,
"easing": "Linear",
"from": {
"centerX": 0.5,
"centerY": 0.5,
"scale": 1.15
},
"to": {
"centerX": 0.53,
"centerY": 0.5,
"scale": 1.2
}
},
{
"path": "resources/w/cutscenes/cutscene2/cs2_gg003.png",
"width": 1280,
"height": 720,
"startMs": 3950,
"endMs": 7083,
"fadeInMs": 1000,
"fadeOutMs": 1000,
"easing": "Linear",
"from": {
"centerX": 0.49,
"centerY": 0.5,
"scale": 1.05
},
"to": {
"centerX": 0.55,
"centerY": 0.5,
"scale": 1.1 "scale": 1.1
} }
}, },
{ {
"path": "resources/w/cutscenes/cutscene2/scr2.png", "path": "resources/w/cutscenes/cutscene2/cs2_gg004.png",
"width": 1280, "width": 1280,
"height": 720, "height": 720,
"startMs": 956, "startMs": 6050,
"endMs": 3522, "endMs": 10100,
"fadeInMs": 1500, "fadeInMs": 1000,
"fadeOutMs": 500, "fadeOutMs": 1000,
"easing": "Linear", "easing": "Linear",
"from": { "from": {
"centerX": 0.5, "centerX": 0.47,
"centerY": 0.6, "centerY": 0.5,
"scale": 1.3 "scale": 1.1
}, },
"to": { "to": {
"centerX": 0.5, "centerX": 0.53,
"centerY": 0.6, "centerY": 0.5,
"scale": 1.5 "scale": 1.2
} }
}, },
{ {
"path": "resources/w/cutscenes/cutscene2/scr4.png", "path": "resources/w/cutscenes/cutscene2/cs2_foreground.png",
"width": 1280, "width": 1280,
"height": 720, "height": 720,
"startMs": 4849, "startMs": 0,
"endMs": 6964, "endMs": 10100,
"fadeInMs": 0, "fadeInMs": 0,
"fadeOutMs": 500, "fadeOutMs": 3000,
"easing": "Linear", "easing": "Linear",
"from": { "from": {
"centerX": 0.5, "centerX": 0.5,
"centerY": 0.35, "centerY": 0.5,
"scale": 1 "scale": 1
}, },
"to": { "to": {
"centerX": 0.5, "centerX": 0.5,
"centerY": 0.35, "centerY": 0.5,
"scale": 1
}
},
{
"path": "resources/w/cutscenes/cutscene2/scr3.png",
"width": 1280,
"height": 720,
"startMs": 3594,
"endMs": 6478,
"fadeInMs": 500,
"fadeOutMs": 1500,
"easing": "Linear",
"from": {
"centerX": 0.5,
"centerY": 0.6,
"scale": 1
},
"to": {
"centerX": 0.5,
"centerY": 0.6,
"scale": 1 "scale": 1
} }
} }
@@ -525,21 +605,21 @@
"lines": [ "lines": [
{ {
"speaker": "", "speaker": "",
"text": "Я начал делать презентацию по книге.", "text": "Я сел за компьютер и начал писать эссе по книге",
"durationMs": 3000, "durationMs": 3000,
"waitForConfirm": false, "waitForConfirm": false,
"luaCallback": "" "luaCallback": ""
}, },
{ {
"speaker": "", "speaker": "",
"text": "Книга была такая скучная что я уснул.", "text": "Книга была очень скучной. Как будто кто-то наложил на книгу чары сна.",
"durationMs": 3000, "durationMs": 4000,
"waitForConfirm": false, "waitForConfirm": false,
"luaCallback": "" "luaCallback": ""
}, },
{ {
"speaker": "", "speaker": "",
"text": "И я проснулся уже ночью...", "text": "Неудивительно что я стал понемногу засыпать...",
"durationMs": 3000, "durationMs": 3000,
"waitForConfirm": false, "waitForConfirm": false,
"luaCallback": "" "luaCallback": ""
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -1
View File
@@ -1004,9 +1004,10 @@ namespace ZL
case SDLK_f: case SDLK_f:
currentLocation->dialogueSystem.startDialogue("phone_night_aiperi001"); currentLocation->dialogueSystem.startDialogue("phone_night_aiperi001");
break; break;
case SDLK_e: case SDLK_e:
//currentLocation->dialogueSystem.startCutscene("lection_cutscene001"); //.startDialogue("test_cutscene_pan_dialogue"); currentLocation->dialogueSystem.startCutscene("computer_cutscene001"); //.startDialogue("test_cutscene_pan_dialogue");
break; break;
+27 -1
View File
@@ -10,6 +10,7 @@
#include <memory> #include <memory>
#include <cfloat> #include <cfloat>
#include <limits> #include <limits>
#include <random>
#include "GameConstants.h" #include "GameConstants.h"
#include "Character.h" #include "Character.h"
#include "external/nlohmann/json.hpp" #include "external/nlohmann/json.hpp"
@@ -1325,6 +1326,23 @@ namespace ZL
static constexpr int64_t kReplanCooldownMs = 500; static constexpr int64_t kReplanCooldownMs = 500;
static constexpr float kStuckMovementThreshold = 0.02f; static constexpr float kStuckMovementThreshold = 0.02f;
static constexpr int kStuckFrameThreshold = 4; static constexpr int kStuckFrameThreshold = 4;
static constexpr float kStuckPauseMin = 0.5f;
static constexpr float kStuckPauseMax = 1.0f;
const float deltaS = static_cast<float>(deltaMs) / 1000.f;
// Tick down pause timers; replan NPCs when their pause expires.
for (auto it = stuckPauseRemainingS.begin(); it != stuckPauseRemainingS.end();) {
it->second -= deltaS;
if (it->second <= 0.f) {
if (!it->first->isPlayer) {
it->first->forceReplan();
}
it = stuckPauseRemainingS.erase(it);
} else {
++it;
}
}
for (auto it = replanCooldownRemainingMs.begin(); it != replanCooldownRemainingMs.end();) { for (auto it = replanCooldownRemainingMs.begin(); it != replanCooldownRemainingMs.end();) {
it->second -= deltaMs; it->second -= deltaMs;
@@ -1362,8 +1380,16 @@ namespace ZL
if (c->isMoving()) { if (c->isMoving()) {
if (moved < kStuckMovementThreshold) { if (moved < kStuckMovementThreshold) {
if (++stuckFrameCounts[c] >= kStuckFrameThreshold) { if (++stuckFrameCounts[c] >= kStuckFrameThreshold) {
c->forceReplan(); c->stopInPlace();
stuckFrameCounts[c] = 0; stuckFrameCounts[c] = 0;
if (stuckPauseRemainingS.find(c) == stuckPauseRemainingS.end()) {
if (!c->isPlayer) {
static std::mt19937 rng(std::random_device{}());
std::uniform_real_distribution<float> pauseDist(kStuckPauseMin, kStuckPauseMax);
stuckPauseRemainingS[c] = pauseDist(rng);
}
// Player just stops; replan is not scheduled.
}
} }
} else { } else {
stuckFrameCounts[c] = 0; stuckFrameCounts[c] = 0;
+1
View File
@@ -183,6 +183,7 @@ namespace ZL
std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions; std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions;
std::unordered_map<Character*, int64_t> replanCooldownRemainingMs; std::unordered_map<Character*, int64_t> replanCooldownRemainingMs;
std::unordered_map<Character*, int> stuckFrameCounts; std::unordered_map<Character*, int> stuckFrameCounts;
std::unordered_map<Character*, float> stuckPauseRemainingS;
static constexpr float NPC_BUMP_CALLBACK_COOLDOWN = 5.0f; static constexpr float NPC_BUMP_CALLBACK_COOLDOWN = 5.0f;
std::unordered_map<int, float> npcBumpedByPlayerCooldown; std::unordered_map<int, float> npcBumpedByPlayerCooldown;