doc
This commit is contained in:
parent
e457021953
commit
31664bb47b
|
@ -0,0 +1,158 @@
|
|||
|
||||
## A high-level object-oriented Gameboy Advance sprite engine library
|
||||
|
||||
That's a mouthful - let's break that down:
|
||||
|
||||
#### High-level object-oriented
|
||||
|
||||
The GBA is an older piece of hardware that's missing an OS. While that is great (`while(1) {}`), it also means there's little software library support. GBA programming boils down to manipulating **memory-mapped IO** pointers. And that's not a lot of fun.
|
||||
|
||||
Instead of writing
|
||||
|
||||
```C
|
||||
vu16* paddle = ((volatile tile_block *)0x06000000)[0][1];
|
||||
for(int i = 0; i < 4 * sizeof(tile_4bpp) / 2; i++) {
|
||||
paddle[i] = 0x2222;
|
||||
}
|
||||
```
|
||||
|
||||
Wouldn't it be a bit more readable if one could write
|
||||
|
||||
```C
|
||||
auto paddle = SpriteBuilder<Sprite>()
|
||||
.withData(paddleTile, sizeof(paddleTile))
|
||||
.withLocation(10, 10)
|
||||
.buildPtr();
|
||||
```
|
||||
|
||||
To leverage C++11's abilities combined with a clear object-oriented approach using abstraction to hide the hexadecimal addresses? That's the objective of this engine.
|
||||
|
||||
**Speed is NOT my primary concern**! I'm not a C(++) expert and I value clean readable code above speedy algorithms. This is just a concept. That said, feel free to fork or provide patches for sloppy work (that will be present). Thank you!
|
||||
|
||||
#### GBA sprite engine
|
||||
|
||||
That means `MODE0`.
|
||||
|
||||
#### library
|
||||
|
||||
It's compiled as a static library for your convenience. Simply link with the library and include the header path and you're all set. Take a look at the demo's `CMake` files if you're interested.
|
||||
|
||||
## Engine features
|
||||
|
||||
A portion of [ToncLib](https://www.coranac.com/man/tonclib/main.htm) has been used as a low-level GBA accessor. If you know what you're doing, you can safely use those, headers are in `<libgba-sprite-engine/gba>`.
|
||||
|
||||
BIOS methods and Sin/Cos lookup tables are also compiled.
|
||||
|
||||
### Implementing your own GBA Game
|
||||
|
||||
#### Scenes
|
||||
|
||||
Scenes contain sprites and backgrounds. You can transition between scenes with `engine->setScene(scene)` or `engine->transitionToScene(scene, effect)`. The main program bootstraps your first scene - from there on it's each scene's responsibility to load another one.
|
||||
|
||||
This is the layout of a main function:
|
||||
|
||||
```C
|
||||
int main() {
|
||||
std::shared_ptr<GBAEngine> engine(new GBAEngine());
|
||||
|
||||
auto startScene = new SampleStartScene(engine);
|
||||
engine->setScene(startScene);
|
||||
|
||||
while (true) {
|
||||
engine->update();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
||||
To create your own scene, subclass `Scene` and implement:
|
||||
|
||||
1. `std::vector<Sprite *> sprites()`: the sprites to load into VRAM
|
||||
2. `std::vector<Background *> backgrounds()`: your (multilayered) backgrounds
|
||||
3. `void load()`: one-time scene loading (create your objects here)
|
||||
4. `void tick(u16 keys)`: gets called each engine `update()`
|
||||
5. set `foregroundPalette` and `backgroundPalette` in your load.
|
||||
|
||||
Loading up a scene usually involves creating some sprites with the builder. Don't forget to set the palettes like this: `std::unique_ptr<ForegroundPaletteManager>(new ForegroundPaletteManager(sharedPal, sizeof(sharedPal)));`
|
||||
|
||||
The `sprites()` method gets periodically called to check whether something has been added or deleted and updates the VRAM and OAM accordingly. **You don't need to manage anything yourself!** Take a look at demo 3.
|
||||
|
||||
A simple fade out scene effect is implemented in demo 1, that converges the palette colors of both palettes to white. It's easy to **create your own effects** by subclassing `SceneEffect`.
|
||||
|
||||
#### Backgrounds
|
||||
|
||||
Scrollable backgrounds are present:
|
||||
|
||||
Call `scroll()` in your scene update.
|
||||
|
||||
Creating a background:
|
||||
|
||||
```C
|
||||
bg = std::unique_ptr<Background>(new Background(1, background_data, sizeof(background_data), map, sizeof(map)));
|
||||
bg->useMapScreenBlock(16);
|
||||
```
|
||||
|
||||
Backgrounds work a bit different in VRAM compared to sprites. There are only 4 backgrounds available, and background #4 is taken by the font. Parameter 1 identifies your background used for prioritizing. Remember to use a screen block different than your map data.
|
||||
|
||||
#### Sprites
|
||||
|
||||
Conjuring sprites on the screen is a matter of exposing them to the sprites vector in your scene. Create them in your load and set them as a `std::unique_ptr` member variable in your scene so they get cleaned up automatically.
|
||||
|
||||
Creating sprites is easy with the `SpriteBuilder`. Specify what kind of sprite you want to make as a template argument (`<Sprite>` or `<AffineSprite>`) and speficy your data `.with...()`. Done? Call `build()` to get a copy or `buildPtr()` to get a copy wrapped in a unique pointer.
|
||||
|
||||
**Affine sprites can transform** using for example `rotate(angle)` - check out demo 1 or 3 for that.
|
||||
|
||||
**Sprite animation is built-in**! Just feed your sprite data to the builder and use `.withAnimated(amountOfFrames, frameDelay)`. Remember to position each frame in one column in the image itself (vertically).
|
||||
|
||||
Useful sprite methods:
|
||||
|
||||
* `animate()`, `animateToFrame(x)` or `stopAnimating()`
|
||||
* `flipVertically(bool)` or `flipHorizontally(bool)`
|
||||
* `setVelocity(dx, dy)` (auto-updates) or `moveTo(x, y)`
|
||||
* `setWithinBounds(bool)` automatically keeps your sprite within the GBA resolution bounds
|
||||
* `collidesWith(otherSprite)` or `isOffScreen()`
|
||||
* Various getters like `getWith()` etc
|
||||
|
||||
#### Sound
|
||||
|
||||
The engine supports **sounds** and **background music** using GBA's Active Sound channel A and B. It's a simple implementation meaning no mixing in either channels (but A and B are mixed).
|
||||
|
||||
Call `engine->enqueueMusic(data, sizeof(data));` as a repeating music or `enqueueSound()` as a one-timer. If some sound is already playing, it will **not be played**. Background music auto-repeats when done. See demo 1.
|
||||
|
||||
#### Text
|
||||
|
||||
![default font](https://github.com/wgroeneveld/gba-sprite-engine/blob/master/engine/src/background/text.png?raw=true)
|
||||
|
||||
There's a **default font embedded into the engine** using the `TextStream::instance()` static instance. It takes up background #4 and claims the last background palette bank so watch out with that!
|
||||
|
||||
Useful text manipulation:
|
||||
|
||||
* `setText(txt, row, col)`
|
||||
* `<< text` or `<< int` etc: append to text stream for debugging purposes.
|
||||
* `setTextColor(COLOR)`: changes default color palette (white).
|
||||
|
||||
#### Error logging
|
||||
|
||||
The text stream is also used if something goes wrong, there's a macro `failure_gba(WHOOPS)` that prints file, line, method and "exception" message to the text stream background.
|
||||
|
||||
### Unit Testing GBA games
|
||||
|
||||
The engine comes with (some) [Google Test](https://github.com/google/googletest) test cases to show you how separate classes can effectively be unit tested. I had to stub out some ARM-specific ToncLib includes, that's why the `add_definitions(-DCODE_COMPILED_AS_PART_OF_TEST)` CMake statement is there. Gtest compiles library source with `g++` and **not with the cross-compiler**!
|
||||
|
||||
### Compiling everything
|
||||
|
||||
The project has been developed with CLion. The `.idea` dir is there for you to get started.
|
||||
|
||||
As such, `CMake` was an easy choice. Use the following commands to build everything, including the demos:
|
||||
|
||||
1. `mkdir cmake-build-debug && cd cmake-build-debug`
|
||||
2. `cmake ./../`
|
||||
|
||||
Things you might need to change in `CMakeLists.txt` files:
|
||||
|
||||
1. I'm assuming your GBA cross compiler is in your `$PATH`. If it's not, add an absolute path to `SET(CMAKE_C_COMPILER arm-none-eabi-gcc)` etc.
|
||||
2. The Google Test Library should be compiled from source in some directory. I have mine hardcoded: `SET(GTEST_LIBRARY "/Users/jefklak/CLionProjects/googletest-release-1.8.0/googletest")` so adjust accordinly or exclude the test subproject.
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
After Width: | Height: | Size: 283 KiB |
Binary file not shown.
After Width: | Height: | Size: 384 KiB |
Loading…
Reference in New Issue