diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/crepe/api/Animator.cpp | 48 | ||||
-rw-r--r-- | src/crepe/api/Animator.h | 101 | ||||
-rw-r--r-- | src/crepe/api/Camera.cpp | 9 | ||||
-rw-r--r-- | src/crepe/api/Camera.h | 26 | ||||
-rw-r--r-- | src/crepe/api/Config.h | 2 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 1 | ||||
-rw-r--r-- | src/crepe/api/Sprite.cpp | 16 | ||||
-rw-r--r-- | src/crepe/api/Sprite.h | 82 | ||||
-rw-r--r-- | src/crepe/api/Transform.h | 2 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 117 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.h | 29 | ||||
-rw-r--r-- | src/crepe/system/AnimatorSystem.cpp | 27 | ||||
-rw-r--r-- | src/crepe/system/AnimatorSystem.h | 7 | ||||
-rw-r--r-- | src/crepe/system/RenderSystem.cpp | 21 | ||||
-rw-r--r-- | src/crepe/system/RenderSystem.h | 11 | ||||
-rw-r--r-- | src/example/rendering_particle.cpp | 73 | ||||
-rw-r--r-- | src/test/ParticleTest.cpp | 6 | ||||
-rw-r--r-- | src/test/RenderSystemTest.cpp | 132 |
18 files changed, 457 insertions, 253 deletions
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 45f67f6..dc99fd4 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -7,21 +7,53 @@ using namespace crepe; -Animator::Animator(game_object_id_t id, Sprite & ss, int row, int col, int col_animator) +Animator::Animator(uint32_t id, Sprite & ss, int max_row, int max_col, + const Animator::Data & ctx) : Component(id), spritesheet(ss), - row(row), - col(col) { + row(max_row), + col(max_col), + data(ctx) { dbg_trace(); - this->spritesheet.mask.h /= col; - this->spritesheet.mask.w /= row; - this->spritesheet.mask.x = 0; - this->spritesheet.mask.y = col_animator * this->spritesheet.mask.h; - this->active = false; + this->spritesheet.mask.h /= this->col; + this->spritesheet.mask.w /= this->row; + this->spritesheet.mask.x = this->data.curr_row * this->spritesheet.mask.w; + this->spritesheet.mask.y = this->data.curr_col * this->spritesheet.mask.h; // need to do this for to get the aspect ratio for a single clipping in the spritesheet this->spritesheet.aspect_ratio = static_cast<double>(this->spritesheet.mask.w) / this->spritesheet.mask.h; } + Animator::~Animator() { dbg_trace(); } + +void Animator::loop() { this->data.looping = true; } + +void Animator::play() { this->active = true; } + +void Animator::pause() { this->active = false; } + +void Animator::stop() { + this->active = false; + this->data.curr_col = 0; + this->data.curr_row = 0; +} +void Animator::set_fps(int fps) { this->data.fps = fps; } + +void Animator::set_cycle_range(int start, int end) { + this->data.cycle_start = start, this->data.cycle_end = end; +} + +void Animator::set_anim(int col) { + Animator::Data & ctx = this->data; + this->spritesheet.mask.x = ctx.curr_row = 0; + ctx.curr_col = col; + this->spritesheet.mask.y = ctx.curr_col * this->spritesheet.mask.h; +} + +void Animator::next_anim() { + Animator::Data & ctx = this->data; + ctx.curr_row = ctx.curr_row++ % this->row; + this->spritesheet.mask.x = ctx.curr_row * this->spritesheet.mask.w; +} diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 6c506aa..dab6697 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -16,33 +16,100 @@ class SDLContext; * sheet. It can be used to play animations, loop them, or stop them. */ class Animator : public Component { +public: + struct Data { + + //! frames per second for animation + int fps = 1; + + //! The current col being animated. + int curr_col = 0; + + //! The current row being animated. + int curr_row = 0; + + //! should the animation loop + bool looping = false; + + //! starting frame for cycling + int cycle_start = 0; + + //! end frame for cycling (-1 --> use last frame) + int cycle_end = -1; + + //! offset in pixels. + // TODO implement + int offset_x = 0; + }; public: - //TODO: need to implement this + /** + * \brief Animator will repeat the animation + * + */ void loop(); + + /** + * \brief starts the animation + * + */ + void play(); + /** + * \brief pauses the animation + * + * sets the active false + * + */ + void pause(); + + /** + * \brief stops the animation + * + * sets the active on false and resets all the current rows and columns + * + */ void stop(); + /** + * \brief set frames per second + * + * \param fps frames per second + */ + void set_fps(int fps); + /** + * \brief set the range in the row + * + * \param start of row animation + * \param end of row animation + */ + void set_cycle_range(int start, int end); + /** + * \brief select which column to animate from + * + * \param col animation column + */ + void set_anim(int col); + + /** + * \brief will go to the next animaiton of current row + * + */ + void next_anim(); public: /** * \brief Constructs an Animator object that will control animations for a sprite sheet. * * \param id The unique identifier for the component, typically assigned automatically. - * \param spritesheet A reference to the Sprite object which holds the sprite sheet for - * animation. - * \param row The maximum number of rows in the sprite sheet. - * \param col The maximum number of columns in the sprite sheet. - * \param col_animate The specific col index of the sprite sheet to animate. This allows - * selecting which col to animate from multiple col in the sheet. + * \param ctx animator data * * This constructor sets up the Animator with the given parameters, and initializes the * animation system. */ - Animator(uint32_t id, Sprite & spritesheet, int row, int col, int col_animate); - + Animator(uint32_t id, Sprite & ss, int max_row, int max_col, const Animator::Data & ctx); ~Animator(); // dbg_trace -private: - //! A reference to the Sprite sheet containing the animation frames. +public: + //! A reference to the Sprite sheet containing. Sprite & spritesheet; //! The maximum number of columns in the sprite sheet. @@ -51,21 +118,11 @@ private: //! The maximum number of rows in the sprite sheet. const int row; - //! The current col being animated. - int curr_col = 0; - - //! The current row being animated. - int curr_row = 0; - - //TODO: Is this necessary? - //int fps; + Animator::Data data; private: //! AnimatorSystem adjust the private member parameters of Animator; friend class AnimatorSystem; - - //! SDLContext reads the Animator member var's - friend class SDLContext; }; } // namespace crepe // diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp index 39d8ab0..b042c35 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -2,19 +2,16 @@ #include "util/Log.h" #include "Camera.h" -#include "Color.h" #include "Component.h" using namespace crepe; -Camera::Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, - const vec2 & viewport_size, const double & zoom, const vec2 & offset) +Camera::Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, + const Data & ctx) : Component(id), - bg_color(bg_color), - offset(offset), screen(screen), viewport_size(viewport_size), - zoom(zoom) { + data(ctx) { dbg_trace(); } diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h index 2d8fa48..f626379 100644 --- a/src/crepe/api/Camera.h +++ b/src/crepe/api/Camera.h @@ -14,23 +14,30 @@ namespace crepe { * position, and zoom level. It controls what part of the game world is visible on the screen. */ class Camera : public Component { +public: + struct Data { + //! Background color of the camera view. + const Color bg_color = Color::WHITE; + + //! Zoom level of the camera view. + double zoom = 1; + + //! offset postion from the game object transform component + vec2 offset; + }; public: /** * \brief Constructs a Camera with the specified ID and background color. * \param id Unique identifier for the camera component. - * \param bg_color Background color for the camera view. + * \param ctx the camera component data */ - Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, - const vec2 & viewport_size, const double & zoom, const vec2 & offset = {0, 0}); + Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, + const Data & ctx); ~Camera(); // dbg_trace only public: - //! Background color of the camera view. - const Color bg_color; - - //! offset postion from the game object transform component - vec2 offset; + Camera::Data data; //! screen the display size in pixels ( output resolution ) const ivec2 screen; @@ -38,9 +45,6 @@ public: //! viewport is the area of the world visible through the camera (in world units) const vec2 viewport_size; - //! Zoom level of the camera view. - const double zoom; - public: /** * \brief Gets the maximum number of camera instances allowed. diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 225e9b9..200a3b0 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -67,7 +67,7 @@ public: //! default window settings struct { //TODO make this constexpr because this will never change - ivec2 default_size = {1080, 720}; + ivec2 default_size = {1280, 720}; std::string window_title = "Jetpack joyride clone"; } window_settings; diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index dc2d9e0..3e9a88e 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -60,6 +60,7 @@ void LoopManager::setup() { this->game_running = true; timer.start(); timer.set_fps(200); + this->scene_manager.load_next_scene(); } void LoopManager::render() { diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index 0a2ad4c..b52a344 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -6,24 +6,20 @@ #include "Component.h" #include "Sprite.h" #include "Texture.h" +#include "types.h" using namespace std; using namespace crepe; -Sprite::Sprite(game_object_id_t id, Texture & image, const Color & color, - const FlipSettings & flip, int sort_layer, int order_layer, int height) +Sprite::Sprite(game_object_id_t id, Texture & texture, const Sprite::Data & ctx) : Component(id), - color(color), - flip(flip), - sprite_image(std::move(image)), - sorting_in_layer(sort_layer), - order_in_layer(order_layer), - height(height) { + texture(std::move(texture)), + data(ctx) { dbg_trace(); - this->mask.w = sprite_image.get_size().x; - this->mask.h = sprite_image.get_size().y; + this->mask.w = this->texture.get_size().x; + this->mask.h = this->texture.get_size().y; this->aspect_ratio = static_cast<double>(this->mask.w) / this->mask.h; } diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index a0e90a0..a1230db 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -1,11 +1,10 @@ #pragma once -#include <cstdint> - #include "../Component.h" #include "Color.h" #include "Texture.h" +#include "types.h" namespace crepe { @@ -20,60 +19,67 @@ class AnimatorSystem; * flip settings, and is managed in layers with defined sorting orders. */ class Sprite : public Component { - public: struct FlipSettings { bool flip_x = false; bool flip_y = false; }; + struct Data { + //! Color tint of the sprite + Color color = Color::WHITE; + + //! Flip settings for the sprite + FlipSettings flip; + + //! Layer sorting level of the sprite + const int sorting_in_layer = 0; + + //! Order within the sorting layer + const int order_in_layer = 0; + + /** + * \size width and height of the sprite in game units + * + * if height is filled in and not width it will multiply width by aspect_ratio. + * if width is filled in and not height it will multiply height by aspect_ratio. + * if neither is filled it will not show sprite because size will be zero + * if both are filled will it use the width and height without making sure the aspect_ratio + * is correct + */ + vec2 size; + + //! independent sprite angle. rotating clockwise direction in degrees + double angle_offset = 0; + + //! independent sprite scale multiplier + double scale_offset = 1; + }; + public: - // TODO: Loek comment in github #27 will be looked another time - // about shared_ptr Texture /** * \brief Constructs a Sprite with specified parameters. * \param game_id Unique identifier for the game object this sprite belongs to. - * \param image Shared pointer to the texture for this sprite. - * \param color Color tint applied to the sprite. - * \param flip Flip settings for horizontal and vertical orientation. - * \param order_layer decides the sorting in layer of the sprite. - * \param sort_layer decides the order in layer of the sprite. - * \param height the height of the image in game units - */ - Sprite(game_object_id_t id, Texture & image, const Color & color, - const FlipSettings & flip, int sort_layer, int order_layer, int height); - - /** - * \brief Destroys the Sprite instance. + * \param texture asset of the image + * \param ctx all the sprite data */ + Sprite(game_object_id_t id, Texture & texture, const Data & ctx); ~Sprite(); //! Texture used for the sprite - const Texture sprite_image; - - //! Color tint of the sprite - Color color; - - //! Flip settings for the sprite - FlipSettings flip; + const Texture texture; - //! Layer sorting level of the sprite - const int sorting_in_layer; - //! Order within the sorting layer - const int order_in_layer; - - //! height in world units - const int height; + Data data; +private: /** - * \aspect_ratio ratio of the img so that scaling will not become weird - * - * cannot be const because if Animator component is addded then ratio becomes scuffed and - * does it need to be calculated again in the Animator - */ - double aspect_ratio; + * \aspect_ratio ratio of the img so that scaling will not become weird + * + * cannot be const because if Animator component is addded then ratio becomes scuffed and + * does it need to be calculated again in the Animator + */ + float aspect_ratio; -private: //! Reads the mask of sprite friend class SDLContext; diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h index 6243a93..34ac70a 100644 --- a/src/crepe/api/Transform.h +++ b/src/crepe/api/Transform.h @@ -15,7 +15,7 @@ class Transform : public Component { public: //! Translation (shift) vec2 position = {0, 0}; - //! Rotation, in degrees + //! Rotation, in degrees clockwise double rotation = 0; //! Multiplication factor double scale = 0; diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index ad9f1f0..72b4e42 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -215,11 +215,13 @@ MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) { return MOUSE_BUTTON_LOOKUP_TABLE[sdl_button]; } -void SDLContext::clear_screen() { +void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); } +void SDLContext::present_screen() { SDL_SetRenderDrawColor(this->game_renderer.get(), 0, 0, 0, 255); - SDL_RenderClear(this->game_renderer.get()); + SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[0]); + SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[1]); + SDL_RenderPresent(this->game_renderer.get()); } -void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer.get()); } SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const { return SDL_Rect{ @@ -229,40 +231,57 @@ SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const { .h = sprite.mask.h, }; } -SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam, - const vec2 & cam_pos, const double & img_scale) const { - int width = sprite.height * sprite.aspect_ratio; - int height = sprite.height; +SDL_FRect SDLContext::get_dst_rect(const DstRect & ctx) const { - width *= img_scale * cam.zoom; - height *= img_scale * cam.zoom; + const Sprite::Data & data = ctx.sprite.data; - return SDL_Rect{ - .x = static_cast<int>((pos.x - cam_pos.x + (cam.viewport_size.x / 2) - width / 2)), - .y = static_cast<int>((pos.y - cam_pos.y + (cam.viewport_size.y / 2) - height / 2)), - .w = width, - .h = height, + vec2 size = {data.size.x == 0 && data.size.y != 0 ? data.size.y * ctx.sprite.aspect_ratio + : data.size.x, + data.size.y == 0 && data.size.x != 0 ? data.size.x / ctx.sprite.aspect_ratio + : data.size.y}; + + const CameraValues & cam = ctx.cam; + + size *= cam.render_scale * ctx.img_scale * data.scale_offset; + + vec2 screen_pos = (ctx.pos - cam.cam_pos + (cam.zoomed_viewport) / 2) * cam.render_scale + - size / 2 + cam.bar_size; + + return SDL_FRect{ + .x = screen_pos.x, + .y = screen_pos.y, + .w = size.x, + .h = size.y, }; } void SDLContext::draw(const RenderContext & ctx) { + const Sprite::Data & data = ctx.sprite.data; SDL_RendererFlip render_flip - = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * ctx.sprite.flip.flip_x) - | (SDL_FLIP_VERTICAL * ctx.sprite.flip.flip_y)); + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * data.flip.flip_x) + | (SDL_FLIP_VERTICAL * data.flip.flip_y)); SDL_Rect srcrect = this->get_src_rect(ctx.sprite); - SDL_Rect dstrect - = this->get_dst_rect(ctx.sprite, ctx.pos, ctx.cam, ctx.cam_pos, ctx.scale); + SDL_FRect dstrect = this->get_dst_rect(SDLContext::DstRect{ + .sprite = ctx.sprite, + .cam = ctx.cam, + .pos = ctx.pos, + .img_scale = ctx.scale, + }); + + double angle = ctx.angle + data.angle_offset; this->set_color_texture(ctx.sprite.sprite_image, ctx.sprite.color); - SDL_RenderCopyEx(this->game_renderer.get(), ctx.sprite.sprite_image.texture.get(), - &srcrect, &dstrect, ctx.angle, NULL, render_flip); + SDL_RenderCopyExF(this->game_renderer.get(), ctx.sprite.texture.texture.get(), &srcrect, + &dstrect, angle, NULL, render_flip); } -void SDLContext::set_camera(const Camera & cam) { +SDLContext::CameraValues SDLContext::set_camera(const Camera & cam) { + const Camera::Data & cam_data = cam.data; + CameraValues ret_cam; // resize window int w, h; SDL_GetWindowSize(this->game_window.get(), &w, &h); @@ -270,42 +289,52 @@ void SDLContext::set_camera(const Camera & cam) { SDL_SetWindowSize(this->game_window.get(), cam.screen.x, cam.screen.y); } - double screen_aspect = cam.screen.x / cam.screen.y; - double viewport_aspect = cam.viewport_size.x / cam.viewport_size.y; + vec2 & zoomed_viewport = ret_cam.zoomed_viewport; + vec2 & bar_size = ret_cam.bar_size; + vec2 & render_scale = ret_cam.render_scale; + + zoomed_viewport = cam.viewport_size * cam_data.zoom; + double screen_aspect = static_cast<double>(cam.screen.x) / cam.screen.y; + double viewport_aspect = zoomed_viewport.x / zoomed_viewport.y; - SDL_Rect view; // calculate black bars if (screen_aspect > viewport_aspect) { - // letterboxing - view.h = cam.screen.y / cam.zoom; - view.w = cam.screen.y * viewport_aspect; - view.x = (cam.screen.x - view.w) / 2; - view.y = 0; - } else { // pillarboxing - view.h = cam.screen.x / viewport_aspect; - view.w = cam.screen.x / cam.zoom; - view.x = 0; - view.y = (cam.screen.y - view.h) / 2; + float scale = cam.screen.y / zoomed_viewport.y; + float adj_width = zoomed_viewport.x * scale; + float bar_width = (cam.screen.x - adj_width) / 2; + this->black_bars[0] = {0, 0, bar_width, (float) cam.screen.y}; + this->black_bars[1] = {(cam.screen.x - bar_width), 0, bar_width, (float) cam.screen.y}; + + bar_size = {bar_width, 0}; + render_scale.x = render_scale.y = scale; + } else { + // letterboxing + float scale = cam.screen.x / (cam.viewport_size.x * cam_data.zoom); + float adj_height = cam.viewport_size.y * scale; + float bar_height = (cam.screen.y - adj_height) / 2; + this->black_bars[0] = {0, 0, (float) cam.screen.x, bar_height}; + this->black_bars[1] + = {0, (cam.screen.y - bar_height), (float) cam.screen.x, bar_height}; + + bar_size = {0, bar_height}; + render_scale.x = render_scale.y = scale; } - // set drawing area - SDL_RenderSetViewport(this->game_renderer.get(), &view); - SDL_RenderSetLogicalSize(this->game_renderer.get(), static_cast<int>(cam.viewport_size.x), - static_cast<int>(cam.viewport_size.y)); - - // set bg color - SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r, cam.bg_color.g, - cam.bg_color.b, cam.bg_color.a); + SDL_SetRenderDrawColor(this->game_renderer.get(), cam_data.bg_color.r, cam_data.bg_color.g, + cam_data.bg_color.b, cam_data.bg_color.a); SDL_Rect bg = { .x = 0, .y = 0, - .w = static_cast<int>(cam.viewport_size.x), - .h = static_cast<int>(cam.viewport_size.y), + .w = cam.screen.x, + .h = cam.screen.y, }; + // fill bg color SDL_RenderFillRect(this->game_renderer.get(), &bg); + + return ret_cam; } uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); } diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index a2b34c1..dfdaa56 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -33,10 +33,17 @@ class InputSystem; */ class SDLContext { public: + //! data that the camera component cannot hold + struct CameraValues { + vec2 zoomed_viewport; + vec2 render_scale; + vec2 bar_size; + vec2 cam_pos; + }; + struct RenderContext { const Sprite & sprite; - const Camera & cam; - const vec2 & cam_pos; + const CameraValues & cam; const vec2 & pos; const double & angle; const double & scale; @@ -114,8 +121,6 @@ private: MouseButton sdl_to_mousebutton(Uint8 sdl_button); private: - //! Will only use get_ticks - friend class AnimatorSystem; //! Will only use delay friend class LoopTimer; /** @@ -170,7 +175,7 @@ private: /** * \brief Draws a sprite to the screen using the specified transform and camera. - * \param RenderCtx Reference to rendering data to draw + * \param RenderContext Reference to rendering data to draw */ void draw(const RenderContext & ctx); @@ -184,9 +189,15 @@ private: * \brief sets the background of the camera (will be adjusted in future PR) * \param camera Reference to the Camera object. */ - void set_camera(const Camera & camera); + CameraValues set_camera(const Camera & camera); private: + struct DstRect { + const Sprite & sprite; + const CameraValues & cam; + const vec2 & pos; + const double & img_scale; + }; /** * \brief calculates the sqaure size of the image * @@ -205,8 +216,7 @@ private: * \param img_scale the image multiplier for increasing img size * \return sdl rectangle to draw a dst image to draw on the screen */ - SDL_Rect get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam, - const vec2 & cam_pos, const double & img_scale) const; + SDL_FRect get_dst_rect(const DstRect & ctx) const; /** * \brief Set an additional color value multiplied into render copy operations. * @@ -221,6 +231,9 @@ private: //! renderer for the crepe engine std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>> game_renderer; + + //! black bars rectangle to draw + SDL_FRect black_bars[2]; }; } // namespace crepe diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 8bb6465..9aede7f 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,4 +1,4 @@ -#include <cstdint> + #include "../api/Animator.h" #include "../facade/SDLContext.h" @@ -13,12 +13,27 @@ void AnimatorSystem::update() { RefVector<Animator> animations = mgr.get_components_by_type<Animator>(); - uint64_t tick = SDLContext::get_instance().get_ticks(); + double elapsed_time = this->timer.get_current_time(); + for (Animator & a : animations) { if (!a.active) continue; - // (10 frames per second) - a.curr_row = (tick / 100) % a.row; - a.spritesheet.mask.x = (a.curr_row * a.spritesheet.mask.w) + a.curr_col; - a.spritesheet.mask = a.spritesheet.mask; + + Animator::Data & ctx = a.data; + double frame_duration = 1.0f / ctx.fps; + + int last_frame = ctx.curr_row; + + int cycle_end = (ctx.cycle_end == -1) ? a.row : ctx.cycle_end; + int total_frames = cycle_end - ctx.cycle_start; + + int curr_frame = static_cast<int>(elapsed_time / frame_duration) % total_frames; + + ctx.curr_row = ctx.cycle_start + curr_frame; + a.spritesheet.mask.x = ctx.curr_row * a.spritesheet.mask.w; + a.spritesheet.mask.y = (ctx.curr_col * a.spritesheet.mask.h); + + if (!ctx.looping && curr_frame == ctx.cycle_start && last_frame == total_frames - 1) { + a.active = false; + } } } diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h index f8179a9..e8a5158 100644 --- a/src/crepe/system/AnimatorSystem.h +++ b/src/crepe/system/AnimatorSystem.h @@ -1,9 +1,7 @@ #pragma once #include "System.h" - -//TODO: -// control if flip works with animation system +#include "api/LoopTimer.h" namespace crepe { @@ -26,6 +24,9 @@ public: * looping). */ void update() override; + +private: + LoopTimer & timer = LoopTimer::get_instance(); }; } // namespace crepe diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 92dba43..111ad7d 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -21,7 +21,7 @@ void RenderSystem::clear_screen() { this->context.clear_screen(); } void RenderSystem::present_screen() { this->context.present_screen(); } -const Camera & RenderSystem::update_camera() { +SDLContext::CameraValues RenderSystem::update_camera() { ComponentManager & mgr = this->mediator.component_manager; RefVector<Camera> cameras = mgr.get_components_by_type<Camera>(); @@ -32,16 +32,17 @@ const Camera & RenderSystem::update_camera() { if (!cam.active) continue; const Transform & transform = mgr.get_components_by_id<Transform>(cam.game_object_id).front().get(); - this->context.set_camera(cam); - this->cam_pos = transform.position + cam.offset; - return cam; + SDLContext::CameraValues cam_val = this->context.set_camera(cam); + cam_val.cam_pos = transform.position + cam.data.offset; + return cam_val; } throw std::runtime_error("No active cameras in current scene"); } bool sorting_comparison(const Sprite & a, const Sprite & b) { - if (a.sorting_in_layer < b.sorting_in_layer) return true; - if (a.sorting_in_layer == b.sorting_in_layer) return a.order_in_layer < b.order_in_layer; + if (a.data.sorting_in_layer < b.data.sorting_in_layer) return true; + if (a.data.sorting_in_layer == b.data.sorting_in_layer) + return a.data.order_in_layer < b.data.order_in_layer; return false; } @@ -59,7 +60,7 @@ void RenderSystem::update() { this->present_screen(); } -bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam, +bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam, const double & scale) { ComponentManager & mgr = this->mediator.component_manager; @@ -80,7 +81,6 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam, this->context.draw(SDLContext::RenderContext{ .sprite = sprite, .cam = cam, - .cam_pos = this->cam_pos, .pos = p.position, .angle = p.angle, .scale = scale, @@ -89,12 +89,11 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam, } return rendering_particles; } -void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam, +void RenderSystem::render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam, const Transform & tm) { this->context.draw(SDLContext::RenderContext{ .sprite = sprite, .cam = cam, - .cam_pos = this->cam_pos, .pos = tm.position, .angle = tm.rotation, .scale = tm.scale, @@ -103,7 +102,7 @@ void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam, void RenderSystem::render() { ComponentManager & mgr = this->mediator.component_manager; - const Camera & cam = this->update_camera(); + const SDLContext::CameraValues & cam = this->update_camera(); RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>(); RefVector<Sprite> sorted_sprites = this->sort(sprites); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 096d058..eaf1213 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -37,7 +37,7 @@ private: void present_screen(); //! Updates the active camera used for rendering. - const Camera & update_camera(); + SDLContext::CameraValues update_camera(); //! Renders the whole screen void render(); @@ -52,7 +52,8 @@ private: * constructor is now protected i cannot make tmp inside * \return true if particles have been rendered */ - bool render_particle(const Sprite & sprite, const Camera & cam, const double & scale); + bool render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam, + const double & scale); /** * \brief renders a sprite with a Transform component on the screen @@ -60,7 +61,8 @@ private: * \param sprite the sprite component that holds all the data * \param tm the Transform component that holds the position,rotation and scale */ - void render_normal(const Sprite & sprite, const Camera & cam, const Transform & tm); + void render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam, + const Transform & tm); /** * \brief sort a vector sprite objects with @@ -79,9 +81,6 @@ private: private: // FIXME: retrieve sdlcontext via mediator after #PR57 SDLContext & context = SDLContext::get_instance(); - - //! camera postion in the current scene - vec2 cam_pos; }; } // namespace crepe diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 349d11e..07e43a1 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -1,5 +1,7 @@ #include "api/Animator.h" #include "api/Camera.h" +#include "api/LoopManager.h" +#include "api/LoopTimer.h" #include "system/AnimatorSystem.h" #include "system/ParticleSystem.h" #include <SDL2/SDL_timer.h> @@ -16,28 +18,10 @@ #include <crepe/system/RenderSystem.h> #include <crepe/types.h> -#include <chrono> - using namespace crepe; using namespace std; -int main(int argc, char * argv[]) { - ComponentManager mgr; - GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1); - RenderSystem sys{mgr}; - ParticleSystem psys{mgr}; - AnimatorSystem asys{mgr}; - - Color color(255, 255, 255, 100); - - auto img = Texture("asset/texture/test_ap43.png"); - Sprite & test_sprite = game_object.add_component<Sprite>( - img, color, Sprite::FlipSettings{true, true}, 1, 1, 500); - - //game_object.add_component<Animator>(test_sprite, 4, 1, 0).active = true; - game_object.add_component<Animator>(test_sprite, 1, 1, 0).active = true; - - /* +/* auto & test = game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ .position = {0, 0}, .max_particles = 10, @@ -59,8 +43,47 @@ int main(int argc, char * argv[]) { }); */ - auto & cam = game_object.add_component<Camera>(Color::RED, ivec2{1080, 720}, - vec2{2000, 2000}, 1.0f); +class TestScene : public Scene { +public: + void load_scene() { + ComponentManager & mgr = this->component_manager; + GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1); + + Color color(255, 255, 255, 255); + + auto img = Texture("asset/spritesheet/pokemon_spritesheet.png"); + + Sprite & test_sprite = game_object.add_component<Sprite>( + img, Sprite::Data{ + .color = color, + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 2, + .order_in_layer = 2, + .size = {0, 100}, + .angle_offset = 0, + }); + + auto & anim = game_object.add_component<Animator>(test_sprite, 4, 4, + Animator::Data{ + .fps = 1, + .looping = false, + }); + anim.set_anim(2); + anim.active = false; + + auto & cam = game_object.add_component<Camera>(ivec2{1280, 720}, vec2{400, 400}, + Camera::Data{ + .bg_color = Color::WHITE, + }); + } + + string get_name() const { return "TestScene"; }; +}; + +int main(int argc, char * argv[]) { + LoopManager engine; + engine.add_scene<TestScene>(); + engine.start(); /* game_object @@ -71,13 +94,5 @@ int main(int argc, char * argv[]) { = 6; */ - auto start = std::chrono::steady_clock::now(); - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { - psys.update(); - asys.update(); - sys.update(); - SDL_Delay(10); - } - return 0; } diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index a659fe5..1409c4f 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -32,7 +32,11 @@ public: Color color(0, 0, 0, 0); auto s1 = Texture("asset/texture/img.png"); Sprite & test_sprite = game_object.add_component<Sprite>( - s1, color, Sprite::FlipSettings{true, true}, 1, 1, 100); + s1, Sprite::Data{ + .color = color, + .flip = Sprite::FlipSettings{true, true}, + .size = {10, 10}, + }); game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ .position = {0, 0}, diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp index c105dcb..4868ddd 100644 --- a/src/test/RenderSystemTest.cpp +++ b/src/test/RenderSystemTest.cpp @@ -35,28 +35,50 @@ public: auto s2 = Texture("asset/texture/img.png"); auto s3 = Texture("asset/texture/img.png"); auto s4 = Texture("asset/texture/img.png"); - auto & sprite1 = entity1.add_component<Sprite>( - s1, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 5, 5, 100); - ASSERT_NE(sprite1.sprite_image.texture.get(), nullptr); - EXPECT_EQ(sprite1.order_in_layer, 5); - EXPECT_EQ(sprite1.sorting_in_layer, 5); - auto & sprite2 = entity2.add_component<Sprite>( - s2, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 2, 1, 100); - ASSERT_NE(sprite2.sprite_image.texture.get(), nullptr); - EXPECT_EQ(sprite2.sorting_in_layer, 2); - EXPECT_EQ(sprite2.order_in_layer, 1); - - auto & sprite3 = entity3.add_component<Sprite>( - s3, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 2, 100); - ASSERT_NE(sprite3.sprite_image.texture.get(), nullptr); - EXPECT_EQ(sprite3.sorting_in_layer, 1); - EXPECT_EQ(sprite3.order_in_layer, 2); - - auto & sprite4 = entity4.add_component<Sprite>( - s4, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 1, 100); - ASSERT_NE(sprite4.sprite_image.texture.get(), nullptr); - EXPECT_EQ(sprite4.sorting_in_layer, 1); - EXPECT_EQ(sprite4.order_in_layer, 1); + auto & sprite1 + = entity1.add_component<Sprite>(s1, Sprite::Data{ + .color = Color(0, 0, 0, 0), + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 5, + .order_in_layer = 5, + .size = {10, 10}, + }); + + ASSERT_NE(sprite1.texture.texture.get(), nullptr); + EXPECT_EQ(sprite1.data.order_in_layer, 5); + EXPECT_EQ(sprite1.data.sorting_in_layer, 5); + auto & sprite2 + = entity2.add_component<Sprite>(s2, Sprite::Data{ + .color = Color(0, 0, 0, 0), + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 2, + .order_in_layer = 1, + }); + ASSERT_NE(sprite2.texture.texture.get(), nullptr); + EXPECT_EQ(sprite2.data.sorting_in_layer, 2); + EXPECT_EQ(sprite2.data.order_in_layer, 1); + + auto & sprite3 + = entity3.add_component<Sprite>(s3, Sprite::Data{ + .color = Color(0, 0, 0, 0), + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 1, + .order_in_layer = 2, + }); + ASSERT_NE(sprite3.texture.texture.get(), nullptr); + EXPECT_EQ(sprite3.data.sorting_in_layer, 1); + EXPECT_EQ(sprite3.data.order_in_layer, 2); + + auto & sprite4 + = entity4.add_component<Sprite>(s4, Sprite::Data{ + .color = Color(0, 0, 0, 0), + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 1, + .order_in_layer = 1, + }); + ASSERT_NE(sprite4.texture.texture.get(), nullptr); + EXPECT_EQ(sprite4.data.sorting_in_layer, 1); + EXPECT_EQ(sprite4.data.order_in_layer, 1); } }; @@ -66,8 +88,13 @@ TEST_F(RenderSystemTest, expected_throws) { // no texture img EXPECT_ANY_THROW({ auto test = Texture(""); - entity1.add_component<Sprite>(test, Color(0, 0, 0, 0), - Sprite::FlipSettings{false, false}, 1, 1, 100); + auto & sprite1 = entity1.add_component<Sprite>( + test, Sprite::Data{ + .color = Color(0, 0, 0, 0), + .flip = Sprite::FlipSettings{false, false}, + .sorting_in_layer = 1, + .order_in_layer = 1, + }); }); // No camera @@ -89,32 +116,35 @@ TEST_F(RenderSystemTest, sorting_sprites) { // 3. sorting_in_layer: 2, order_in_layer: 1 (entity2) // 4. sorting_in_layer: 5, order_in_layer: 5 (entity1) - EXPECT_EQ(sorted_sprites[0].get().sorting_in_layer, 1); - EXPECT_EQ(sorted_sprites[0].get().order_in_layer, 1); + EXPECT_EQ(sorted_sprites[0].get().data.sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[0].get().data.order_in_layer, 1); - EXPECT_EQ(sorted_sprites[1].get().sorting_in_layer, 1); - EXPECT_EQ(sorted_sprites[1].get().order_in_layer, 2); + EXPECT_EQ(sorted_sprites[1].get().data.sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[1].get().data.order_in_layer, 2); - EXPECT_EQ(sorted_sprites[2].get().sorting_in_layer, 2); - EXPECT_EQ(sorted_sprites[2].get().order_in_layer, 1); + EXPECT_EQ(sorted_sprites[2].get().data.sorting_in_layer, 2); + EXPECT_EQ(sorted_sprites[2].get().data.order_in_layer, 1); - EXPECT_EQ(sorted_sprites[3].get().sorting_in_layer, 5); - EXPECT_EQ(sorted_sprites[3].get().order_in_layer, 5); + EXPECT_EQ(sorted_sprites[3].get().data.sorting_in_layer, 5); + EXPECT_EQ(sorted_sprites[3].get().data.order_in_layer, 5); for (size_t i = 1; i < sorted_sprites.size(); ++i) { const Sprite & prev = sorted_sprites[i - 1].get(); const Sprite & curr = sorted_sprites[i].get(); - if (prev.sorting_in_layer == curr.sorting_in_layer) { - EXPECT_LE(prev.order_in_layer, curr.order_in_layer); + if (prev.data.sorting_in_layer == curr.data.sorting_in_layer) { + EXPECT_LE(prev.data.order_in_layer, curr.data.order_in_layer); } else { - EXPECT_LE(prev.sorting_in_layer, curr.sorting_in_layer); + EXPECT_LE(prev.data.sorting_in_layer, curr.data.sorting_in_layer); } } } TEST_F(RenderSystemTest, Update) { - entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); + entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, + .screen = ivec2{1080, 720}, + .viewport_size = vec2{2000, 2000}, + .zoom = 1.0f}); { vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>(); ASSERT_EQ(sprites.size(), 4); @@ -142,7 +172,10 @@ TEST_F(RenderSystemTest, Camera) { EXPECT_NE(cameras.size(), 1); } { - entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); + entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, + .screen = ivec2{1080, 720}, + .viewport_size = vec2{2000, 2000}, + .zoom = 1.0f}); auto cameras = this->mgr.get_components_by_type<Camera>(); EXPECT_EQ(cameras.size(), 1); } @@ -150,18 +183,21 @@ TEST_F(RenderSystemTest, Camera) { //TODO improve with newer version } TEST_F(RenderSystemTest, Color) { - entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); + entity1.add_component<Camera>(Camera::Data{.bg_color = Color::WHITE, + .screen = ivec2{1080, 720}, + .viewport_size = vec2{2000, 2000}, + .zoom = 1.0f}); auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get(); - ASSERT_NE(sprite.sprite_image.texture.get(), nullptr); + ASSERT_NE(sprite.texture.texture.get(), nullptr); - sprite.color = Color::GREEN; - EXPECT_EQ(sprite.color.r, Color::GREEN.r); - EXPECT_EQ(sprite.color.g, Color::GREEN.g); - EXPECT_EQ(sprite.color.b, Color::GREEN.b); - EXPECT_EQ(sprite.color.a, Color::GREEN.a); + sprite.data.color = Color::GREEN; + EXPECT_EQ(sprite.data.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.data.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.data.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.data.color.a, Color::GREEN.a); this->sys.update(); - EXPECT_EQ(sprite.color.r, Color::GREEN.r); - EXPECT_EQ(sprite.color.g, Color::GREEN.g); - EXPECT_EQ(sprite.color.b, Color::GREEN.b); - EXPECT_EQ(sprite.color.a, Color::GREEN.a); + EXPECT_EQ(sprite.data.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.data.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.data.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.data.color.a, Color::GREEN.a); } |