Working on cutscenes and pathfinding

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

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',
]; ];

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": ""

BIN
resources/w/cutscenes/cutscene2/cs2_background.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_books.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_chair.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_foreground.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_gg001.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_gg002.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_gg003.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/cs2_gg004.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr1.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr2.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr3.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/w/cutscenes/cutscene2/scr4.png (Stored with Git LFS)

Binary file not shown.

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;

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;

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;