-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path3-game_loop.cpp
More file actions
141 lines (110 loc) · 5.95 KB
/
3-game_loop.cpp
File metadata and controls
141 lines (110 loc) · 5.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
KTech's Tutorial, the official KTech tutorial taught by examples.
Copyright (C) 2023-2024 Ethan Kaufman (AKA Kaup)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../../ktech/ktech.hpp"
auto main() -> int
{
/*
Here's a basic game world hierarchy. Change it however you'd like.
map
|________
v v
layer camera
|
v
object
*/
// Engine
KTech::Engine engine{KTech::UPoint(15, 8), 24};
// Map
KTech::Map map{engine};
// Layer: add it to `map`.
KTech::Layer layer{engine, map.m_id};
// Object: add it to `layer`
KTech::Object object{engine, layer.m_id, KTech::Point(5, 2)};
// Give `object` some `Texture`s.
object.m_textures.resize(2);
object.m_textures[0].Simple(
KTech::UPoint(3, 3),
KTech::CellA('a', KTech::RGBAColors::black, KTech::RGBAColors::white)
// Relative position not given: (0, 0) by default.
);
object.m_textures[1].Simple(
KTech::UPoint(3, 3),
KTech::CellA('b', KTech::RGBAColors::white, KTech::RGBAColors::black),
KTech::Point(1, 1)
);
// Camera: add it to `Map`
KTech::Camera camera{engine, map.m_id, KTech::Point(0, 0), engine.output.resolution};
// Give the camera a background color (`Camera::m_background` is a `CellA`, and `CellA::b` is the `RGBA` background color).
camera.m_background.b = KTech::RGBAColors::blue;
/*
In KTech, you (the user) create your own game loop.
The "game loop" is a loop that times and runs game iterations, which are known as "ticks".
Each individual tick is usually responsible of (we are going to dive deeper into each of these tasks):
- Updating the game state:
- Distribute player inputs.
- Call due timed invocations.
- Call on-tick functions.
- Outputting the game state:
- Render.
- Draw.
- Print.
- Waiting and continuing to the next tick.
A game loop encloses these tasks (in an iteration; a tick) and lets them iterate as long as the game should keep running.
*/
/*
After initializing our game (creating all our world structures and joining them together), we should enter our game loop, because we are ready for the game to start running:
*/
while (engine.running) // (1)
{
// Call functions, that call other functions, that change things in your game:
engine.input.CallCallbacks(); // (2)
engine.time.CallInvocations(); // (3)
engine.memory.CallOnTicks(); // (4)
if (engine.output.ShouldRenderThisTick()) // (5)
{
// Draw and print if the game changed:
camera.Render(); // (6)
camera.Draw(); // (7)
engine.output.Print(); // (8)
}
else if (engine.output.ShouldPrintThisTick()) // (9)
{
// Print if the terminal changed:
engine.output.Print();
}
// Continue to the next tick after timing it.
engine.time.WaitUntilNextTick(); // (10)
}
/*
After existing the game loop, your game should prepare to quit (e.g. by saving player progress).
*/
/*
Let's understand each step:
1: `Engine::running` is a simple `bool` variable that states whether the game loop should keep iterating, or exit. It's `true` by default, and can be set to `false` from anywhere to safely exit the game. For example, it is automatically set to `false` when the input engine component receives the quit key (Control+C by default). This leads to your game loop exiting, allowing you to prepare before the game actually quits when `main()` reaches its end (for example, by saving player progress).
2: `Engine::input` is the input engine component. `Input::CallCallbacks()` distributes player inputs to your functions, which we will try later.
3: `Engine::time` is the time engine component. `Time::CallInvocations()` calls functions that were invoked (by you directly or indirectly) to be called in this tick. We will also invoke functions in a later chapter.
4: `Engine::memory` is the memory engine component. `Memory::CallOnTicks()` calls the `OnTick()` function of all world structures. Of course, we will utilize this functionality as well, but later.
5: `Engine::output` is the output engine component. `Output::ShouldRenderThisTick()` answers the following question: "did anything change by calling those previous 3 functions?" If it returns `true`, it means we should render our game again because the previously printed frame is outdated.
6: `Camera::Render()` renders all of the `Object`s of all of the `Layer`s in its parent `Map`.
7: `Camera::Draw()` draws the just-rendered image to the output engine component's image buffer.
8: `Output::Print()` prints the image buffer to the terminal, for the player to see.
9: `Output::ShouldPrintThisTick()` answers the following question: "did the terminal change its size?" If it returns `true`, it means that the last image that was printed to the terminal got squashed or wasn't full, so we should print it again to display it correctly in the terminal.
10: `Time::WaitUntilNextTick()` enters sleep (temporarily set the thread to an inactive state) for the duration of time that will make our game loop run at a consistent rate, also know as the "ticks per second" (TPS) rate. It's the value we specified previously in `Engine`'s constructor, 24. That means this game loop will iterate 24 times every second, which includes updating the game's state, rendering it (assuming it changes every tick), and printing it, 24 times every second.
*/
/*
You should build and run this source file (`build/bin/3-game_loop`) to see how it looks like. Then continue to the next chapter.
*/
}