Add flappy bird

This commit is contained in:
Robin Rottstädt 2023-09-23 22:12:50 +02:00
parent 237102965b
commit 9b57ca68c6
No known key found for this signature in database
GPG key ID: 630B61F1D46CCE35
12 changed files with 8392 additions and 1 deletions

View file

@ -0,0 +1,298 @@
/**
* 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 <unordered_map>
#include <iomanip>
#include <iostream>
#include "image_loader.hpp"
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.0006f;
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.005f;
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.02f;
const float gravity = -0.0002f;
const float move_up_velocity = 0.0003f;
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 * 20.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{};
// 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();
// Keyboard and state change
flappyBird.on_keyboard(w.keyboard_input());
flappyBird.update();
// Draw
background.draw(shader);
grass.draw(shader);
flappyBird.draw(shader);
// Quit
return !(w.keyboard_input().size() &&
w.keyboard_input().top().key == 'Q');
})) {
};
return 0;
}