Update 'Step 1: Scene, Systems, and Actions'
parent
211cebb422
commit
edc9aeb766
|
@ -1,5 +1,82 @@
|
|||
Now that the component and entity are basically implemented with a manager, the next step actually use them.
|
||||
# Scenes
|
||||
In a game, there would be many _Scenes_, such as main game loop, main menu, pause screen, etc. Each Scene has its own logic, systems, key handling, and entities.
|
||||
The lecture uses OO design approach to implementing Scenes. It introduces a BaseScene interface class where it would contains common Scene function and data. Subsequent Scenes will derived from the BaseScene to implement Scene-specific logic.
|
||||
|
||||
Unfortunately, once again, C does not have such convenience. So, I have to emulate it somewhat. The implementation will also have a base Scene struct. Subsequent implemented Scene will need to contain a Scene field and a Scene-specific data field.
|
||||
|
||||
The base Scene struct looks like this in `scene.h`:
|
||||
```
|
||||
struct Scene
|
||||
{
|
||||
struct sc_map_64 action_map; // key -> actions
|
||||
struct sc_array_systems systems;
|
||||
system_func_t render_function;
|
||||
action_func_t action_function;
|
||||
EntityManager_t ent_manager;
|
||||
SceneType_t scene_type;
|
||||
void * scene_data;
|
||||
bool paused;
|
||||
bool has_ended;
|
||||
};
|
||||
```
|
||||
Note that in the base Scene struct, it holds a pointer the scene-specific data.
|
||||
|
||||
As a starter, the LevelScene struct, which is where the gameplay takes place, is implemented as such in `scene_impl.h`:
|
||||
```
|
||||
typedef struct LevelScene
|
||||
{
|
||||
Scene_t scene;
|
||||
LevelSceneData_t data;
|
||||
}LevelScene_t;
|
||||
|
||||
typedef struct LevelSceneData
|
||||
{
|
||||
Vector2 player_dir;
|
||||
TileGrid_t tilemap;
|
||||
bool jumped_pressed;
|
||||
bool crouch_pressed;
|
||||
}LevelSceneData_t;
|
||||
```
|
||||
As seen above, these data fields are specific to the LevelScene. The LevelSceneData is then set as the Scene `scene_data` pointer during initialisation.
|
||||
# Systems
|
||||
As mentioned before, systems are functions that describes the interactions of components and/or entities. Systems can vary between Scene to Scene. In this implementation, a system is a function pointer that takes in a pointer to a base Scene class and returns nothing. Using the Scene class, Scene-specific data can be accessed via the `scene_data` pointer, while the entities and/or components can be access via the `ent_manager` field.
|
||||
|
||||
# Actions
|
||||
During the loop, the systems are executed in a linear order. Therefore, the **order** of the systems added to the Scene is important.
|
||||
# Key Handling and Actions
|
||||
As per the lectures, Actions are introduced as interface to the physical controls used. The buttons/keys/motions of the physical inputs are translate into these Actions via a defined mapping that is registered during runtime.
|
||||
|
||||
Actions can performed different things for different scenes. E.g. the Up action in a main menu would move the selection pointer upwards, while that may cause the player to jump in a gameplay scene.
|
||||
|
||||
Therefore, Scenes must also implement what Actions would do for that scene under `action_function` field.
|
||||
|
||||
Raylib provides functions to detect key presses and releases. One nice function is the `GetKeyPressed` function which gives the keys pressed (not hold) for the frame. Internally, Raylib maintains a queue for the key pressed. However, it does not have a corresponding function to detect key releases.
|
||||
|
||||
To deal with this, a separate queue is used to maintain the key already pressed in order to check for releases. In the implementation, the keys that are pressed previously are checked for release. Then, it will check for any new key presses. A snippet for this logic can be seen in `scene_test.c`
|
||||
```
|
||||
struct sc_queue_32 key_buffer;
|
||||
...
|
||||
for (size_t i=0; i<sz; i++)
|
||||
{
|
||||
int button = sc_queue_del_first(&key_buffer);
|
||||
ActionType_t action = sc_map_get_64(&scene.scene.action_map, button);
|
||||
if (IsKeyReleased(button))
|
||||
{
|
||||
do_action(&scene.scene, action, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
do_action(&scene.scene, action, true);
|
||||
sc_queue_add_last(&key_buffer, button);
|
||||
}
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
int button = GetKeyPressed();
|
||||
if (button == 0) break;
|
||||
ActionType_t action = sc_map_get_64(&scene.scene.action_map, button);
|
||||
if (!sc_map_found(&scene.scene.action_map)) continue;
|
||||
do_action(&scene.scene, action, true);
|
||||
sc_queue_add_last(&key_buffer, button);
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue