Compare commits
2 Commits
24851a89e8
...
16e7580418
| Author | SHA1 | Date | |
|---|---|---|---|
| 16e7580418 | |||
| be4dcd4cf9 |
@ -1006,6 +1006,13 @@ namespace ZL
|
|||||||
int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight);
|
int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight);
|
||||||
handleMotion(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
handleMotion(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
|
||||||
|
|
||||||
|
if (dialogueSystem.blocksGameplayInput()) {
|
||||||
|
dialogueSystem.handlePointerMoved(
|
||||||
|
static_cast<float>(mx),
|
||||||
|
Environment::projectionHeight - static_cast<float>(my)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (rightMouseDown) {
|
if (rightMouseDown) {
|
||||||
int dx = event.motion.x - lastMouseX;
|
int dx = event.motion.x - lastMouseX;
|
||||||
int dy = event.motion.y - lastMouseY;
|
int dy = event.motion.y - lastMouseY;
|
||||||
@ -1042,7 +1049,7 @@ namespace ZL
|
|||||||
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
||||||
switch (event.key.keysym.sym) {
|
switch (event.key.keysym.sym) {
|
||||||
case SDLK_f:
|
case SDLK_f:
|
||||||
dialogueSystem.startDialogue("test_cutscene_pan_dialogue_silent");
|
dialogueSystem.startDialogue("test_choice_dialogue");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_e:
|
case SDLK_e:
|
||||||
|
|||||||
@ -84,6 +84,12 @@ bool DialogueOverlay::init(Renderer& renderer, const std::string& zipFile) {
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogueOverlay::update(const PresentationModel& model, int deltaMs) {
|
||||||
|
if (model.mode != PresentationMode::Choice) {
|
||||||
|
hoveredChoiceIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
||||||
if (model.mode == PresentationMode::Hidden) {
|
if (model.mode == PresentationMode::Hidden) {
|
||||||
lastChoiceRects.clear();
|
lastChoiceRects.clear();
|
||||||
@ -170,12 +176,9 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
|
|||||||
lastChoiceRects.push_back(rect);
|
lastChoiceRects.push_back(rect);
|
||||||
choiceQuads[i].rebuild(rect);
|
choiceQuads[i].rebuild(rect);
|
||||||
|
|
||||||
const bool isSelected = static_cast<int>(i) == model.selectedChoice;
|
const bool isHighlighted = static_cast<int>(i) == hoveredChoiceIndex || static_cast<int>(i) == model.selectedChoice;
|
||||||
std::shared_ptr<Texture> choiceTexture = choiceMainTexture;
|
std::shared_ptr<Texture> choiceTexture = (model.choices[i].kind == ChoiceKind::Optional) ? choiceOptionalTexture : choiceMainTexture;
|
||||||
if (model.choices[i].kind == ChoiceKind::Optional) {
|
if (isHighlighted) {
|
||||||
choiceTexture = choiceOptionalTexture;
|
|
||||||
}
|
|
||||||
if (isSelected) {
|
|
||||||
choiceTexture = choiceSelectedTexture;
|
choiceTexture = choiceSelectedTexture;
|
||||||
}
|
}
|
||||||
drawQuad(renderer, choiceQuads[i], choiceTexture);
|
drawQuad(renderer, choiceQuads[i], choiceTexture);
|
||||||
@ -187,10 +190,10 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
|
|||||||
|
|
||||||
for (size_t i = 0; i < model.choices.size(); ++i) {
|
for (size_t i = 0; i < model.choices.size(); ++i) {
|
||||||
const UiRect& rect = lastChoiceRects[i];
|
const UiRect& rect = lastChoiceRects[i];
|
||||||
const bool isSelected = static_cast<int>(i) == model.selectedChoice;
|
const bool isHighlighted = static_cast<int>(i) == hoveredChoiceIndex || static_cast<int>(i) == model.selectedChoice;
|
||||||
const std::array<float, 4> color = (model.choices[i].kind == ChoiceKind::Optional)
|
const std::array<float, 4> color = (model.choices[i].kind == ChoiceKind::Optional)
|
||||||
? std::array<float, 4>{0.82f, 0.82f, 0.82f, 1.0f}
|
? std::array<float, 4>{0.82f, 0.82f, 0.82f, 1.0f}
|
||||||
: std::array<float, 4>{ 1.0f, 0.93f, 0.65f, 1.0f };
|
: std::array<float, 4>{ 1.0f, 0.93f, 0.65f, 1.0f };
|
||||||
|
|
||||||
choiceRenderer->drawText(
|
choiceRenderer->drawText(
|
||||||
wrapText(model.choices[i].text, 52),
|
wrapText(model.choices[i].text, 52),
|
||||||
@ -198,7 +201,7 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
|
|||||||
rect.y + 9.0f,
|
rect.y + 9.0f,
|
||||||
1.0f,
|
1.0f,
|
||||||
false,
|
false,
|
||||||
isSelected ? std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f} : color
|
isHighlighted ? std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f} : color
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,21 +420,48 @@ void DialogueOverlay::drawCutscene(Renderer& renderer, const PresentationModel&
|
|||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DialogueOverlay::handlePointerReleased(float x, float y, const PresentationModel& model, int& outChoiceIndex) const {
|
void DialogueOverlay::handlePointerDown(float x, float y, const PresentationModel& model) {
|
||||||
|
if (model.mode == PresentationMode::Choice) {
|
||||||
|
handlePointerMoved(x, y, model);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogueOverlay::handlePointerMoved(float x, float y, const PresentationModel& model) {
|
||||||
|
if (model.mode == PresentationMode::Choice) {
|
||||||
|
hoveredChoiceIndex = -1;
|
||||||
|
for (size_t i = 0; i < lastChoiceRects.size(); ++i) {
|
||||||
|
if (rectContains(lastChoiceRects[i], x, y)) {
|
||||||
|
hoveredChoiceIndex = static_cast<int>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hoveredChoiceIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DialogueOverlay::handlePointerReleased(float x, float y, const PresentationModel& model, int& outChoiceIndex, bool& outAdvanceDialogue) {
|
||||||
outChoiceIndex = -1;
|
outChoiceIndex = -1;
|
||||||
|
outAdvanceDialogue = false;
|
||||||
|
|
||||||
if (model.mode == PresentationMode::Choice) {
|
if (model.mode == PresentationMode::Choice) {
|
||||||
for (size_t i = 0; i < lastChoiceRects.size(); ++i) {
|
for (size_t i = 0; i < lastChoiceRects.size(); ++i) {
|
||||||
if (lastChoiceRects[i].contains(x, y)) {
|
if (rectContains(lastChoiceRects[i], x, y)) {
|
||||||
outChoiceIndex = static_cast<int>(i);
|
outChoiceIndex = static_cast<int>(i);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lastDialogueAdvanceRect.contains(x, y);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.mode == PresentationMode::Dialogue) {
|
if (model.mode == PresentationMode::Dialogue) {
|
||||||
return lastDialogueAdvanceRect.contains(x, y);
|
if (lastDialogueAdvanceRect.contains(x, y)) {
|
||||||
|
outAdvanceDialogue = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.mode == PresentationMode::Cutscene) {
|
if (model.mode == PresentationMode::Cutscene) {
|
||||||
@ -494,4 +524,8 @@ std::string DialogueOverlay::wrapText(const std::string& input, size_t maxLineLe
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DialogueOverlay::rectContains(const UiRect& rect, float x, float y) {
|
||||||
|
return x >= rect.x && x <= rect.x + rect.w && y >= rect.y && y <= rect.y + rect.h;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZL::Dialogue
|
} // namespace ZL::Dialogue
|
||||||
@ -15,11 +15,12 @@ namespace ZL::Dialogue {
|
|||||||
class DialogueOverlay {
|
class DialogueOverlay {
|
||||||
public:
|
public:
|
||||||
bool init(Renderer& renderer, const std::string& zipFile = "");
|
bool init(Renderer& renderer, const std::string& zipFile = "");
|
||||||
|
void update(const PresentationModel& model, int deltaMs);
|
||||||
void draw(Renderer& renderer, const PresentationModel& model);
|
void draw(Renderer& renderer, const PresentationModel& model);
|
||||||
|
|
||||||
// Coordinates are expected in the game's UI projection space
|
void handlePointerDown(float x, float y, const PresentationModel& model);
|
||||||
// Returns true only when the click should advance/select.
|
void handlePointerMoved(float x, float y, const PresentationModel& model);
|
||||||
bool handlePointerReleased(float x, float y, const PresentationModel& model, int& outChoiceIndex) const;
|
bool handlePointerReleased(float x, float y, const PresentationModel& model, int& outChoiceIndex, bool& outAdvanceDialogue);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TexturedQuad {
|
struct TexturedQuad {
|
||||||
@ -60,6 +61,8 @@ private:
|
|||||||
mutable UiRect lastCutsceneAdvanceRect{};
|
mutable UiRect lastCutsceneAdvanceRect{};
|
||||||
mutable bool cutsceneAdvanceEnabled = false;
|
mutable bool cutsceneAdvanceEnabled = false;
|
||||||
|
|
||||||
|
int hoveredChoiceIndex = -1;
|
||||||
|
|
||||||
std::unique_ptr<TextRenderer> nameRenderer;
|
std::unique_ptr<TextRenderer> nameRenderer;
|
||||||
std::unique_ptr<TextRenderer> bodyRenderer;
|
std::unique_ptr<TextRenderer> bodyRenderer;
|
||||||
std::unique_ptr<TextRenderer> choiceRenderer;
|
std::unique_ptr<TextRenderer> choiceRenderer;
|
||||||
@ -80,6 +83,7 @@ private:
|
|||||||
void drawQuad(Renderer& renderer, const TexturedQuad& quad, const std::shared_ptr<Texture>& texture) const;
|
void drawQuad(Renderer& renderer, const TexturedQuad& quad, const std::shared_ptr<Texture>& texture) const;
|
||||||
|
|
||||||
static std::string wrapText(const std::string& input, size_t maxLineLength);
|
static std::string wrapText(const std::string& input, size_t maxLineLength);
|
||||||
|
static bool rectContains(const UiRect& rect, float x, float y);
|
||||||
|
|
||||||
static float lerpFloat(float a, float b, float t);
|
static float lerpFloat(float a, float b, float t);
|
||||||
static ResolvedViewport resolveViewportPose(
|
static ResolvedViewport resolveViewportPose(
|
||||||
|
|||||||
@ -185,10 +185,26 @@ void DialogueRuntime::moveSelection(int delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int count = static_cast<int>(visibleChoices.size());
|
const int count = static_cast<int>(visibleChoices.size());
|
||||||
selectedChoice = (selectedChoice + delta) % count;
|
if (selectedChoice < 0 || selectedChoice >= count) {
|
||||||
if (selectedChoice < 0) {
|
selectedChoice = (delta >= 0) ? 0 : (count - 1);
|
||||||
selectedChoice += count;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
selectedChoice = (selectedChoice + delta) % count;
|
||||||
|
if (selectedChoice < 0) {
|
||||||
|
selectedChoice += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
presentation.selectedChoice = selectedChoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogueRuntime::selectChoice(int index) {
|
||||||
|
if (mode != Mode::WaitingForChoice || visibleChoices.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (index < 0 || index >= static_cast<int>(visibleChoices.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectedChoice = index;
|
||||||
presentation.selectedChoice = selectedChoice;
|
presentation.selectedChoice = selectedChoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,14 +362,14 @@ void DialogueRuntime::presentChoices(const Node& node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mode = Mode::WaitingForChoice;
|
mode = Mode::WaitingForChoice;
|
||||||
selectedChoice = 0;
|
selectedChoice = -1;
|
||||||
presentation.mode = PresentationMode::Choice;
|
presentation.mode = PresentationMode::Choice;
|
||||||
presentation.speaker = node.speaker;
|
presentation.speaker = node.speaker;
|
||||||
presentation.fullText = node.text;
|
presentation.fullText = node.text;
|
||||||
presentation.visibleText = node.text;
|
presentation.visibleText = node.text;
|
||||||
presentation.portraitPath = node.portrait;
|
presentation.portraitPath = node.portrait;
|
||||||
presentation.backgroundPath.clear();
|
presentation.backgroundPath.clear();
|
||||||
presentation.selectedChoice = 0;
|
presentation.selectedChoice = -1;
|
||||||
presentation.revealCompleted = true;
|
presentation.revealCompleted = true;
|
||||||
presentation.showCutsceneSubtitle = false;
|
presentation.showCutsceneSubtitle = false;
|
||||||
presentation.cutsceneCamera = {};
|
presentation.cutsceneCamera = {};
|
||||||
|
|||||||
@ -26,6 +26,7 @@ public:
|
|||||||
|
|
||||||
void confirmAdvance();
|
void confirmAdvance();
|
||||||
void moveSelection(int delta);
|
void moveSelection(int delta);
|
||||||
|
void selectChoice(int index);
|
||||||
|
|
||||||
const PresentationModel& getPresentation() const { return presentation; }
|
const PresentationModel& getPresentation() const { return presentation; }
|
||||||
|
|
||||||
|
|||||||
@ -66,24 +66,43 @@ bool DialogueSystem::handleKeyDown(SDL_Keycode key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DialogueSystem::handlePointerDown(float x, float y) {
|
||||||
|
if (!runtime.isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overlay.handlePointerDown(x, y, runtime.getPresentation());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DialogueSystem::handlePointerMoved(float x, float y) {
|
||||||
|
if (!runtime.isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overlay.handlePointerMoved(x, y, runtime.getPresentation());
|
||||||
|
}
|
||||||
|
|
||||||
bool DialogueSystem::handlePointerReleased(float x, float y) {
|
bool DialogueSystem::handlePointerReleased(float x, float y) {
|
||||||
if (!runtime.isActive()) {
|
if (!runtime.isActive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int choiceIndex = -1;
|
int choiceIndex = -1;
|
||||||
|
bool advanceDialogue = false;
|
||||||
const PresentationModel& model = runtime.getPresentation();
|
const PresentationModel& model = runtime.getPresentation();
|
||||||
if (!overlay.handlePointerReleased(x, y, model, choiceIndex)) {
|
if (!overlay.handlePointerReleased(x, y, model, choiceIndex, advanceDialogue)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (choiceIndex >= 0) {
|
if (choiceIndex >= 0) {
|
||||||
while (runtime.getPresentation().selectedChoice != choiceIndex) {
|
runtime.selectChoice(choiceIndex);
|
||||||
runtime.moveSelection(1);
|
runtime.confirmAdvance();
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advanceDialogue) {
|
||||||
|
runtime.confirmAdvance();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.confirmAdvance();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,8 @@ public:
|
|||||||
void draw(Renderer& renderer);
|
void draw(Renderer& renderer);
|
||||||
|
|
||||||
bool handleKeyDown(SDL_Keycode key);
|
bool handleKeyDown(SDL_Keycode key);
|
||||||
|
void handlePointerDown(float x, float y);
|
||||||
|
void handlePointerMoved(float x, float y);
|
||||||
bool handlePointerReleased(float x, float y);
|
bool handlePointerReleased(float x, float y);
|
||||||
|
|
||||||
bool startDialogue(const std::string& dialogueId);
|
bool startDialogue(const std::string& dialogueId);
|
||||||
|
|||||||
@ -174,7 +174,7 @@ struct PresentationModel {
|
|||||||
std::string portraitPath;
|
std::string portraitPath;
|
||||||
std::string backgroundPath;
|
std::string backgroundPath;
|
||||||
std::vector<PresentedChoice> choices;
|
std::vector<PresentedChoice> choices;
|
||||||
int selectedChoice = 0;
|
int selectedChoice = -1;
|
||||||
bool revealCompleted = true;
|
bool revealCompleted = true;
|
||||||
bool showCutsceneSubtitle = false;
|
bool showCutsceneSubtitle = false;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user