Compare commits
24 commits
Author | SHA1 | Date | |
---|---|---|---|
|
1779f750ff | ||
|
cdf2cbd6c0 | ||
b9faf6c22c | |||
|
d1f0ad538e | ||
|
8375917b35 | ||
a61d10bb56 | |||
6abdc90a3a | |||
945adb53c9 | |||
e92dadaf4d | |||
b124afdedf | |||
e37a74137d | |||
5a9eb10507 | |||
ba56c0d911 | |||
68915cb24b | |||
6ae437ef75 | |||
7a3afe1281 | |||
500464fa73 | |||
2a42731628 | |||
b9c7ce3b48 | |||
ddb62cb395 | |||
97697d2d7a | |||
5e6630a92d | |||
f452b40000 | |||
40e4b160df |
43
README.de.md
|
@ -1,28 +1,41 @@
|
||||||
# ParadisSO - eine minimale 2D-Grafikengine
|
# ParadiSO - eine minimale 2D-Grafikengine
|
||||||
|
|
||||||
**ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. *ParadiSO* verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System).
|
**ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. _ParadiSO_ verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System).
|
||||||
|
|
||||||
## Bildungszwecke
|
## Bildungszwecke
|
||||||
|
|
||||||
Einige Argumente für seinen Bildungsaspekt:
|
Einige Argumente für seinen Bildungsaspekt:
|
||||||
|
|
||||||
- Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes
|
- Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes
|
||||||
- Stark von Rust-Code inspiriert
|
- Stark von Rust-Code inspiriert
|
||||||
- Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen.
|
- Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen.
|
||||||
- Versteckt alte `C`-APIs hinter einer modernisierten Fassade
|
- Versteckt alte `C`-APIs hinter einer modernisierten Fassade
|
||||||
- Es lehnt sich stark an die STL und ihre Algorithmen an
|
- Es lehnt sich stark an die STL und ihre Algorithmen an
|
||||||
|
|
||||||
## Minimalistisch
|
## Minimalistisch
|
||||||
|
|
||||||
Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden.
|
Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden.
|
||||||
|
|
||||||
## Abhängigkeiten
|
## Abhängigkeiten
|
||||||
|
|
||||||
ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden:
|
ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden:
|
||||||
|
|
||||||
- [GLFW 3.3.8](https://github.com/glfw/glfw)
|
- [GLFW 3.3.8](https://github.com/glfw/glfw)
|
||||||
- [GLAD](https://github.com/Dav1dde/glad)
|
- [GLAD](https://github.com/Dav1dde/glad)
|
||||||
|
- [STB image](https://github.com/nothings/stb)
|
||||||
|
|
||||||
## Zuarbeiten
|
## Toolchains
|
||||||
|
|
||||||
* [TimePlex](https://code.technotecture.net/Timeplex)
|
ParadiSO kann auf verschiedenen Plattformen gebaut werden
|
||||||
|
|
||||||
|
- Windows (Visual Studio Build Tools 2022)
|
||||||
|
- MacOS (clang 14 or later)
|
||||||
|
- Linux (clang 14 or later, gcc 13.2.1)
|
||||||
|
|
||||||
|
Andere Kombinationen sind möglich aber nicht getestet.
|
||||||
|
|
||||||
|
## Beiträge
|
||||||
|
|
||||||
|
- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build
|
||||||
|
- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
|
||||||
|
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone
|
||||||
|
|
35
README.md
|
@ -1,28 +1,41 @@
|
||||||
# ParadisSO - a minimal 2D graphics engine
|
# ParadiSO - a minimal 2D graphics engine
|
||||||
|
|
||||||
**ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. *ParadiSO* mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS.
|
**ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. _ParadiSO_ mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS.
|
||||||
|
|
||||||
## Educational
|
## Educational
|
||||||
|
|
||||||
Some arguments for its educational side:
|
Some arguments for its educational side:
|
||||||
|
|
||||||
* mix and match of various concepts and paradigms to write expressive but concise code
|
- mix and match of various concepts and paradigms to write expressive but concise code
|
||||||
* heavily inspired by Rust code
|
- heavily inspired by Rust code
|
||||||
* math code is eager evaluation but `constexpr` to compensate overheads
|
- math code is eager evaluation but `constexpr` to compensate overheads
|
||||||
* hides old-style `C` APIs behind a renovated facade
|
- hides old-style `C` APIs behind a renovated facade
|
||||||
* it leans heavily on the STL and its algorithms
|
- it leans heavily on the STL and its algorithms
|
||||||
|
|
||||||
## Minimal
|
## Minimal
|
||||||
|
|
||||||
Because this engine should show some patterns and design concepts it tries to avoid adding unnecessary bloat.
|
Because this engine should show some patterns and design concepts it tries to avoid adding unnecessary bloat.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
ParadiSO comes with batteries included. However, it should be mentioned here:
|
ParadiSO comes with batteries included. However, it should be mentioned here:
|
||||||
|
|
||||||
* [GLFW 3.3.8](https://github.com/glfw/glfw)
|
- [GLFW 3.3.8](https://github.com/glfw/glfw)
|
||||||
* [GLAD](https://github.com/Dav1dde/glad)
|
- [GLAD](https://github.com/Dav1dde/glad)
|
||||||
|
- [STB image](https://github.com/nothings/stb)
|
||||||
|
|
||||||
|
## Toolchains
|
||||||
|
|
||||||
|
ParadiSO is being developed to work on all major desktop systems.
|
||||||
|
|
||||||
|
- Windows (Visual Studio Build Tools 2022)
|
||||||
|
- MacOS (clang 14 or later)
|
||||||
|
- Linux (clang 14 or later, gcc 13.2.1)
|
||||||
|
|
||||||
|
Other combinations might work but are untested.
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
* [TimePlex](https://code.technotecture.net/Timeplex)
|
- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build
|
||||||
|
- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
|
||||||
|
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone
|
||||||
|
|
50
docs/README.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Todo
|
||||||
|
|
||||||
|
Here some ideas for improving this tiny engine:
|
||||||
|
|
||||||
|
## Rendering
|
||||||
|
- [ ] replace the OpenGL renderer with a Vulkan backend
|
||||||
|
- [ ] add animatable sprites (access to UV mapping and tiling)
|
||||||
|
- [ ] add a SDF based renderer (parametric tiles and font rendering)
|
||||||
|
|
||||||
|
## Game Support
|
||||||
|
- [ ] audio!
|
||||||
|
- [ ] some minimal animation system with tweening with different f-curves
|
||||||
|
|
||||||
|
|
||||||
|
## System Level
|
||||||
|
|
||||||
|
- [ ] add a `Asset` handler to load cache and manage assets
|
||||||
|
- [ ] introspection of file system if we load assset
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
- [ ] replace some of the 'unkown source' assets
|
||||||
|
|
||||||
|
## Build / Dev Support
|
||||||
|
- [ ] add a test rig either with Snitch or Catch2
|
||||||
|
- [ ] write some reasonable testcases
|
||||||
|
- [ ] add CPU and GPU benchmarks to address various issues
|
||||||
|
|
||||||
|
|
||||||
|
# Issues
|
||||||
|
|
||||||
|
|
||||||
|
```sh
|
||||||
|
Performance counter stats for 'bin/paradiso_pong':
|
||||||
|
|
||||||
|
555,35 msec task-clock:u # 0,042 CPUs utilized
|
||||||
|
0 context-switches:u # 0,000 /sec
|
||||||
|
0 cpu-migrations:u # 0,000 /sec
|
||||||
|
4.072 page-faults:u # 7,332 K/sec
|
||||||
|
319.484.735 cycles:u # 0,575 GHz
|
||||||
|
358.165.995 instructions:u # 1,12 insn per cycle
|
||||||
|
86.037.942 branches:u # 154,926 M/sec
|
||||||
|
2.469.068 branch-misses:u # 2,87% of all branches
|
||||||
|
|
||||||
|
13,092775373 seconds time elapsed
|
||||||
|
|
||||||
|
0,311565000 seconds user
|
||||||
|
0,247491000 seconds sys
|
||||||
|
```
|
||||||
|
above run with `perf stat bin/paradiso_pong` shows some really bad performance issues.
|
|
@ -1,3 +1,3 @@
|
||||||
add_subdirectory(simple)
|
add_subdirectory(simple)
|
||||||
add_subdirectory(pong)
|
add_subdirectory(pong)
|
||||||
add_subdirectory(flappy_bird)
|
add_subdirectory(quickwings)
|
|
@ -1,11 +0,0 @@
|
||||||
file(GLOB_RECURSE flappy_bird_src "*.cpp")
|
|
||||||
file(GLOB_RECURSE flappy_bird_lib "lib/*.hpp" "lib/*.h")
|
|
||||||
file(GLOB_RECURSE flappy_bird_assets "assets/*")
|
|
||||||
|
|
||||||
add_executable(flappy_bird ${flappy_bird_src} ${flappy_bird_lib})
|
|
||||||
target_link_libraries(flappy_bird paradiso_core)
|
|
||||||
|
|
||||||
add_custom_command(TARGET flappy_bird POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:flappy_bird>/assets)
|
|
||||||
|
|
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 470 B |
|
@ -1,310 +0,0 @@
|
||||||
/**
|
|
||||||
* paradiso - Paradigmen der Softwareentwicklung
|
|
||||||
*
|
|
||||||
* (c) Copyright 2023 Hartmut Seichter
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <paradiso/bitmap.hpp>
|
|
||||||
#include <paradiso/context.hpp>
|
|
||||||
#include <paradiso/geometry.hpp>
|
|
||||||
#include <paradiso/renderer.hpp>
|
|
||||||
#include <paradiso/shader.hpp>
|
|
||||||
#include <paradiso/sprite.hpp>
|
|
||||||
#include <paradiso/vector.hpp>
|
|
||||||
#include <paradiso/window.hpp>
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "lib/image_loader.hpp"
|
|
||||||
|
|
||||||
const int frame_rate = 60;
|
|
||||||
|
|
||||||
struct Background {
|
|
||||||
paradiso::Sprite backgroundLeft;
|
|
||||||
paradiso::Sprite backgroundRight;
|
|
||||||
paradiso::Sprite grassLeft;
|
|
||||||
paradiso::Sprite grassRight;
|
|
||||||
|
|
||||||
paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight};
|
|
||||||
|
|
||||||
Background() {
|
|
||||||
auto backgroundImage =
|
|
||||||
image_loader::load(std::string("background-day.png"));
|
|
||||||
backgroundLeft = paradiso::Sprite{
|
|
||||||
.bitmap = backgroundImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)};
|
|
||||||
backgroundRight = paradiso::Sprite{
|
|
||||||
.bitmap = backgroundImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(2.0f, 0.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)};
|
|
||||||
|
|
||||||
auto grassImage = image_loader::load(std::string("base.png"));
|
|
||||||
grassLeft = paradiso::Sprite{
|
|
||||||
.bitmap = grassImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, -1.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
|
|
||||||
grassRight = paradiso::Sprite{
|
|
||||||
.bitmap = grassImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(2.0f, -1.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(const paradiso::Shader& shader) {
|
|
||||||
for (auto sprite : scrolling) {
|
|
||||||
if (sprite->pivot.x() <= -2.0f) {
|
|
||||||
sprite->pivot.x() += 4.0f;
|
|
||||||
}
|
|
||||||
sprite->pivot.x() -= 0.001f;
|
|
||||||
shader.set_uniform("pivot", sprite->pivot);
|
|
||||||
shader.set_uniform("scale", sprite->scale);
|
|
||||||
shader.set_uniform("rotation", sprite->rotation);
|
|
||||||
renderer.draw(*sprite, shader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
paradiso::Renderer renderer{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Grass {
|
|
||||||
paradiso::Sprite grassLeft;
|
|
||||||
paradiso::Sprite grassRight;
|
|
||||||
|
|
||||||
paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight};
|
|
||||||
|
|
||||||
Grass() {
|
|
||||||
auto grassImage = image_loader::load(std::string("base.png"));
|
|
||||||
grassLeft = paradiso::Sprite{
|
|
||||||
.bitmap = grassImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, -0.9f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
|
|
||||||
grassRight = paradiso::Sprite{
|
|
||||||
.bitmap = grassImage,
|
|
||||||
.pivot = paradiso::Vector2<float>::make(2.0f, -0.9f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(const paradiso::Shader& shader) {
|
|
||||||
for (auto sprite : scrolling) {
|
|
||||||
if (sprite->pivot.x() <= -2.0f) {
|
|
||||||
sprite->pivot.x() += 4.0f;
|
|
||||||
}
|
|
||||||
sprite->pivot.x() -= 0.035f;
|
|
||||||
shader.set_uniform("pivot", sprite->pivot);
|
|
||||||
shader.set_uniform("scale", sprite->scale);
|
|
||||||
shader.set_uniform("rotation", sprite->rotation);
|
|
||||||
renderer.draw(*sprite, shader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
paradiso::Renderer renderer{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FlappyBird {
|
|
||||||
|
|
||||||
paradiso::Renderer renderer1{};
|
|
||||||
paradiso::Renderer renderer2{};
|
|
||||||
paradiso::Renderer renderer3{};
|
|
||||||
|
|
||||||
std::array<paradiso::Sprite, 3> birds;
|
|
||||||
unsigned int flap = 0;
|
|
||||||
unsigned int flapSpeed = 15; // How many ticks per flap
|
|
||||||
unsigned int flapCounter = 0; // How many ticks since last flap
|
|
||||||
|
|
||||||
float velocity = 0.0f;
|
|
||||||
const float max_velocity = 0.05f;
|
|
||||||
|
|
||||||
const float gravity = -0.004f;
|
|
||||||
const float move_up_velocity = 0.0055f;
|
|
||||||
|
|
||||||
bool move_up = false;
|
|
||||||
bool paused = true;
|
|
||||||
|
|
||||||
const float max_pos = 0.95f;
|
|
||||||
const float min_pos = -0.5f;
|
|
||||||
|
|
||||||
float pos = 0.0f;
|
|
||||||
|
|
||||||
float rotation = 0.0f;
|
|
||||||
|
|
||||||
FlappyBird() {
|
|
||||||
float scaleh = 0.07f;
|
|
||||||
float scalew = scaleh * 1.416666666666667f;
|
|
||||||
|
|
||||||
birds = {
|
|
||||||
paradiso::Sprite{
|
|
||||||
.bitmap =
|
|
||||||
image_loader::load(std::string("yellowbird-downflap.png")),
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(scalew, scaleh)},
|
|
||||||
paradiso::Sprite{
|
|
||||||
.bitmap =
|
|
||||||
image_loader::load(std::string("yellowbird-midflap.png")),
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(scalew, scaleh)},
|
|
||||||
paradiso::Sprite{
|
|
||||||
.bitmap =
|
|
||||||
image_loader::load(std::string("yellowbird-upflap.png")),
|
|
||||||
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
|
|
||||||
.scale = paradiso::Vector2<float>::make(scalew, scaleh)}};
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(const paradiso::Shader& shader) {
|
|
||||||
// Update flap state
|
|
||||||
if (flapCounter < flapSpeed) {
|
|
||||||
flapCounter++;
|
|
||||||
} else {
|
|
||||||
flapCounter = 0;
|
|
||||||
flap = (flap + 1) % birds.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto bird = birds[flap];
|
|
||||||
bird.pivot.y() = pos;
|
|
||||||
bird.rotation = rotation;
|
|
||||||
shader.set_uniform("pivot", bird.pivot);
|
|
||||||
shader.set_uniform("scale", bird.scale);
|
|
||||||
shader.set_uniform("rotation", bird.rotation);
|
|
||||||
|
|
||||||
switch (flap) {
|
|
||||||
case 0:
|
|
||||||
renderer1.draw(bird, shader);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
renderer2.draw(bird, shader);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
renderer3.draw(bird, shader);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
// Stop game
|
|
||||||
if (paused)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Apply gravity
|
|
||||||
velocity += gravity;
|
|
||||||
|
|
||||||
if (move_up)
|
|
||||||
velocity += move_up_velocity - gravity;
|
|
||||||
|
|
||||||
// Cap velocity
|
|
||||||
if (velocity > max_velocity)
|
|
||||||
velocity = max_velocity;
|
|
||||||
if (velocity < -max_velocity)
|
|
||||||
velocity = -max_velocity;
|
|
||||||
|
|
||||||
// Cap position
|
|
||||||
pos += velocity;
|
|
||||||
if (pos < min_pos) {
|
|
||||||
pos = min_pos;
|
|
||||||
velocity = 0.0f;
|
|
||||||
}
|
|
||||||
if (pos > max_pos) {
|
|
||||||
pos = max_pos;
|
|
||||||
velocity = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update rotation
|
|
||||||
rotation = velocity * 15.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyboard handler
|
|
||||||
void on_keyboard(const paradiso::Window::KeyboardInputStack& input) {
|
|
||||||
if (input.size()) {
|
|
||||||
paused = false;
|
|
||||||
bool pressed_up = input.top().key == ' ' || input.top().key == 'W';
|
|
||||||
|
|
||||||
if (input.top().action == 1 && pressed_up) {
|
|
||||||
move_up = true;
|
|
||||||
} else if (input.top().action == 0 && pressed_up) {
|
|
||||||
move_up = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto main() -> int {
|
|
||||||
|
|
||||||
// Ausgabefenster ... sieht aus als wäre es auf dem Stack
|
|
||||||
auto window = paradiso::Window();
|
|
||||||
|
|
||||||
auto size = paradiso::Size{.width = 500, .height = 700};
|
|
||||||
|
|
||||||
/*
|
|
||||||
window.set_resizecallback([](auto& w) -> void {
|
|
||||||
w.set_size(paradiso::Size{.width = 405, .height = 720});
|
|
||||||
});
|
|
||||||
|
|
||||||
*/
|
|
||||||
window
|
|
||||||
.set_size(size) // ... Grösse
|
|
||||||
.set_position(paradiso::Point{.x = 100, .y = 100}) // ... Position
|
|
||||||
.set_title("PardiSO.FlappyBird") // ... Titel
|
|
||||||
.set_visible(true); // ... und jetzt anzeigen!
|
|
||||||
|
|
||||||
// der Fenster Kontext
|
|
||||||
auto ctx = paradiso::Context{};
|
|
||||||
|
|
||||||
// ein Shader (Schattierungsprogramm)
|
|
||||||
auto shader = paradiso::Shader{};
|
|
||||||
|
|
||||||
// wir nutzen einen vorgefertigten shader
|
|
||||||
shader.load_preset(paradiso::Shader::Preset::Sprite);
|
|
||||||
|
|
||||||
// ein viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen
|
|
||||||
// Pixeln sollte hier auch eine dementsprechende Grösse eingestellt
|
|
||||||
// werden
|
|
||||||
ctx.set_viewport(paradiso::Rectangle{
|
|
||||||
.position = paradiso::Point{.x = 0, .y = 0}, .size = size});
|
|
||||||
|
|
||||||
// nothing beats a classic look
|
|
||||||
ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00));
|
|
||||||
|
|
||||||
// Load
|
|
||||||
auto background = Background{};
|
|
||||||
auto grass = Grass{};
|
|
||||||
|
|
||||||
auto flappyBird = FlappyBird{};
|
|
||||||
|
|
||||||
// timer
|
|
||||||
|
|
||||||
// das update führt den hier mitgegebnen Ausdruck innerhalb der internen
|
|
||||||
// Updates des Fensters auf. Es wird hier auch explizit ein bool gefordert
|
|
||||||
// damit das update auch zu jederzeit unterbrochen werden kann
|
|
||||||
while (window.update([&](paradiso::Window& w) -> bool {
|
|
||||||
ctx.set_viewport(paradiso::Rectangle{
|
|
||||||
.position = paradiso::Point{.x = 0, .y = 0}, .size = size});
|
|
||||||
|
|
||||||
ctx.clear();
|
|
||||||
auto t1 = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
// Keyboard and state change
|
|
||||||
flappyBird.on_keyboard(w.keyboard_input());
|
|
||||||
flappyBird.update();
|
|
||||||
|
|
||||||
// Draw
|
|
||||||
background.draw(shader);
|
|
||||||
grass.draw(shader);
|
|
||||||
flappyBird.draw(shader);
|
|
||||||
|
|
||||||
// wait for frame rate
|
|
||||||
auto t2 = std::chrono::high_resolution_clock::now();
|
|
||||||
auto duration =
|
|
||||||
std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
|
|
||||||
auto wait = std::chrono::microseconds(1000000 / frame_rate) - duration;
|
|
||||||
std::this_thread::sleep_for(wait);
|
|
||||||
|
|
||||||
// Quit
|
|
||||||
return !(w.keyboard_input().size() &&
|
|
||||||
w.keyboard_input().top().key == 'Q');
|
|
||||||
})) {
|
|
||||||
};
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
#include <paradiso/rgba.hpp>
|
|
||||||
#include <paradiso/sprite.hpp>
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <optional>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
// STB image loading
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "lib/stb_image.h"
|
|
||||||
|
|
||||||
#include "lib/image_loader.hpp"
|
|
||||||
|
|
||||||
std::unordered_map<std::string, paradiso::Bitmap> image_loader::image_cache =
|
|
||||||
std::unordered_map<std::string, paradiso::Bitmap>();
|
|
||||||
|
|
||||||
paradiso::Bitmap image_loader::load(const std::string& filename) {
|
|
||||||
if (image_cache.find(filename) == image_cache.end()) {
|
|
||||||
std::string path = ASSET_PATH + filename;
|
|
||||||
std::cout << "Loading " << path << std::endl;
|
|
||||||
auto data = readBMP(path);
|
|
||||||
image_cache[filename] = data;
|
|
||||||
}
|
|
||||||
return image_cache[filename];
|
|
||||||
}
|
|
||||||
|
|
||||||
paradiso::Bitmap image_loader::readBMP(std::string& filename) {
|
|
||||||
// Load with stb_image
|
|
||||||
stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL
|
|
||||||
int width, height, channels;
|
|
||||||
unsigned char* image =
|
|
||||||
stbi_load(filename.c_str(), &width, &height, &channels, 4);
|
|
||||||
int size = width * height;
|
|
||||||
|
|
||||||
if (!image)
|
|
||||||
throw std::runtime_error("Error loading image");
|
|
||||||
|
|
||||||
// Convert to Vector of RGBA
|
|
||||||
std::vector<paradiso::RGBA> rgba = std::vector<paradiso::RGBA>(size);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
// get rgba values
|
|
||||||
int pos = i * 4;
|
|
||||||
int r = image[pos + 0];
|
|
||||||
int g = image[pos + 1];
|
|
||||||
int b = image[pos + 2];
|
|
||||||
int a = image[pos + 3];
|
|
||||||
|
|
||||||
// bug in from_rgba. it expects bgra, not rgba
|
|
||||||
auto val = paradiso::RGBA::from_rgba(b, g, r, a);
|
|
||||||
rgba[i] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate image by 90 degrees CW
|
|
||||||
std::vector<paradiso::RGBA> rotated = std::vector<paradiso::RGBA>(size);
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
|
|
||||||
int pos = y * width + x;
|
|
||||||
int pos_rotated = x * height + (height - y - 1);
|
|
||||||
rotated[pos_rotated] = rgba[pos];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// free image
|
|
||||||
stbi_image_free(image);
|
|
||||||
|
|
||||||
return paradiso::Bitmap::from_data(
|
|
||||||
paradiso::Size{static_cast<unsigned int>(height),
|
|
||||||
static_cast<unsigned int>(width)},
|
|
||||||
rotated);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <paradiso/bitmap.hpp>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
class image_loader {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief loads an Image from a file
|
|
||||||
* @param[in] filename path to file
|
|
||||||
* @return bitmap from file
|
|
||||||
*/
|
|
||||||
static paradiso::Bitmap load(const std::string& filename);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline const std::string ASSET_PATH = "assets/";
|
|
||||||
|
|
||||||
static std::unordered_map<std::string, paradiso::Bitmap> image_cache;
|
|
||||||
|
|
||||||
static paradiso::Bitmap readBMP(std::string& filename);
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* paradiso - Paradigmen der Softwareentwicklung
|
* paradiso - Paradigmen der Softwareentwicklung
|
||||||
*
|
*
|
||||||
* (c) Copyright 2023 Hartmut Seichter
|
* (c) Copyright 2023-2024 Hartmut Seichter
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
struct PongStage {
|
struct PongStage {
|
||||||
|
@ -86,7 +85,7 @@ struct PongPaddle {
|
||||||
velocity_horizontal *= whoopiness;
|
velocity_horizontal *= whoopiness;
|
||||||
sprite.pivot.x() += velocity_horizontal;
|
sprite.pivot.x() += velocity_horizontal;
|
||||||
|
|
||||||
std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
|
sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
|
||||||
|
|
||||||
// update shader uniforms
|
// update shader uniforms
|
||||||
shader.set_uniform("pivot", sprite.pivot);
|
shader.set_uniform("pivot", sprite.pivot);
|
||||||
|
@ -151,7 +150,7 @@ struct PongBall {
|
||||||
|
|
||||||
void draw(const paradiso::Shader& shader) {
|
void draw(const paradiso::Shader& shader) {
|
||||||
|
|
||||||
std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
|
sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
|
||||||
|
|
||||||
// update shader uniforms
|
// update shader uniforms
|
||||||
shader.set_uniform("pivot", sprite.pivot);
|
shader.set_uniform("pivot", sprite.pivot);
|
||||||
|
@ -166,6 +165,9 @@ struct PongBall {
|
||||||
paradiso::Renderer renderer{};
|
paradiso::Renderer renderer{};
|
||||||
|
|
||||||
constexpr void push(const auto& impulse) noexcept { velocity += impulse; }
|
constexpr void push(const auto& impulse) noexcept { velocity += impulse; }
|
||||||
|
|
||||||
|
constexpr void whoop(const auto& whoopiness) noexcept { velocity *= whoopiness; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
|
@ -234,6 +236,19 @@ auto main() -> int {
|
||||||
ball.sprite.pivot.x() = 0.0f;
|
ball.sprite.pivot.x() = 0.0f;
|
||||||
ball.sprite.pivot.y() = 0.9f;
|
ball.sprite.pivot.y() = 0.9f;
|
||||||
}
|
}
|
||||||
|
// speed adjust
|
||||||
|
if (w.keyboard_input().top().key == 'N') {
|
||||||
|
|
||||||
|
std::cout << "Speed Up!\n";
|
||||||
|
|
||||||
|
ball.push(paradiso::Vector2<float>::make(0.f,0.01f));
|
||||||
|
|
||||||
|
} else if (w.keyboard_input().top().key == 'M') {
|
||||||
|
|
||||||
|
ball.push(paradiso::Vector2<float>::make(0.f,-0.01f));
|
||||||
|
|
||||||
|
std::cout << "Speed Lower!\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ball.interact(stage);
|
ball.interact(stage);
|
||||||
|
@ -251,4 +266,4 @@ auto main() -> int {
|
||||||
};
|
};
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
20
examples/quickwings/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
set(quickwings_srcs quickwings.cpp)
|
||||||
|
set(quickwings_assets
|
||||||
|
assets/background-day.png
|
||||||
|
assets/base.png
|
||||||
|
assets/pipe-green.png
|
||||||
|
assets/yellowbird-downflap.png
|
||||||
|
assets/yellowbird-midflap.png
|
||||||
|
assets/yellowbird-upflap.png
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${quickwings_assets} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
|
add_executable(quickwings ${quickwings_srcs} ${quickwings_assets})
|
||||||
|
|
||||||
|
target_link_libraries(quickwings paradiso_core)
|
||||||
|
|
||||||
|
add_custom_command(TARGET quickwings POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:quickwings>/assets)
|
||||||
|
|
BIN
examples/quickwings/assets/background-day.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
examples/quickwings/assets/base.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
examples/quickwings/assets/gameover.png
Normal file
After Width: | Height: | Size: 758 B |
BIN
examples/quickwings/assets/message.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
BIN
examples/quickwings/assets/tappybird/Font/kenvector_future.ttf
Normal file
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterA.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterB.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterC.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterD.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterE.png
Normal file
After Width: | Height: | Size: 747 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterF.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterG.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterH.png
Normal file
After Width: | Height: | Size: 795 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterI.png
Normal file
After Width: | Height: | Size: 448 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterK.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterL.png
Normal file
After Width: | Height: | Size: 580 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterM.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterN.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterO.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterP.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterR.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterS.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterT.png
Normal file
After Width: | Height: | Size: 696 B |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterU.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterV.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterW.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterX.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterY.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number0.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number1.png
Normal file
After Width: | Height: | Size: 948 B |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number2.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number3.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number5.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number6.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number7.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number8.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Numbers/number9.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/UIbg.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png
Normal file
After Width: | Height: | Size: 826 B |
BIN
examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png
Normal file
After Width: | Height: | Size: 832 B |
BIN
examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/medalGold.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/tap.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/tapRight.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/tapTick.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/background.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/groundDirt.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/groundGrass.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/groundIce.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/groundRock.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/groundSnow.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/puffLarge.png
Normal file
After Width: | Height: | Size: 448 B |
BIN
examples/quickwings/assets/tappybird/PNG/puffSmall.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
examples/quickwings/assets/tappybird/PNG/rock.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockDown.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockGrass.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockGrassDown.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockIce.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockIceDown.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockSnow.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/rockSnowDown.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/starBronze.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/starGold.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
examples/quickwings/assets/tappybird/PNG/starSilver.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
examples/quickwings/assets/tappybird/Spritesheet/planes.png
Normal file
After Width: | Height: | Size: 35 KiB |
14
examples/quickwings/assets/tappybird/Spritesheet/planes.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<TextureAtlas imagePath="sheet.png">
|
||||||
|
<SubTexture name="planeBlue1.png" x="0" y="73" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeBlue2.png" x="0" y="0" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeBlue3.png" x="0" y="365" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeGreen1.png" x="88" y="219" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeGreen2.png" x="88" y="146" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeGreen3.png" x="88" y="73" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeRed1.png" x="88" y="0" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeRed2.png" x="0" y="438" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeRed3.png" x="88" y="292" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeYellow1.png" x="0" y="292" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeYellow2.png" x="0" y="219" width="88" height="73"/>
|
||||||
|
<SubTexture name="planeYellow3.png" x="0" y="146" width="88" height="73"/>
|
||||||
|
</TextureAtlas>
|