diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/consts.h | 3 | ||||
-rw-r--r-- | src/game.cpp | 33 | ||||
-rw-r--r-- | src/game.h | 15 | ||||
-rw-r--r-- | src/main.cpp | 2 | ||||
-rw-r--r-- | src/muxer.cpp | 12 | ||||
-rw-r--r-- | src/muxer.h | 2 | ||||
-rw-r--r-- | src/renderer.cpp | 96 | ||||
-rw-r--r-- | src/renderer.h | 57 | ||||
-rw-r--r-- | src/sign.cpp | 130 | ||||
-rw-r--r-- | src/sign.h | 45 |
10 files changed, 381 insertions, 14 deletions
diff --git a/src/consts.h b/src/consts.h index 78312c0..ecb2306 100644 --- a/src/consts.h +++ b/src/consts.h | |||
@@ -12,5 +12,8 @@ constexpr int CHUNK_WIDTH = 80; | |||
12 | constexpr int CHUNK_HEIGHT = 80; | 12 | constexpr int CHUNK_HEIGHT = 80; |
13 | constexpr int RADIUS = 8; | 13 | constexpr int RADIUS = 8; |
14 | constexpr int NUM_TITLES = 1; | 14 | constexpr int NUM_TITLES = 1; |
15 | constexpr int MESSAGE_MARGIN = 64; | ||
16 | constexpr int MESSAGE_TEXT_WIDTH = GAME_WIDTH - MESSAGE_MARGIN * 2; | ||
17 | constexpr int CHARS_PER_BEEP = 8; | ||
15 | 18 | ||
16 | #endif /* end of include guard: CONSTS_H_152EBF56 */ | 19 | #endif /* end of include guard: CONSTS_H_152EBF56 */ |
diff --git a/src/game.cpp b/src/game.cpp index 301447f..5838528 100644 --- a/src/game.cpp +++ b/src/game.cpp | |||
@@ -7,9 +7,10 @@ | |||
7 | #include "renderer.h" | 7 | #include "renderer.h" |
8 | #include "consts.h" | 8 | #include "consts.h" |
9 | 9 | ||
10 | Game::Game(std::mt19937& rng, Muxer& muxer) : | 10 | Game::Game(std::mt19937& rng, Muxer& muxer, Renderer& renderer) : |
11 | rng(rng), | 11 | rng(rng), |
12 | muxer(muxer) | 12 | muxer(muxer), |
13 | sign(renderer.getFont()) | ||
13 | { | 14 | { |
14 | losePopLampTimer.accumulate(losePopLampTimer.getDt()); | 15 | losePopLampTimer.accumulate(losePopLampTimer.getDt()); |
15 | 16 | ||
@@ -631,7 +632,7 @@ void Game::performDash() { | |||
631 | } | 632 | } |
632 | } | 633 | } |
633 | 634 | ||
634 | void Game::update(size_t frameTime) { | 635 | void Game::updatePlaying(size_t frameTime) { |
635 | SDL_Event e; | 636 | SDL_Event e; |
636 | 637 | ||
637 | while (SDL_PollEvent(&e)) | 638 | while (SDL_PollEvent(&e)) |
@@ -666,8 +667,22 @@ void Game::update(size_t frameTime) { | |||
666 | { | 667 | { |
667 | if (losing == LoseState::None) | 668 | if (losing == LoseState::None) |
668 | { | 669 | { |
670 | auto [lookX, lookY] = coordInDirection(player_x, player_y, playerAnim.getDirection()); | ||
671 | MapData& lookTile = map.at(lookX, lookY); | ||
669 | if (moving) { | 672 | if (moving) { |
670 | queueDash = true; | 673 | if (!lookTile.sign) { |
674 | queueDash = true; | ||
675 | } | ||
676 | } else if (lookTile.sign) { | ||
677 | if (lookTile.text.empty()) { | ||
678 | int lineToRead = nextSignIndex++; | ||
679 | if (nextSignIndex >= signTexts.size()) { | ||
680 | nextSignIndex = 0; | ||
681 | } | ||
682 | lookTile.text = signTexts[lineToRead]; | ||
683 | } | ||
684 | |||
685 | sign.displayMessage(lookTile.text); | ||
671 | } else { | 686 | } else { |
672 | performDash(); | 687 | performDash(); |
673 | } | 688 | } |
@@ -815,7 +830,7 @@ void Game::update(size_t frameTime) { | |||
815 | switch (signInstructionState) { | 830 | switch (signInstructionState) { |
816 | case SignInstructionState::Hidden: { | 831 | case SignInstructionState::Hidden: { |
817 | auto [lookX, lookY] = coordInDirection(player_x, player_y, playerAnim.getDirection()); | 832 | auto [lookX, lookY] = coordInDirection(player_x, player_y, playerAnim.getDirection()); |
818 | if (map.at(lookX, lookY).sign) { | 833 | if (losing == LoseState::None && map.at(lookX, lookY).sign) { |
819 | signInstructionState = SignInstructionState::FadingIn; | 834 | signInstructionState = SignInstructionState::FadingIn; |
820 | signFade.start(1000); | 835 | signFade.start(1000); |
821 | } | 836 | } |
@@ -913,3 +928,11 @@ void Game::update(size_t frameTime) { | |||
913 | 928 | ||
914 | playerAnim.update(frameTime); | 929 | playerAnim.update(frameTime); |
915 | } | 930 | } |
931 | |||
932 | void Game::update(size_t frameTime) { | ||
933 | if (sign.signDisplayState != SignInstructionState::Hidden) { | ||
934 | sign.update(frameTime, *this); | ||
935 | } else { | ||
936 | updatePlaying(frameTime); | ||
937 | } | ||
938 | } | ||
diff --git a/src/game.h b/src/game.h index 71685e6..637a033 100644 --- a/src/game.h +++ b/src/game.h | |||
@@ -11,6 +11,9 @@ | |||
11 | #include "animation.h" | 11 | #include "animation.h" |
12 | #include "interpolation.h" | 12 | #include "interpolation.h" |
13 | #include "consts.h" | 13 | #include "consts.h" |
14 | #include "sign.h" | ||
15 | |||
16 | class Renderer; | ||
14 | 17 | ||
15 | constexpr int TilesetIndex(int x, int y) { | 18 | constexpr int TilesetIndex(int x, int y) { |
16 | return x + y * 25; | 19 | return x + y * 25; |
@@ -23,13 +26,6 @@ enum class LoseState { | |||
23 | Outro | 26 | Outro |
24 | }; | 27 | }; |
25 | 28 | ||
26 | enum class SignInstructionState { | ||
27 | Hidden, | ||
28 | FadingIn, | ||
29 | Visible, | ||
30 | FadingOut | ||
31 | }; | ||
32 | |||
33 | struct Input { | 29 | struct Input { |
34 | bool left = false; | 30 | bool left = false; |
35 | bool right = false; | 31 | bool right = false; |
@@ -58,7 +54,7 @@ struct Kickup { | |||
58 | class Game { | 54 | class Game { |
59 | public: | 55 | public: |
60 | 56 | ||
61 | Game(std::mt19937& rng, Muxer& muxer); | 57 | Game(std::mt19937& rng, Muxer& muxer, Renderer& render); |
62 | 58 | ||
63 | void update(size_t dt); | 59 | void update(size_t dt); |
64 | 60 | ||
@@ -111,6 +107,7 @@ public: | |||
111 | int nextSignIndex = 0; | 107 | int nextSignIndex = 0; |
112 | SignInstructionState signInstructionState = SignInstructionState::Hidden; | 108 | SignInstructionState signInstructionState = SignInstructionState::Hidden; |
113 | Interpolation signFade; | 109 | Interpolation signFade; |
110 | Sign sign; | ||
114 | 111 | ||
115 | private: | 112 | private: |
116 | 113 | ||
@@ -144,6 +141,8 @@ private: | |||
144 | 141 | ||
145 | void performDash(); | 142 | void performDash(); |
146 | 143 | ||
144 | void updatePlaying(size_t frameTime); | ||
145 | |||
147 | }; | 146 | }; |
148 | 147 | ||
149 | #endif /* end of include guard: GAME_H_7D2B65AE */ | 148 | #endif /* end of include guard: GAME_H_7D2B65AE */ |
diff --git a/src/main.cpp b/src/main.cpp index 49f5ff2..2bd8f3c 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
@@ -21,7 +21,7 @@ int main(int, char**) | |||
21 | Renderer renderer; | 21 | Renderer renderer; |
22 | Muxer muxer; | 22 | Muxer muxer; |
23 | 23 | ||
24 | Game game(rng, muxer); | 24 | Game game(rng, muxer, renderer); |
25 | 25 | ||
26 | constexpr int titleFadeLen = 2000; | 26 | constexpr int titleFadeLen = 2000; |
27 | bool doneTitles = false; | 27 | bool doneTitles = false; |
diff --git a/src/muxer.cpp b/src/muxer.cpp index 3450187..c93c45a 100644 --- a/src/muxer.cpp +++ b/src/muxer.cpp | |||
@@ -42,6 +42,18 @@ void Muxer::setPlayerLoc(int x, int y) { | |||
42 | ERRCHECK(system_->setListenerAttributes(0, &attributes)); | 42 | ERRCHECK(system_->setListenerAttributes(0, &attributes)); |
43 | } | 43 | } |
44 | 44 | ||
45 | void Muxer::playSound(std::string name) { | ||
46 | std::string eventPath = std::string("event:/") + name; | ||
47 | |||
48 | FMOD::Studio::EventDescription* eventDescription = nullptr; | ||
49 | ERRCHECK(system_->getEvent(eventPath.c_str(), &eventDescription)); | ||
50 | |||
51 | FMOD::Studio::EventInstance* eventInstance = nullptr; | ||
52 | ERRCHECK(eventDescription->createInstance(&eventInstance)); | ||
53 | ERRCHECK(eventInstance->start()); | ||
54 | ERRCHECK(eventInstance->release()); | ||
55 | } | ||
56 | |||
45 | void Muxer::playSoundAtPosition(std::string name, float x, float y) { | 57 | void Muxer::playSoundAtPosition(std::string name, float x, float y) { |
46 | std::string eventPath = std::string("event:/") + name; | 58 | std::string eventPath = std::string("event:/") + name; |
47 | 59 | ||
diff --git a/src/muxer.h b/src/muxer.h index b1a5b26..9750808 100644 --- a/src/muxer.h +++ b/src/muxer.h | |||
@@ -28,6 +28,8 @@ public: | |||
28 | 28 | ||
29 | void setPlayerLoc(int x, int y); | 29 | void setPlayerLoc(int x, int y); |
30 | 30 | ||
31 | void playSound(std::string name); | ||
32 | |||
31 | void playSoundAtPosition(std::string name, float x, float y); | 33 | void playSoundAtPosition(std::string name, float x, float y); |
32 | 34 | ||
33 | void setMusicLevel(int level); | 35 | void setMusicLevel(int level); |
diff --git a/src/renderer.cpp b/src/renderer.cpp index 2be36ae..c8c1746 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "renderer.h" | 1 | #include "renderer.h" |
2 | #include <iostream> | ||
2 | #include "game.h" | 3 | #include "game.h" |
3 | 4 | ||
4 | Renderer::Renderer() | 5 | Renderer::Renderer() |
@@ -113,6 +114,11 @@ Renderer::Renderer() | |||
113 | 114 | ||
114 | loadTextureFromFile("../res/title0.png", titles_[0]); | 115 | loadTextureFromFile("../res/title0.png", titles_[0]); |
115 | SDL_QueryTexture(titles_[0].get(), nullptr, nullptr, &titleWidths_[0], &titleHeights_[0]); | 116 | SDL_QueryTexture(titles_[0].get(), nullptr, nullptr, &titleWidths_[0], &titleHeights_[0]); |
117 | |||
118 | font_ = font_ptr(TTF_OpenFont("../res/softsquare.ttf", 45)); | ||
119 | if (!font_) { | ||
120 | throw ttf_error(); | ||
121 | } | ||
116 | } | 122 | } |
117 | 123 | ||
118 | void Renderer::renderGame( | 124 | void Renderer::renderGame( |
@@ -389,6 +395,55 @@ void Renderer::renderGame( | |||
389 | SDL_RenderCopy(ren_.get(), readInstruction_.get(), nullptr, nullptr); | 395 | SDL_RenderCopy(ren_.get(), readInstruction_.get(), nullptr, nullptr); |
390 | } | 396 | } |
391 | 397 | ||
398 | if (game.sign.signDisplayState != SignInstructionState::Hidden) { | ||
399 | int opacity = 255; | ||
400 | if (game.sign.signDisplayState == SignInstructionState::FadingIn) { | ||
401 | opacity = game.sign.signDisplayFade.getProgress(0, 255); | ||
402 | } else if (game.sign.signDisplayState == SignInstructionState::FadingOut) { | ||
403 | opacity = game.sign.signDisplayFade.getProgress(255, 0); | ||
404 | } | ||
405 | |||
406 | SDL_Rect signRect { | ||
407 | 0, | ||
408 | GAME_HEIGHT / 2 - (45 * 2 + 1 + MESSAGE_MARGIN * 2) / 2, | ||
409 | GAME_WIDTH, | ||
410 | 45 * 2 + 1 + MESSAGE_MARGIN * 2 | ||
411 | }; | ||
412 | |||
413 | SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_BLEND); | ||
414 | SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, opacity); | ||
415 | SDL_RenderFillRect(ren_.get(), &signRect); | ||
416 | |||
417 | if (game.sign.signDisplayState == SignInstructionState::Visible) { | ||
418 | int lineIndex = 0; | ||
419 | for (const SignLine& line : game.sign.linesToShow) { | ||
420 | if (messageLines_[lineIndex].line != line.text) { | ||
421 | renderMessageLine(messageLines_[lineIndex], line.text, game); | ||
422 | } | ||
423 | |||
424 | if (line.charsRevealed > 0) { | ||
425 | { | ||
426 | SDL_Rect srcRect { | ||
427 | 0, 0, messageLines_[lineIndex].charIndexToWidth[line.charsRevealed], | ||
428 | TTF_FontHeight(font_.get()) | ||
429 | }; | ||
430 | SDL_Rect destRect { | ||
431 | MESSAGE_MARGIN, | ||
432 | GAME_HEIGHT / 2 - (45 * 2 + 1 + MESSAGE_MARGIN * 2) / 2 + MESSAGE_MARGIN + (45 + 1) * lineIndex, | ||
433 | srcRect.w, | ||
434 | srcRect.h }; | ||
435 | |||
436 | SDL_SetRenderTarget(ren_.get(), nullptr); | ||
437 | SDL_RenderCopy(ren_.get(), messageLines_[lineIndex].renderedTex.get(), &srcRect, &destRect); | ||
438 | //std::cout << line.charsRevealed << " (" << messageLines_[lineIndex].charIndexToWidth[line.charsRevealed] << "): " << messageLines_[lineIndex].line.substr(0,line.charsRevealed) << std::endl; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | lineIndex++; | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
392 | SDL_RenderPresent(ren_.get()); | 447 | SDL_RenderPresent(ren_.get()); |
393 | } | 448 | } |
394 | 449 | ||
@@ -443,3 +498,44 @@ void Renderer::loadTextureFromFile(std::string_view path, texture_ptr& texture) | |||
443 | texture = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get())); | 498 | texture = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get())); |
444 | SDL_SetTextureBlendMode(texture.get(), SDL_BLENDMODE_BLEND); | 499 | SDL_SetTextureBlendMode(texture.get(), SDL_BLENDMODE_BLEND); |
445 | } | 500 | } |
501 | |||
502 | void Renderer::renderMessageLine(MessageCache& line, const std::string& text, const Game& game) { | ||
503 | line.line = text; | ||
504 | |||
505 | line.renderedTex.reset( | ||
506 | SDL_CreateTexture( | ||
507 | ren_.get(), | ||
508 | SDL_PIXELFORMAT_RGBA8888, | ||
509 | SDL_TEXTUREACCESS_TARGET, | ||
510 | MESSAGE_TEXT_WIDTH, | ||
511 | TTF_FontHeight(font_.get()))); | ||
512 | |||
513 | SDL_SetTextureBlendMode(line.renderedTex.get(), SDL_BLENDMODE_BLEND); | ||
514 | |||
515 | SDL_SetRenderTarget(ren_.get(), line.renderedTex.get()); | ||
516 | SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_BLEND); | ||
517 | SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0); | ||
518 | SDL_RenderClear(ren_.get()); | ||
519 | |||
520 | line.charIndexToWidth.clear(); | ||
521 | line.charIndexToWidth.push_back(0); | ||
522 | |||
523 | for (int i=0; i<line.line.size(); i++) { | ||
524 | if (line.line[i] != ' ') { | ||
525 | int width = 0; | ||
526 | std::string substr = line.line.substr(0, i+1); | ||
527 | TTF_SizeText(font_.get(), substr.c_str(), &width, nullptr); | ||
528 | line.charIndexToWidth.push_back(width); | ||
529 | } else { | ||
530 | line.charIndexToWidth.push_back(line.charIndexToWidth.back()); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | SDL_Color fgColor {.r = 255, .g = 255, .b = 255, .a = 255}; | ||
535 | SDL_Color bgColor {.r = 0, .g = 0, .b = 0, .a = 255}; | ||
536 | SDL_Rect rect {0, 0, line.charIndexToWidth.back(), TTF_FontHeight(font_.get())}; | ||
537 | surface_ptr lineSurf = surface_ptr(TTF_RenderText_Shaded(font_.get(), line.line.c_str(), fgColor, bgColor)); | ||
538 | texture_ptr lineTex = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), lineSurf.get())); | ||
539 | SDL_RenderCopy(ren_.get(), lineTex.get(), nullptr, &rect); | ||
540 | } | ||
541 | |||
diff --git a/src/renderer.h b/src/renderer.h index de1e125..ce2e7e1 100644 --- a/src/renderer.h +++ b/src/renderer.h | |||
@@ -3,10 +3,13 @@ | |||
3 | 3 | ||
4 | #include <SDL.h> | 4 | #include <SDL.h> |
5 | #include <SDL_image.h> | 5 | #include <SDL_image.h> |
6 | #include <SDL_ttf.h> | ||
6 | #include <stdexcept> | 7 | #include <stdexcept> |
7 | #include <memory> | 8 | #include <memory> |
8 | #include <array> | 9 | #include <array> |
9 | #include <string_view> | 10 | #include <string_view> |
11 | #include <vector> | ||
12 | #include <string> | ||
10 | #include "consts.h" | 13 | #include "consts.h" |
11 | 14 | ||
12 | class Game; | 15 | class Game; |
@@ -27,6 +30,14 @@ public: | |||
27 | } | 30 | } |
28 | }; | 31 | }; |
29 | 32 | ||
33 | class ttf_error : public std::logic_error { | ||
34 | public: | ||
35 | |||
36 | ttf_error() : std::logic_error(TTF_GetError()) | ||
37 | { | ||
38 | } | ||
39 | }; | ||
40 | |||
30 | class sdl_wrapper { | 41 | class sdl_wrapper { |
31 | public: | 42 | public: |
32 | 43 | ||
@@ -67,6 +78,26 @@ public: | |||
67 | } | 78 | } |
68 | }; | 79 | }; |
69 | 80 | ||
81 | class ttf_wrapper { | ||
82 | public: | ||
83 | |||
84 | ttf_wrapper() | ||
85 | { | ||
86 | if (TTF_Init() != 0) | ||
87 | { | ||
88 | ttf_error ex; | ||
89 | TTF_Quit(); | ||
90 | |||
91 | throw ex; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | ~ttf_wrapper() | ||
96 | { | ||
97 | TTF_Quit(); | ||
98 | } | ||
99 | }; | ||
100 | |||
70 | class window_deleter { | 101 | class window_deleter { |
71 | public: | 102 | public: |
72 | 103 | ||
@@ -111,6 +142,16 @@ public: | |||
111 | 142 | ||
112 | using texture_ptr = std::unique_ptr<SDL_Texture, texture_deleter>; | 143 | using texture_ptr = std::unique_ptr<SDL_Texture, texture_deleter>; |
113 | 144 | ||
145 | class font_deleter { | ||
146 | public: | ||
147 | |||
148 | void operator()(TTF_Font* ptr) { | ||
149 | TTF_CloseFont(ptr); | ||
150 | } | ||
151 | }; | ||
152 | |||
153 | using font_ptr = std::unique_ptr<TTF_Font, font_deleter>; | ||
154 | |||
114 | class Renderer { | 155 | class Renderer { |
115 | public: | 156 | public: |
116 | 157 | ||
@@ -122,14 +163,18 @@ public: | |||
122 | 163 | ||
123 | void renderTitle(int num, double fade); | 164 | void renderTitle(int num, double fade); |
124 | 165 | ||
166 | TTF_Font* getFont() { return font_.get(); } | ||
167 | |||
125 | private: | 168 | private: |
126 | 169 | ||
127 | void loadTextureFromFile(std::string_view path, texture_ptr& texture); | 170 | void loadTextureFromFile(std::string_view path, texture_ptr& texture); |
128 | 171 | ||
129 | sdl_wrapper sdl_; | 172 | sdl_wrapper sdl_; |
130 | img_wrapper img_; | 173 | img_wrapper img_; |
174 | ttf_wrapper ttf_; | ||
131 | window_ptr win_; | 175 | window_ptr win_; |
132 | renderer_ptr ren_; | 176 | renderer_ptr ren_; |
177 | font_ptr font_; | ||
133 | 178 | ||
134 | texture_ptr playerFade_; | 179 | texture_ptr playerFade_; |
135 | texture_ptr lampFade_; | 180 | texture_ptr lampFade_; |
@@ -142,6 +187,18 @@ private: | |||
142 | std::array<texture_ptr, NUM_TITLES> titles_; | 187 | std::array<texture_ptr, NUM_TITLES> titles_; |
143 | std::array<int, NUM_TITLES> titleWidths_; | 188 | std::array<int, NUM_TITLES> titleWidths_; |
144 | std::array<int, NUM_TITLES> titleHeights_; | 189 | std::array<int, NUM_TITLES> titleHeights_; |
190 | |||
191 | // Text rendering | ||
192 | struct MessageCache { | ||
193 | texture_ptr renderedTex; | ||
194 | std::vector<int> charIndexToWidth; | ||
195 | std::string line; | ||
196 | std::string overflow; | ||
197 | }; | ||
198 | |||
199 | void renderMessageLine(MessageCache& line, const std::string& text, const Game& game); | ||
200 | |||
201 | MessageCache messageLines_[2]; | ||
145 | }; | 202 | }; |
146 | 203 | ||
147 | #endif /* end of include guard: RENDERER_H_6A58EC30 */ | 204 | #endif /* end of include guard: RENDERER_H_6A58EC30 */ |
diff --git a/src/sign.cpp b/src/sign.cpp new file mode 100644 index 0000000..992ac3d --- /dev/null +++ b/src/sign.cpp | |||
@@ -0,0 +1,130 @@ | |||
1 | #include "sign.h" | ||
2 | #include <list> | ||
3 | #include "util.h" | ||
4 | #include "consts.h" | ||
5 | #include "game.h" | ||
6 | |||
7 | void Sign::displayMessage(std::string text) { | ||
8 | signDisplayState = SignInstructionState::FadingIn; | ||
9 | lines.clear(); | ||
10 | |||
11 | auto lineChunks = splitStr<std::list<std::string>>(text, "\\n"); | ||
12 | for (std::string lineChunk : lineChunks) { | ||
13 | auto words = splitStr<std::list<std::string>>(lineChunk, " "); | ||
14 | std::string prev = words.front(); | ||
15 | words.pop_front(); | ||
16 | std::string cur = prev; | ||
17 | bool pauseLine = false; | ||
18 | |||
19 | while (!words.empty()) { | ||
20 | cur = prev + " " + words.front(); | ||
21 | |||
22 | int width = 0; | ||
23 | TTF_SizeText(font_, cur.c_str(), &width, nullptr); | ||
24 | if (width > MESSAGE_TEXT_WIDTH) { | ||
25 | lines.push_back({.text = prev, .pause = pauseLine}); | ||
26 | pauseLine = !pauseLine; | ||
27 | cur = words.front(); | ||
28 | } else if (words.size() == 1) { | ||
29 | lines.push_back({.text = cur, .pause = true}); | ||
30 | } | ||
31 | |||
32 | prev = cur; | ||
33 | words.pop_front(); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | lines.back().pause = true; | ||
38 | linesToShow.push_back(lines.front()); | ||
39 | lines.pop_front(); | ||
40 | |||
41 | if (!linesToShow.back().pause) { | ||
42 | linesToShow.push_back(lines.front()); | ||
43 | lines.pop_front(); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | void Sign::update(size_t dt, Game& game) { | ||
48 | SDL_Event e; | ||
49 | |||
50 | while (SDL_PollEvent(&e)) { | ||
51 | if (e.type == SDL_QUIT) { | ||
52 | game.quit = true; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | switch (signDisplayState) { | ||
57 | case SignInstructionState::Hidden: { | ||
58 | // Shouldn't happen. | ||
59 | break; | ||
60 | } | ||
61 | case SignInstructionState::FadingIn: { | ||
62 | signDisplayFade.tick(dt); | ||
63 | if (signDisplayFade.isComplete()) { | ||
64 | signDisplayState = SignInstructionState::Visible; | ||
65 | } | ||
66 | |||
67 | break; | ||
68 | } | ||
69 | case SignInstructionState::FadingOut: { | ||
70 | signDisplayFade.tick(dt); | ||
71 | if (signDisplayFade.isComplete()) { | ||
72 | signDisplayState = SignInstructionState::Hidden; | ||
73 | } | ||
74 | |||
75 | break; | ||
76 | } | ||
77 | case SignInstructionState::Visible: { | ||
78 | const Uint8* state = SDL_GetKeyboardState(NULL); | ||
79 | if (state[SDL_SCANCODE_SPACE]) { | ||
80 | bool fullyRevealed = true; | ||
81 | for (const SignLine& line : linesToShow) { | ||
82 | if (line.charsRevealed != line.text.size()) { | ||
83 | fullyRevealed = false; | ||
84 | break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | if (fullyRevealed) { | ||
89 | if (linesToShow.back().pause) { | ||
90 | linesToShow.back().pause = false; | ||
91 | // Play a sound | ||
92 | } | ||
93 | if (lines.empty()) { | ||
94 | linesToShow.clear(); | ||
95 | signDisplayState = SignInstructionState::FadingOut; | ||
96 | signDisplayFade.start(1000); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | textAdvTimer_.accumulate(dt); | ||
103 | while (textAdvTimer_.step()) { | ||
104 | bool advancedChars = false; | ||
105 | for (SignLine& line : linesToShow) { | ||
106 | if (line.charsRevealed < line.text.size()) { | ||
107 | if (line.charsRevealed % CHARS_PER_BEEP == 0) { | ||
108 | // Play a sound | ||
109 | game.muxer.playSound("textbeep"); | ||
110 | } | ||
111 | line.charsRevealed++; | ||
112 | advancedChars = true; | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | if (!advancedChars) { | ||
117 | if (!lines.empty() && !linesToShow.back().pause) { | ||
118 | if (linesToShow.size() == 2) { | ||
119 | linesToShow.pop_front(); | ||
120 | } | ||
121 | linesToShow.push_back(lines.front()); | ||
122 | lines.pop_front(); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | } | ||
diff --git a/src/sign.h b/src/sign.h new file mode 100644 index 0000000..c90a8fd --- /dev/null +++ b/src/sign.h | |||
@@ -0,0 +1,45 @@ | |||
1 | #ifndef SIGN_H_B0491849 | ||
2 | #define SIGN_H_B0491849 | ||
3 | |||
4 | #include <string> | ||
5 | #include <list> | ||
6 | #include <SDL_ttf.h> | ||
7 | #include "interpolation.h" | ||
8 | #include "timer.h" | ||
9 | |||
10 | class Game; | ||
11 | |||
12 | enum class SignInstructionState { | ||
13 | Hidden, | ||
14 | FadingIn, | ||
15 | Visible, | ||
16 | FadingOut | ||
17 | }; | ||
18 | |||
19 | struct SignLine { | ||
20 | std::string text; | ||
21 | bool pause = false; | ||
22 | int charsRevealed = 0; | ||
23 | }; | ||
24 | |||
25 | class Sign { | ||
26 | public: | ||
27 | |||
28 | explicit Sign(TTF_Font* font) : font_(font) {} | ||
29 | |||
30 | void displayMessage(std::string text); | ||
31 | |||
32 | void update(size_t dt, Game& game); | ||
33 | |||
34 | SignInstructionState signDisplayState = SignInstructionState::Hidden; | ||
35 | Interpolation signDisplayFade; | ||
36 | std::list<SignLine> lines; | ||
37 | std::list<SignLine> linesToShow; | ||
38 | |||
39 | private: | ||
40 | |||
41 | TTF_Font* font_; | ||
42 | Timer textAdvTimer_ { 15 }; | ||
43 | }; | ||
44 | |||
45 | #endif /* end of include guard: SIGN_H_B0491849 */ | ||