MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
defender_window.hpp
Go to the documentation of this file.
1#ifndef DEFENDER_WINDOW_HPP
2#define DEFENDER_WINDOW_HPP
3
4#include "defender_assets.hpp"
6#include "defender_types.hpp"
7
8#include "asteroids3d_types.hpp"
9#include "rain.hpp"
10#include "ship.hpp"
11#include "starfield.hpp"
12
13#include "mxvk/mxvk.hpp"
15#include "mxvk/mxvk_console.hpp"
17#if defined(MXVK_WITH_MIXER) || defined(WITH_MIXER)
18#include "mxvk/mxvk_sound.hpp"
19#endif
20
21#include <SDL3/SDL.h>
22
23#include <array>
24#include <chrono>
25#include <cstdint>
26#include <memory>
27#include <ostream>
28#include <string>
29#include <vector>
30
31#include <glm/glm.hpp>
32
33namespace defender {
34
36 public:
37 DefenderWindow(const std::string &path, int width, int height, bool fullscreen, bool enable_vsync);
38 ~DefenderWindow() override;
39 void event(SDL_Event &e) override;
40 void onSwapchainRecreated() override;
41 void onPrepareFrameRendering(VkCommandBuffer cmd, uint32_t image_index) override;
42 void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t image_index) override;
43 private:
44 std::string asset_root;
45 std::chrono::steady_clock::time_point last_frame_time = std::chrono::steady_clock::now();
46 float elapsed_seconds = 0.0f;
48 float intro_fade = 1.0f;
49 Uint32 intro_last_update_ms = 0;
50 Uint32 intro_fade_in_start_ms = 0;
51 static constexpr Uint32 INTRO_FADE_IN_DURATION_MS = 500;
52 static constexpr int INTRO_RAIN_TEXTURE_WIDTH = 1280;
53 static constexpr int INTRO_RAIN_TEXTURE_HEIGHT = 720;
54 static constexpr int ENEMY_SPAWN_ATTEMPTS = 16;
55 static constexpr float ENEMY_SEPARATION_PADDING = 0.12f;
56 Uint32 countdown_timer = 0;
57 Uint32 countdown_duration = 1000;
58 Uint32 countdown_start_ms = 0;
59 int countdown_number = 3;
60 Uint32 launch_timer = 0;
61 Uint32 launch_duration = 1000;
62 Uint32 launch_start_ms = 0;
63 float ship_forward_direction = 1.0f;
64 float camera_center_x = 0.0f;
65 float playable_world_top = WORLD_TOP;
66 float respawn_timer = 0.0f;
67 int score = 0;
68 int lives = 5;
69 int level = 1;
70 bool level_active = false;
71 bool game_over = false;
72 bool ship_respawning = false;
73 bool reverse_pressed = false;
74 bool propulsion_pressed = false;
75 bool up_pressed = false;
76 bool down_pressed = false;
77 bool fire_pressed = false;
78 bool roll_left_pressed = false;
79 bool roll_right_pressed = false;
80 bool boost_pressed = false;
81 bool controller_propulsion_pressed = false;
82 bool controller_boost_pressed = false;
83 bool controller_roll_left_pressed = false;
84 bool controller_roll_right_pressed = false;
85 bool controller_reverse_trigger_pressed = false;
86 float controller_vertical_input = 0.0f;
87 bool show_fps_counter = false;
88 bool crt_enabled = true;
89 float fps_accumulator = 0.0f;
90 int fps_frame_count = 0;
91 std::string fps_text = "FPS: --";
92 float barrel_roll_direction = 1.0f;
93 float barrel_roll_progress = 0.0f;
94 float barrel_roll_angle = 0.0f;
95 static constexpr float BARREL_ROLL_DURATION = 0.65f;
96 static constexpr int DEFAULT_FONT_SIZE = 24;
97 static constexpr int HUD_FONT_SIZE = DEFAULT_FONT_SIZE * 2;
98 static constexpr int COUNTDOWN_FONT_SIZE = HUD_FONT_SIZE;
99 mxvk::Font hud_font{};
100 mxvk::Font countdown_font{};
101
102 space::Ship ship{};
103 std::array<space::Projectile, MAX_PROJECTILES> projectiles{};
104 std::array<Ufo, MAX_UFOS> ufos{};
105 std::array<Asteroid, MAX_ASTEROIDS> asteroids{};
106 std::array<space::Particle, space::MAX_PARTICLES> particles{};
107 space::StarField star_field{};
108 mxvk::VKAbstractModel ship_model{};
109 std::array<mxvk::VKAbstractModel, MAX_ASTEROIDS> asteroid_models{};
110 mxvk::VK_Sprite3D *star_sprite = nullptr;
111 mxvk::VK_Sprite3D *terrain_sprite = nullptr;
112 mxvk::VK_Sprite3D *projectile_sprite = nullptr;
113 std::array<std::array<mxvk::VK_Sprite3D *, UFO_ANIMATION_FRAMES>, UFO_SPRITE_SET_COUNT> ufo_sprite_sets{};
114 std::array<std::array<SpriteAlphaBounds, UFO_ANIMATION_FRAMES>, UFO_SPRITE_SET_COUNT> ufo_sprite_bounds{};
115 mxvk::VK_Sprite3D *effect_sprite = nullptr;
116 mxvk::VK_Sprite *intro_sprite = nullptr;
117 mxvk::VK_Sprite *fade_overlay_sprite = nullptr;
118 std::unique_ptr<matrix::Rain> intro_rain{};
120 mxvk::VK_Controller controller{};
121 bool console_ready = false;
122#if defined(MXVK_WITH_MIXER) || defined(WITH_MIXER)
123 std::unique_ptr<mxvk::VK_Mixer> background_music{};
124 int background_music_track = -1;
125 int crash_sound = -1;
126 int shoot_sound = -1;
127 int takeoff_sound = -1;
128 int asteroid_explosion_sound = -1;
129 int ufo_explosion_sound = -1;
130#endif
131 glm::vec3 camera_position{0.0f, CAMERA_HEIGHT, CAMERA_DISTANCE};
132 glm::mat4 last_ship_model_matrix{1.0f};
133 VkBuffer flame_vertex_buffer = VK_NULL_HANDLE;
134 VkDeviceMemory flame_vertex_buffer_memory = VK_NULL_HANDLE;
135 VkPipeline flame_pipeline = VK_NULL_HANDLE;
136 VkPipelineLayout flame_pipeline_layout = VK_NULL_HANDLE;
137 uint32_t flame_vertex_count = 0;
138
139 void configure_console();
140 bool handle_console_command(const std::vector<std::string> &args, std::ostream &out);
141 void log_game(const std::string &message, SDL_Color color = SDL_Color{180, 220, 255, 255});
142 [[nodiscard]] const char *mode_name() const;
143 [[nodiscard]] static std::string format_vec3(const glm::vec3 &value);
144 bool parse_int_arg(const std::vector<std::string> &args, std::size_t index, const char *name, int &value, std::ostream &out) const;
145 bool parse_float_arg(const std::vector<std::string> &args, std::size_t index, const char *name, float &value, std::ostream &out) const;
146 [[nodiscard]] int active_ufo_count() const;
147 [[nodiscard]] int active_asteroid_count() const;
148 [[nodiscard]] int active_projectile_count() const;
149 Ufo *find_inactive_ufo();
150 Asteroid *find_inactive_asteroid();
151 void clear_input_state();
152 bool open_controller();
153 void sync_controller_connection();
154 [[nodiscard]] float controller_axis(SDL_GamepadAxis axis) const;
155 void update_controller_input();
156#if defined(MXVK_WITH_MIXER) || defined(WITH_MIXER)
157 void ensure_background_music_playing();
158 void play_sound(int sound_id);
159#endif
160 void update_ship(float dt);
161 void update_barrel_roll(float dt);
162 glm::mat4 build_ship_model_matrix();
163 glm::mat4 build_asteroid_model_matrix(const Asteroid &asteroid, const mxvk::VKAbstractModel &model_resource) const;
164 void update_camera_position(float dt);
165 void update_playable_world_top(const VkExtent2D &extent);
166 void reset_intro_screen();
167 void start_launch_countdown();
168 void start_intro_fade_in();
169 void draw_intro(const VkExtent2D &extent);
170 void draw_intro_fade_in(const VkExtent2D &extent);
171 void draw_fade_overlay(const VkExtent2D &extent, float alpha);
172 void update_camera_scroll(float aspect);
173 void update_countdown();
174 void draw_countdown(VkCommandBuffer cmd, uint32_t image_index, const VkExtent2D &extent, const glm::mat4 &view, const glm::mat4 &projection);
175 void init_ufos();
176 void init_asteroids();
177 void start_level();
178 void update_level_progress();
179 void respawn_ufo(Ufo &ufo, bool initial_spawn = false);
180 void update_ufos(float dt);
181 void respawn_asteroid(Asteroid &asteroid, bool initial_spawn = false);
182 void update_asteroids(float dt);
183 [[nodiscard]] float ufo_collision_radius(const Ufo &ufo) const;
184 [[nodiscard]] bool enemy_spawn_is_clear(const glm::vec3 &position, float radius, const Ufo *ignored_ufo, const Asteroid *ignored_asteroid) const;
185 void clamp_enemy_to_world_y(glm::vec3 &position, glm::vec3 &velocity, float radius);
186 void separate_enemies(glm::vec3 &first_position,
187 glm::vec3 &first_velocity,
188 float first_radius,
189 glm::vec3 &second_position,
190 glm::vec3 &second_velocity,
191 float second_radius,
192 float restitution);
193 void resolve_enemy_overlaps();
194 [[nodiscard]] int current_ufo_frame(const Ufo &ufo) const;
195 [[nodiscard]] float current_ufo_pulse(const Ufo &ufo) const;
196 [[nodiscard]] glm::vec2 ufo_draw_size(const Ufo &ufo, float pulse) const;
197 void draw_ufos();
198 void draw_terrain();
199 void draw_asteroids(VkCommandBuffer cmd, uint32_t image_index, const glm::mat4 &view, const glm::mat4 &projection);
200 void create_flame_resources();
201 void cleanup_flame_resources();
202 void cleanup_flame_swapchain_resources();
203 void create_flame_swapchain_resources();
204 void create_flame_mesh();
205 void create_flame_pipeline();
206 void draw_engine_flame(VkCommandBuffer cmd, const VkExtent2D &extent, const glm::mat4 &view, const glm::mat4 &projection);
207 void create_buffer(VkDeviceSize size,
208 VkBufferUsageFlags usage,
209 VkMemoryPropertyFlags properties,
210 VkBuffer &buffer,
211 VkDeviceMemory &buffer_memory) const;
212 [[nodiscard]] uint32_t find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) const;
213 void fire_projectile();
214 void update_projectiles(float dt);
215 void check_projectile_ufo_hits();
216 void check_projectile_asteroid_hits();
217 void check_ship_ufo_collisions();
218 void check_ship_asteroid_collisions();
219 void lose_life();
220 void update_respawn(float dt);
221 void reset_ship_to_origin();
222 void reset_ufos_for_origin_start();
223 void restart_game();
224 void clear_projectiles();
225 void draw_projectiles();
226 void spawn_ufo_explosion(const glm::vec3 &position, float explosion_scale = 1.0f);
227 void spawn_alien_explosion(const glm::vec3 &position, float explosion_scale = 1.0f);
228 void spawn_ship_explosion(const glm::vec3 &position, float explosion_scale = 1.0f);
229 void spawn_enemy_explosion(const glm::vec3 &position, float explosion_scale, const std::array<glm::vec3, 4> &wave_colors, bool color_flash = false);
230 space::Particle *find_free_particle();
231 void update_particles(float dt);
232 void draw_particles();
233 void clear_particles();
234 void update_fps_counter(float delta_seconds);
235 void draw_hud(const VkExtent2D &extent);
236 void draw_scanner(const VkExtent2D &extent);
237 };
238} // namespace defender
239
240#endif
void onPrepareFrameRendering(VkCommandBuffer cmd, uint32_t image_index) override
Record resource transitions that must happen before dynamic rendering begins.
void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t image_index) override
Optional hook for derived classes to record extra draw commands.
void event(SDL_Event &e) override
Handle one SDL event.
DefenderWindow(const std::string &path, int width, int height, bool fullscreen, bool enable_vsync)
void onSwapchainRecreated() override
Called after swapchain and render resources are recreated.
Small RAII wrapper for an SDL_ttf font handle.
Definition mxvk_text.hpp:46
Convenience wrapper that owns mesh, textures, descriptors, and pipeline state.
Lightweight command console renderer for mxvk::VK_Window.
RAII wrapper for SDL_Gamepad (standard layout mapping).
Depth-tested 3D billboard sprite batch.
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:37
Mutable gameplay and movement state for a player ship.
Definition ship.hpp:17
Manages and renders a camera-centered field of animated stars.
Definition starfield.hpp:22
High-level model wrapper integrated with MXVK dynamic rendering.
In-game command console for MXVK / Vulkan windows.
SDL3 joystick and gamepad RAII wrappers.
SDL3_mixer audio subsystem wrapper.
constexpr float WORLD_TOP
constexpr int UFO_SPRITE_SET_COUNT
constexpr float CAMERA_DISTANCE
constexpr float CAMERA_HEIGHT
Runtime state for an explosion or engine particle.