Compare commits

...

10 commits

7 changed files with 336 additions and 112 deletions

View file

@ -1,40 +1,41 @@
# ParadiSO - 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<EFBFBD>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<EFBFBD>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. - 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<EFBFBD>tigen Ballast zu vermeiden. Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden.
## Abh<EFBFBD>ngigkeiten ## Abhängigkeiten
ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erw<EFBFBD>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) - [STB image](https://github.com/nothings/stb)
## Toolchains ## Toolchains
ParadiSO kann auf verschiedenen Plattformen gebaut werden ParadiSO kann auf verschiedenen Plattformen gebaut werden
- Windows (Visual Studio Build Tools 2022) - Windows (Visual Studio Build Tools 2022)
- MacOS (clang 14 or later) - MacOS (clang 14 or later)
- Linux (clang 14 or later, gcc 13.2.1) - Linux (clang 14 or later, gcc 13.2.1)
Andere Kombinationen sind möglich aber nicht getestet. Andere Kombinationen sind möglich aber nicht getestet.
## Beitr<EFBFBD>ge ## Beiträge
* [Tim G<>tzelmann](https://code.technotecture.net/Timeplex) Windows Build - [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build
* [Robin Rottst<73>dt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader - [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone

View file

@ -1,41 +1,41 @@
# ParadiSO - 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) - [STB image](https://github.com/nothings/stb)
## Toolchains ## Toolchains
ParadiSO is being developed to work on all major desktop systems. ParadiSO is being developed to work on all major desktop systems.
- Windows (Visual Studio Build Tools 2022) - Windows (Visual Studio Build Tools 2022)
- MacOS (clang 14 or later) - MacOS (clang 14 or later)
- Linux (clang 14 or later, gcc 13.2.1) - Linux (clang 14 or later, gcc 13.2.1)
Other combinations might work but are untested. Other combinations might work but are untested.
## Contributors ## Contributors
* [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build - [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build
* [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader - [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,10 +1,14 @@
/** /**
* paradiso - Paradigmen der Softwareentwicklung * paradiso - Paradigmen der Softwareentwicklung
* *
* (c) Copyright 2023 Hartmut Seichter, Robin Rottstädt * (c) Copyright 2023 Hartmut Seichter, Robin Rottstädt, brxxh (Hannes Brothuhn)
* *
*/ */
#include <bits/iterator_concepts.h>
#include <cstdio>
#include <cstdlib>
#include <ostream>
#include <paradiso/bitmap.hpp> #include <paradiso/bitmap.hpp>
#include <paradiso/bitmap_io.hpp> #include <paradiso/bitmap_io.hpp>
#include <paradiso/context.hpp> #include <paradiso/context.hpp>
@ -20,10 +24,19 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
#include <cstdlib>
#include <ctime>
// #include "lib/image_loader.hpp" // #include "lib/image_loader.hpp"
const int frame_rate = 60; const int frame_rate = 60;
bool game_over = false;
float risky_pos_x;
float risky_pos_max_x;
float risky_pos_bottom_y;
float risky_pos_top_y;
float risky_pos_bottom_max_y;
float risky_pos_top_max_y;
struct Background { struct Background {
paradiso::Sprite backgroundLeft; paradiso::Sprite backgroundLeft;
@ -33,81 +46,179 @@ struct Background {
paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight}; paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight};
paradiso::Renderer renderer{};
Background() { Background() {
auto backgroundImage = auto backgroundImage =
paradiso::BitmapIO::get().load("background-day.png"); paradiso::BitmapIO::get().load("background-day.png");
backgroundLeft = paradiso::Sprite{ backgroundLeft = paradiso::Sprite{
.bitmap = backgroundImage, .bitmap = backgroundImage,
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f), .pivot = {paradiso::Vector2<float>::make(0.0f, 0.16f)},
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)}; .scale = {paradiso::Vector2<float>::make(1.01f, 1.3f)}};
backgroundRight = paradiso::Sprite{ backgroundRight = paradiso::Sprite{
.bitmap = backgroundImage, .bitmap = backgroundImage,
.pivot = paradiso::Vector2<float>::make(2.0f, 0.0f), .pivot = {paradiso::Vector2<float>::make(2.018f, 0.16f)},
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)}; .scale = {paradiso::Vector2<float>::make(1.01f, 1.3f)}};
auto grassImage = paradiso::BitmapIO::get().load("base.png"); auto grassImage = paradiso::BitmapIO::get().load("base.png");
grassLeft = paradiso::Sprite{ grassLeft = paradiso::Sprite{
.bitmap = grassImage, .bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(0.0f, -1.0f), .pivot = {paradiso::Vector2<float>::make(0.0f, -1.0f)},
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)}; .scale = {paradiso::Vector2<float>::make(1.0f, 0.33333f)}};
grassRight = paradiso::Sprite{ grassRight = paradiso::Sprite{
.bitmap = grassImage, .bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(2.0f, -1.0f), .pivot = {paradiso::Vector2<float>::make(2.0f, -1.0f)},
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)}; .scale = {paradiso::Vector2<float>::make(1.0f, 0.33333f)}};
} }
void draw(const paradiso::Shader& shader) { void draw(const paradiso::Shader& shader) {
for (auto sprite : scrolling) { for (auto sprite : scrolling) {
if (sprite->pivot.x() <= -2.0f) { if (game_over == false) {
sprite->pivot.x() += 4.0f; if (sprite->pivot.x() <= -2.0f) {
sprite->pivot.x() += 4.0f;
}
sprite->pivot.x() -= 0.002f;
} }
sprite->pivot.x() -= 0.001f;
shader.set_uniform("pivot", sprite->pivot); shader.set_uniform("pivot", sprite->pivot);
shader.set_uniform("scale", sprite->scale); shader.set_uniform("scale", sprite->scale);
shader.set_uniform("rotation", sprite->rotation); shader.set_uniform("rotation", sprite->rotation);
renderer.draw(*sprite, shader); renderer.draw(*sprite, shader);
} }
} }
};
paradiso::Renderer renderer{}; struct Pipe {
paradiso::Sprite pipe_top;
paradiso::Sprite pipe_bottom;
paradiso::Renderer renderer1{};
paradiso::Renderer renderer2{};
bool paused = false;
int pipe_spawn_rand_int = rand() % 80 + 15;
float pipe_spawn_rand = float(pipe_spawn_rand_int) / 100;
bool pos_reset = false;
Pipe() {
auto pipe_image = paradiso::BitmapIO::get().load("pipe-green.png");
pipe_top = paradiso::Sprite{
.bitmap = pipe_image,
.pivot = {paradiso::Vector2<float>::make(1.4f, pipe_spawn_rand + 1.0f)},
.scale = {paradiso::Vector2<float>::make(((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)},
.rotation = 3.1415926f};
pipe_bottom = paradiso::Sprite{
.bitmap = pipe_image,
.pivot = {paradiso::Vector2<float>::make(1.4f, pipe_spawn_rand - 1.5f)},
.scale = {paradiso::Vector2<float>::make(((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)}};
paused = true;
}
void update() {
if (game_over == true) {
paused = true;
}
if (paused == true) {
return;
}
else {
pipe_spawn_rand_int = rand() % 80 + 15;
pipe_spawn_rand = float(pipe_spawn_rand_int) / 100;
pipe_top.pivot.x() -= 0.02f;
pipe_bottom.pivot.x() -= 0.02f;
risky_pos_x = pipe_top.pivot.x();
risky_pos_max_x = pipe_top.pivot.x() + ((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f;
risky_pos_top_y = pipe_top.pivot.y();
risky_pos_top_max_y = pipe_top.pivot.y() + 10.0f;
risky_pos_bottom_y = pipe_bottom.pivot.y();
risky_pos_bottom_max_y = pipe_bottom.pivot.y() - 10.0f;
if (pipe_top.pivot.x() <= -1.4f || pipe_bottom.pivot.x() <= -1.4f) {
pos_reset = true;
if (pos_reset == true) {
pipe_top.pivot.y() = pipe_spawn_rand + 1.0f;
pipe_bottom.pivot.y() = pipe_spawn_rand - 1.5;
pos_reset = false;
}
pipe_top.pivot.x() = 1.4f;
pipe_bottom.pivot.x() = 1.4f;
}
}
}
void draw(const paradiso::Shader& shader) {
shader.set_uniform("pivot", pipe_bottom.pivot);
shader.set_uniform("scale", pipe_bottom.scale);
renderer1.draw(pipe_bottom, shader);
shader.set_uniform("pivot", pipe_top.pivot);
shader.set_uniform("scale", pipe_top.scale);
shader.set_uniform("rotation", pipe_top.rotation);
renderer1.draw(pipe_top, shader);
}
}; };
struct Grass { struct Grass {
paradiso::Sprite grassLeft; paradiso::Sprite grassLeft;
paradiso::Sprite grassRight; paradiso::Sprite grassRight;
paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight}; paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight};
paradiso::Renderer renderer1{};
paradiso::Renderer renderer2{};
Grass() { Grass() {
auto grassImage = paradiso::BitmapIO::get().load(std::string("base.png")); auto grassImage = paradiso::BitmapIO::get().load("base.png");
grassLeft = paradiso::Sprite{ grassLeft = paradiso::Sprite{
.bitmap = grassImage, .bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(0.0f, -0.9f), .pivot = {paradiso::Vector2<float>::make(0.0f, -0.9f)},
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)}; .scale = {paradiso::Vector2<float>::make(((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}};
grassRight = paradiso::Sprite{ grassRight = paradiso::Sprite{
.bitmap = grassImage, .bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(2.0f, -0.9f), .pivot = {paradiso::Vector2<float>::make(1.002f, -0.9f)},
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)}; .scale = {paradiso::Vector2<float>::make(((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}};
} }
void draw(const paradiso::Shader& shader) { void draw(const paradiso::Shader& shader) {
for (auto sprite : scrolling) { if (game_over == false) {
if (sprite->pivot.x() <= -2.0f) { grassLeft.pivot.x() -= 0.02f;
sprite->pivot.x() += 4.0f; grassRight.pivot.x() -= 0.02f;
}
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{}; if (grassRight.pivot.x() <= 0.0f) {
grassLeft.pivot.x() = 1.002f;
}
if (grassRight.pivot.x() <= -1.002f) {
grassRight.pivot.x() = 1.002f;
}
}
shader.set_uniform("pivot", grassLeft.pivot);
shader.set_uniform("scale", grassLeft.scale);
shader.set_uniform("rotation", grassLeft.rotation);
shader.set_uniform("pivot", grassRight.pivot);
shader.set_uniform("scale", grassRight.scale);
shader.set_uniform("rotation", grassRight.rotation);
renderer1.draw(grassLeft, shader);
renderer2.draw(grassRight, shader);
}
}; };
struct QuickWings {
struct QuickWings {
paradiso::Renderer renderer1{}; paradiso::Renderer renderer1{};
paradiso::Renderer renderer2{}; paradiso::Renderer renderer2{};
paradiso::Renderer renderer3{}; paradiso::Renderer renderer3{};
@ -118,10 +229,10 @@ struct QuickWings {
unsigned int flapCounter = 0; // How many ticks since last flap unsigned int flapCounter = 0; // How many ticks since last flap
float velocity = 0.0f; float velocity = 0.0f;
const float max_velocity = 0.05f; const float max_velocity = 0.02f;
const float gravity = -0.004f; const float gravity = -0.002f;
const float move_up_velocity = 0.0055f; const float move_up_velocity = 0.02f;
bool move_up = false; bool move_up = false;
bool paused = true; bool paused = true;
@ -129,30 +240,32 @@ struct QuickWings {
const float max_pos = 0.95f; const float max_pos = 0.95f;
const float min_pos = -0.5f; const float min_pos = -0.5f;
float pos = 0.0f; float pos = 0.34f;
float rotation = 0.0f; float rotation = 0.0f;
int collision_counter = 0;
QuickWings() { QuickWings() {
float scaleh = 0.07f; float scaleh = 0.08f;
float scalew = scaleh * 1.416666666666667f; float scalew = 0.158f;
birds = { birds = {
paradiso::Sprite{ paradiso::Sprite{
.bitmap = .bitmap =
paradiso::BitmapIO::get().load("yellowbird-downflap.png"), paradiso::BitmapIO::get().load("yellowbird-downflap.png"),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f), .pivot = {paradiso::Vector2<float>::make(0.0f, 0.0f)},
.scale = paradiso::Vector2<float>::make(scalew, scaleh)}, .scale = {paradiso::Vector2<float>::make(scalew, scaleh)}},
paradiso::Sprite{ paradiso::Sprite{
.bitmap = .bitmap =
paradiso::BitmapIO::get().load("yellowbird-midflap.png"), paradiso::BitmapIO::get().load("yellowbird-midflap.png"),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f), .pivot = {paradiso::Vector2<float>::make(0.0f, 0.0f)},
.scale = paradiso::Vector2<float>::make(scalew, scaleh)}, .scale = {paradiso::Vector2<float>::make(scalew, scaleh)}},
paradiso::Sprite{ paradiso::Sprite{
.bitmap = .bitmap =
paradiso::BitmapIO::get().load("yellowbird-upflap.png"), paradiso::BitmapIO::get().load("yellowbird-upflap.png"),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f), .pivot = {paradiso::Vector2<float>::make(0.0f, 0.0f)},
.scale = paradiso::Vector2<float>::make(scalew, scaleh)}}; .scale = {paradiso::Vector2<float>::make(scalew, scaleh)}}};
} }
void draw(const paradiso::Shader& shader) { void draw(const paradiso::Shader& shader) {
@ -185,53 +298,144 @@ struct QuickWings {
} }
void update() { void update() {
if (game_over == true) {
paused = true;
}
// Stop game // Stop game
if (paused) if (paused) {
return; 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) { else {
pos = max_pos; // Apply gravity
velocity = 0.0f; 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;
game_over = true;
}
if (pos > max_pos) {
pos = max_pos;
velocity = 0.0f;
game_over = true;
}
// Update rotation
rotation = velocity * 10.0f;
} }
// Update rotation float final_risky_pos_top_y = risky_pos_top_y - 1.06f;
rotation = velocity * 15.0f; float final_risky_pos_bottom_y = risky_pos_bottom_y + 1.06f;
if (risky_pos_x - 0.3f <= 0.0f && risky_pos_max_x >= 0.0f) {
if (pos >= final_risky_pos_top_y && pos <= risky_pos_top_max_y) {
game_over = true;
}
if (pos <= final_risky_pos_bottom_y && pos >= risky_pos_bottom_max_y) {
if (collision_counter == 0) {
collision_counter++;
}
else {
collision_counter = 2;
}
if (collision_counter == 2) {
game_over = true;
}
}
}
} }
// keyboard handler // keyboard handler
void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { void on_keyboard(const paradiso::Window::KeyboardInputStack& input) {
if (input.size()) { if (input.size()) {
paused = false; paused = false;
bool pressed_up = input.top().key == ' ' || input.top().key == 'W';
if (input.top().action == 1 && pressed_up) { if (paused == false) {
move_up = true; bool pressed_up = input.top().key == ' ' || input.top().key == 'W';
} else if (input.top().action == 0 && pressed_up) {
move_up = false; if (input.top().action == 1 && pressed_up) {
move_up = true;
} else if (input.top().action == 0 && pressed_up) {
move_up = false;
}
}
else {
return;
} }
} }
} }
}; };
struct Message {
paradiso::Sprite messageSprite;
paradiso::Renderer renderer{};
bool start = false;
float pos = 100.0f;
Message() {
auto messageImage = paradiso::BitmapIO::get().load("message.png");
messageSprite = paradiso::Sprite{
.bitmap = messageImage,
.pivot = {paradiso::Vector2<float>::make(0.0f, 0.0f)},
.scale = {paradiso::Vector2<float>::make(0.8f, 0.8f)}
};
};
void draw(const paradiso::Shader& shader) {
shader.set_uniform("pivot", messageSprite.pivot);
shader.set_uniform("scale", messageSprite.scale);
renderer.draw(messageSprite, shader);
}
void update() {
if (start == true) {
messageSprite.pivot.y() = pos;
}
}
void on_keyboard(const paradiso::Window::KeyboardInputStack& input) {
if (input.size()) {
start = true;
}
}
};
struct GameOverMessage {
paradiso::Sprite messageSprite;
paradiso::Renderer renderer{};
GameOverMessage() {
auto messageImage = paradiso::BitmapIO::get().load("gameover.png");
messageSprite = paradiso::Sprite{
.bitmap = messageImage,
.pivot = {paradiso::Vector2<float>::make(0.0f, 0.4f)},
.scale = {paradiso::Vector2<float>::make(((500.0f - (500.0f - 192.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 42.0f)) / 700.0f) * 2.25f)}
};
};
void draw(const paradiso::Shader& shader) {
shader.set_uniform("pivot", messageSprite.pivot);
shader.set_uniform("scale", messageSprite.scale);
renderer.draw(messageSprite, shader);
}
};
auto main() -> int { auto main() -> int {
std::srand(std::time(nullptr));
// Ausgabefenster ... sieht aus als wäre es auf dem Stack // Ausgabefenster ... sieht aus als wäre es auf dem Stack
auto window = paradiso::Window(); auto window = paradiso::Window();
@ -246,7 +450,7 @@ auto main() -> int {
*/ */
window window
.set_size(size) // ... Grösse .set_size(size) // ... Grösse
.set_position(paradiso::Point{.x = 100, .y = 100}) // ... Position .set_position(paradiso::Point{.x = 1920 / 2 - 500 / 2, .y = 1080 / 2 - 700 / 2}) // ... Position
.set_title("PardiSO.FlappyBird") // ... Titel .set_title("PardiSO.FlappyBird") // ... Titel
.set_visible(true); // ... und jetzt anzeigen! .set_visible(true); // ... und jetzt anzeigen!
@ -276,8 +480,11 @@ auto main() -> int {
// Load // Load
auto background = Background{}; auto background = Background{};
auto grass = Grass{}; auto grass = Grass{};
auto quickwingsapp = QuickWings{}; auto quickwingsapp = QuickWings{};
auto pipe = Pipe{};
auto message = Message{};
auto gameover = GameOverMessage{};
// timer // timer
@ -291,13 +498,29 @@ auto main() -> int {
ctx.clear(); ctx.clear();
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
// Keyboard and state change // Keyboard and state change + update
if (quickwingsapp.paused == false) {
pipe.paused = false;
}
pipe.update();
quickwingsapp.on_keyboard(w.keyboard_input()); quickwingsapp.on_keyboard(w.keyboard_input());
quickwingsapp.update(); quickwingsapp.update();
message.on_keyboard(w.keyboard_input());
message.update();
// Draw // Draw
background.draw(shader); background.draw(shader);
pipe.draw(shader);
grass.draw(shader); grass.draw(shader);
message.draw(shader);
if (game_over == true) {
gameover.draw(shader);
}
quickwingsapp.draw(shader); quickwingsapp.draw(shader);
// wait for frame rate // wait for frame rate
@ -310,7 +533,7 @@ auto main() -> int {
// Quit // Quit
return !(w.keyboard_input().size() && return !(w.keyboard_input().size() &&
w.keyboard_input().top().key == 'Q'); w.keyboard_input().top().key == 'Q');
})) { })) {
}; };
return 0; return 0;