Quellcode durchsuchen

:sparkles: added button component (currently only visual, no functionality)

Felix Bytow vor 1 Jahr
Ursprung
Commit
ed8ec45732
6 geänderte Dateien mit 358 neuen und 2 gelöschten Zeilen
  1. 1 0
      CMakeLists.txt
  2. 5 1
      game/DummyState.cxx
  3. 5 0
      game/DummyState.hxx
  4. 312 0
      game/ui/Button.cxx
  5. 34 0
      game/ui/Button.hxx
  6. 1 1
      main.cxx

+ 1 - 0
CMakeLists.txt

@@ -37,6 +37,7 @@ add_executable(Snake WIN32
     game/SplashState.cxx game/SplashState.hxx
     game/DummyState.cxx game/DummyState.hxx
     game/AssetManager.cxx game/AssetManager.hxx
+    game/ui/Button.cxx game/ui/Button.hxx
 )
 
 target_link_libraries(Snake PRIVATE

+ 5 - 1
game/DummyState.cxx

@@ -5,12 +5,16 @@
 void DummyState::update(GameStateManager& gsm, std::chrono::milliseconds delta_time)
 {
   (void) gsm;
-  (void) delta_time;
+  time_in_state_ += delta_time;
+  test_button_.set_pressed((time_in_state_.count() % 4'000) >= 2'000);
 }
 
 void DummyState::render(SDLRenderer& renderer)
 {
   SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
   SDL_RenderClear(renderer);
+
+  test_button_.render(renderer);
+
   SDL_RenderPresent(renderer);
 }

+ 5 - 0
game/DummyState.hxx

@@ -4,12 +4,17 @@
 #define SNAKE_DUMMYSTATE_HXX
 
 #include "GameState.hxx"
+#include "ui/Button.hxx"
 
 class DummyState final : public GameState {
 public:
   void update(GameStateManager& gsm, std::chrono::milliseconds delta_time) override;
 
   void render(SDLRenderer& renderer) override;
+
+private:
+  std::chrono::milliseconds time_in_state_{0};
+  Button test_button_{"Test", 15, 15, 300, 80};
 };
 
 #endif // SNAKE_DUMMYSTATE_HXX

+ 312 - 0
game/ui/Button.cxx

@@ -0,0 +1,312 @@
+#include "Button.hxx"
+
+#include "../AssetManager.hxx"
+
+#include "../../SDLRenderer.hxx"
+
+#include <cassert>
+
+namespace {
+  SDL_Rect const UPPER_LEFT{
+      .x = 0,
+      .y = 0,
+      .w = 6,
+      .h = 5,
+  };
+
+  SDL_Rect const UPPER_EDGE{
+      .x = 6,
+      .y = 0,
+      .w = 37,
+      .h = 5,
+  };
+
+  SDL_Rect const UPPER_RIGHT{
+      .x = 43,
+      .y = 0,
+      .w = 6,
+      .h = 5,
+  };
+
+  SDL_Rect const LEFT_EDGE{
+      .x = 0,
+      .y = 5,
+      .w = 6,
+      .h = 35,
+  };
+
+  SDL_Rect const CENTER{
+      .x = 6,
+      .y = 5,
+      .w = 37,
+      .h = 35,
+  };
+
+  SDL_Rect const RIGHT_EDGE{
+      .x = 43,
+      .y = 5,
+      .w = 6,
+      .h = 35,
+  };
+
+  SDL_Rect const LOWER_LEFT_UP{
+      .x = 0,
+      .y = 40,
+      .w = 6,
+      .h = 9,
+  };
+
+  SDL_Rect const LOWER_EDGE_UP{
+      .x = 6,
+      .y = 40,
+      .w = 37,
+      .h = 9,
+  };
+
+  SDL_Rect const LOWER_RIGHT_UP{
+      .x = 43,
+      .y = 40,
+      .w = 6,
+      .h = 9,
+  };
+
+  SDL_Rect const LOWER_LEFT_DOWN{
+      .x = 0,
+      .y = 40,
+      .w = 6,
+      .h = 5,
+  };
+
+  SDL_Rect const LOWER_EDGE_DOWN{
+      .x = 6,
+      .y = 40,
+      .w = 37,
+      .h = 5,
+  };
+
+  SDL_Rect const LOWER_RIGHT_DOWN{
+      .x = 43,
+      .y = 40,
+      .w = 6,
+      .h = 5,
+  };
+
+  SDL_Rect calculate_text_rect(SDL_Rect const& area, SDL_Texture* texture)
+  {
+    int text_w, text_h;
+    SDL_QueryTexture(texture, nullptr, nullptr, &text_w, &text_h);
+
+    float const text_aspect = static_cast<float>(text_w)/static_cast<float>(text_h);
+    float const area_aspect = static_cast<float>(area.w)/static_cast<float>(area.h);
+
+    int put_w, put_h;
+    if (text_aspect>area_aspect) {
+      put_w = area.w;
+      put_h = static_cast<int>(static_cast<float>(put_w)/text_aspect);
+    }
+    else {
+      put_h = area.h;
+      put_w = static_cast<int>(static_cast<float>(put_h)*text_aspect);
+    }
+
+    return {
+        .x = area.x+(area.w-put_w)/2,
+        .y = area.y+(area.h-put_h)/2,
+        .w = put_w,
+        .h = put_h,
+    };
+  }
+}
+
+Button::Button(std::string title, int x, int y, int w, int h)
+    :title_{std::move(title)}, x_{x}, y_{y}, w_{w}, h_{h}, pressed_{false}
+{
+  assert(w_>=12);
+  assert(h_>=14);
+
+  up_ = std::async(std::launch::deferred, [] {
+    return AssetManager::instance().get_texture_asset("blue_button_up.png");
+  });
+  down_ = std::async(std::launch::deferred, [] {
+    return AssetManager::instance().get_texture_asset("blue_button_down.png");
+  });
+  font_ = std::async(std::launch::deferred, [] {
+    return AssetManager::instance().get_font_asset("kenvector_future.ttf");
+  });
+}
+
+void Button::set_pressed(bool const pressed)
+{
+  pressed_ = pressed;
+}
+
+bool Button::is_pressed() const
+{
+  return pressed_;
+}
+
+void Button::render(SDLRenderer& renderer)
+{
+  auto const text = TTF_RenderUTF8_Solid(font_.get(), title_.c_str(), {0, 0, 0, SDL_ALPHA_OPAQUE});
+  auto const text_ure = SDL_CreateTextureFromSurface(renderer, text);
+  SDL_FreeSurface(text);
+
+  if (pressed_) {
+    auto const down = down_.get();
+
+    SDL_Rect const upper_left{
+        .x = x_,
+        .y = y_+4,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::UPPER_LEFT, &upper_left);
+
+    SDL_Rect const upper_edge{
+        .x = x_+6,
+        .y = y_+4,
+        .w = w_-12,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::UPPER_EDGE, &upper_edge);
+
+    SDL_Rect const upper_right{
+        .x = x_+w_-6,
+        .y = y_+4,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::UPPER_RIGHT, &upper_right);
+
+    SDL_Rect const left_edge{
+        .x = x_,
+        .y = y_+9,
+        .w = 6,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, down, &::LEFT_EDGE, &left_edge);
+
+    SDL_Rect const center{
+        .x = x_+6,
+        .y = y_+9,
+        .w = w_-12,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, down, &::CENTER, &center);
+
+    SDL_Rect const text_rect = ::calculate_text_rect(center, text_ure);
+    SDL_RenderCopy(renderer, text_ure, nullptr, &text_rect);
+
+    SDL_Rect const right_edge{
+        .x = x_+w_-6,
+        .y = y_+9,
+        .w = 6,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, down, &::RIGHT_EDGE, &right_edge);
+
+    SDL_Rect const lower_left{
+        .x = x_,
+        .y = y_+h_-5,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::LOWER_LEFT_DOWN, &lower_left);
+
+    SDL_Rect const lower_edge{
+        .x = x_+6,
+        .y = y_+h_-5,
+        .w = w_-12,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::LOWER_EDGE_DOWN, &lower_edge);
+
+    SDL_Rect const lower_right{
+        .x = x_+w_-6,
+        .y = y_+h_-5,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, down, &::LOWER_RIGHT_DOWN, &lower_right);
+  }
+  else {
+    auto const up = up_.get();
+
+    SDL_Rect const upper_left{
+        .x = x_,
+        .y = y_,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, up, &::UPPER_LEFT, &upper_left);
+
+    SDL_Rect const upper_edge{
+        .x = x_+6,
+        .y = y_,
+        .w = w_-12,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, up, &::UPPER_EDGE, &upper_edge);
+
+    SDL_Rect const upper_right{
+        .x = x_+w_-6,
+        .y = y_,
+        .w = 6,
+        .h = 5,
+    };
+    SDL_RenderCopy(renderer, up, &::UPPER_RIGHT, &upper_right);
+
+    SDL_Rect const left_edge{
+        .x = x_,
+        .y = y_+5,
+        .w = 6,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, up, &::LEFT_EDGE, &left_edge);
+
+    SDL_Rect const center{
+        .x = x_+6,
+        .y = y_+5,
+        .w = w_-12,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, up, &::CENTER, &center);
+
+    SDL_Rect const text_rect = ::calculate_text_rect(center, text_ure);
+    SDL_RenderCopy(renderer, text_ure, nullptr, &text_rect);
+
+    SDL_Rect const right_edge{
+        .x = x_+w_-6,
+        .y = y_+5,
+        .w = 6,
+        .h = h_-14,
+    };
+    SDL_RenderCopy(renderer, up, &::RIGHT_EDGE, &right_edge);
+
+    SDL_Rect const lower_left{
+        .x = x_,
+        .y = y_+h_-9,
+        .w = 6,
+        .h = 9,
+    };
+    SDL_RenderCopy(renderer, up, &::LOWER_LEFT_UP, &lower_left);
+
+    SDL_Rect const lower_edge{
+        .x = x_+6,
+        .y = y_+h_-9,
+        .w = w_-12,
+        .h = 9,
+    };
+    SDL_RenderCopy(renderer, up, &::LOWER_EDGE_UP, &lower_edge);
+
+    SDL_Rect const lower_right{
+        .x = x_+w_-6,
+        .y = y_+h_-9,
+        .w = 6,
+        .h = 9,
+    };
+    SDL_RenderCopy(renderer, up, &::LOWER_RIGHT_UP, &lower_right);
+  }
+
+  SDL_DestroyTexture(text_ure);
+}

+ 34 - 0
game/ui/Button.hxx

@@ -0,0 +1,34 @@
+#pragma once
+
+#ifndef SNAKE_BUTTON_HXX
+#define SNAKE_BUTTON_HXX
+
+#include <SDL.h>
+#include <SDL_ttf.h>
+
+#include <future>
+#include <string>
+
+class SDLRenderer;
+
+class Button final {
+public:
+  Button(std::string title, int x, int y, int w, int h);
+
+  void set_pressed(bool pressed);
+
+  bool is_pressed() const;
+
+  void render(SDLRenderer& renderer);
+
+private:
+  std::string title_;
+  int x_, y_, w_, h_;
+  bool pressed_;
+
+  std::shared_future<SDL_Texture*> up_;
+  std::shared_future<SDL_Texture*> down_;
+  std::shared_future<TTF_Font*> font_;
+};
+
+#endif // SNAKE_BUTTON_HXX

+ 1 - 1
main.cxx

@@ -51,4 +51,4 @@ int main(int argc, char** argv) try
 } catch (std::exception const& ex) {
   SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", ex.what());
   return EXIT_FAILURE;
-}
+}