owned this note
owned this note
Published
Linked with GitHub
---
tags: allegro5-practice
---
# Note for sample game routine (in C)
:::info
Note:
This is a draft note for an Allegro5 practice project ([ ***Link*** ](https://github.com/pykenny/Allegro5_Game_Practice)).
Update for this project will mainly focus on code implementation (i.e., the GitHub repo above), so notes here may not be up-to-date, or inconsistent with the latest version.
:::
## Main Goal
To write a space-evader-like game in C, and further convert it to [*ATS2*](http://www.ats-lang.org/) implementation on top-level logic. That's it!
Some expected outcome for final deliverable:
- Game menu with HI-score
- A space evader game as the main body
- Provide pause menu to let users have some water during gameplay
## TODO List
[Here](/2qnaNdwCQmKa0UcTvd7N2A) is the TODO list for short/long term goal for implementation.
## Components - I
Rudiment thought about components that should be handled separatedly at top-level logic:
### Control
Essentially an Allegro5 event queue, ***TIMER + KEYBOARD + SCREEN*** events are required.
Status (described below) that interacts with user operation will access and listen to this component.
### Process status
What the main (or the most outer / top) routine do is to keep checking returned value from subroutine function currently runned. These returned values are essentially state transfers of the main routine.
Subroutines can also have their own inner states and structured with similar logic. Hence the whole process is expected to become a nested structure of subroutines.
On the topmost level, it would be something looks like this:
```c
/* (...) */
int proc_status = STATE_INIT;
int return_stat = 0;
/* Assume STATE_EXIT == 0. */
while (proc_status) {
switch (proc_status) {
case STATE_INIT:
proc_status = proc_init(...);
break;
case STATE_MENU:
proc_status = proc_menu(...);
break;
/* (...some other states...) */
case STATE_FINISH:
/* Do any required resource cleanup here */
proc_status = proc_finish(...);
/* proc_status should be STATE_EXIT here. */
break;
}
}
return return_stat; /* Pass to main/main0's return */
```
- **Init** (#Start state)
Time during initialization.
* Branches:
- Init completed -> **Menu**
- Failed on init -> **Finish**
- **Menu** ($Control)
Show menu before gameplay. Maybe provide some information about hi-score and hi-score of the latest gameplay.
* Branches:
- User select 'Play' -> **Gameplay**
- User select 'Exit' -> **Finish**
- User tries to shut off anyway -> **Finish**
- **Gameplay** ($Control)
Do gameplay, you know it.
* Branches
- User tries to shut off anyway -> **Finish**
- User tries to return to menu -> **Menu**
- User press stop button -> **Pause**
- **Finish**
Do any cleanup if needed.
Generally Allegro5 will do most of its routine cleanup, so just checkout if there's any need to release resource (include self defined structures and other Allegro5 objects).
* Branches
- End with cleanup -> **Exit**
- **Exit** (#End state)
Just a flag used to break off main routine.
## Components - II
This part is for components related to gameplay routine.
One thing I have in mind is about how to extend the structure into multi-stage game in the future, which is a very common concept for arcade games. So the thoughts here will try to prepare space for this part.
### States for Gameplay
- **Init** ($Start state)
Handle required initialization
* Branches
- After initialization -> **Playing**
- Failed -> **Finish**
- **Playing**
User is interacting with the game in realtime.
* Branches
- User tries to shut off anyway -> **Finish**
- User stop the game -> **Pause**
- **Pause**
Pause the game and require user's further operation
* Branches
- User tries to shut off anyway -> **Finish**
- User select resume -> **Gameplay**
- User select back to title -> **Menu**
- **Finish**
Clear off related resouce
* Branches
- The only result -> **Exit**
- **Exit** ($End state)
Exit flag after resource clear-off
### Player
Status of player. The gameplay routine should keep track of this status because when player lose all tokens (may be life points, HP, or cash, etc.) it should directly lead the gameplay to the end. Since multi-stage game generally preserve player's status to the next stage, it should be treated as a separated component at higher level, instead of being wrapped in stage component.
### Stage
Represents a single stage, which is a complex structure includes overall status of the stage along with related resources (for instance, background image) and logic for stage components (enemy movements, drawing, etc.).
### Shared-Resource
There should be some globally shared resources (for instance, items in the game) that are commonly used, and would be better to stored in some shared-resource component to make the program efficient.
There are some possible resources which can be stored in this component:
- Small sound effects
* Large ones (such as WAV format musics) should be loaded on stage creation to save memory
- Commonly used images/texures (such as player status interface and stage-shared entities)
### General Functions for/between Components
For this game, I think it's mostly:
- collision (deal with collision between different shapes)
- Shape drawing (however right now I'll just use 2D image pasting so this is not urgent)
## Some Thoughts about Collision ~and\ Shape\ Data\ Format~
In current implementation it's just all rectangular collisions, but more complicated ones may be required in the future:
### Angle/Rotation
Right now there's no need for rotation. However, we'll probably need libraries that support matrix computation if added.
### Rect-Rect
The most simplest ones, only require 4 boundary overlap checkings.
Four numeral data required: $(x_{center}, y_{center}, x_{half-width}, y_{half-height})$
### Circle-Circle
Compute distance between two centers and check relationship between (R1 + R2).
Three numeral data required: $(x_{center}, y_{center}, r)$
### Rect-Circle
TODO: [Reference](https://yal.cc/rectangle-circle-intersection-test/)
### Oval
Solving oval collision mathematically is not feasible for game physics. There are some approximation on oval function but still takes much (non-simple) computation process. One way to deal with this is to "fake" oval with combination of circles and rectangles, or just circles.
A straightforward way to do so for all-circle implementation: given limit on number of circles used $C_{lim}$, its data can be represented as $(size, data[C_{lim} * 3])$.
## Some Thoughts about Animation
Does not have background knowledge about 2D/3D drawing library (such as DirectX on Windows) so right now I'll just skip this part. But will sure to be required for asthetic consideration(?).
### About Frame-wise animation
You'll need:
- Priority (or sorted) queue that allows filtering (pop off completed effects), which stores some structure that contains:
1. Drawing function.
2. A list of related entities (which will be sent into the drawing function). For instance, pointer to an enemy object that indicates eneny position.
3. Counter of effect lifetime. (which will be sent into the drawing function) This is important for frame if sprite is used.
- An array that keeps a group of these queues of size $N$, used to represent drawing layers
- An array of size $N$ that keeps a group of linked lists (or perhaps priority queues?) for effect blenders on each layer
A algorithm for animation is described below, for each frame:
1. Traverse drawing layers from lowest to highest.
2. For each layer, trigger drawing functions with all parameters needed, from lowest to highest (priority value in the queue is something like z-value in CSS). All drawing function should provide a return value that indicates whether it should be popped out of the queue.
3. Remove all finished effect items.
4. Call all blender functions stored for this layer, then paste the layer. Once it's all done, move to the next drawing layer.