2020-09-10 14:50:36 +00:00
|
|
|
// TODO mutex guard instead of lock/unlock
|
2020-09-26 18:23:03 +00:00
|
|
|
// TODO virtual destructors
|
2020-07-26 20:37:20 +00:00
|
|
|
#ifndef SDLPP_HPP
|
|
|
|
#define SDLPP_HPP
|
|
|
|
|
2020-09-12 11:09:20 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include "SDL2/SDL.h"
|
|
|
|
#include "SDL2/SDL_image.h"
|
|
|
|
#include "SDL2/SDL_ttf.h"
|
|
|
|
#else
|
2020-07-26 20:37:20 +00:00
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <SDL2/SDL_image.h>
|
2020-08-22 11:17:56 +00:00
|
|
|
#include <SDL2/SDL_ttf.h>
|
2020-09-12 11:09:20 +00:00
|
|
|
#endif // UNIX
|
2020-08-21 19:40:15 +00:00
|
|
|
#include <algorithm>
|
2020-08-21 18:53:21 +00:00
|
|
|
#include <cmath>
|
2020-07-26 20:37:20 +00:00
|
|
|
#include <iostream>
|
2020-07-28 17:35:31 +00:00
|
|
|
#include <limits>
|
2020-07-26 20:37:20 +00:00
|
|
|
#include <memory>
|
2020-08-21 19:40:15 +00:00
|
|
|
#include <mutex>
|
2020-08-22 23:08:10 +00:00
|
|
|
#include <unordered_set>
|
2020-07-26 20:37:20 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2020-08-23 07:47:31 +00:00
|
|
|
#define SDLPP_TEXT_LEFT 0x0001
|
|
|
|
#define SDLPP_TEXT_RIGHT 0x0002
|
|
|
|
#define SDLPP_TEXT_CENTER 0x0004
|
|
|
|
#define SDLPP_TEXT_TOP 0x0008
|
|
|
|
#define SDLPP_TEXT_BOTTOM 0x0010
|
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
namespace SDLPP {
|
|
|
|
|
2020-08-23 07:50:05 +00:00
|
|
|
int hex2num( char c );
|
2020-08-21 16:32:15 +00:00
|
|
|
|
2020-08-23 07:50:05 +00:00
|
|
|
std::tuple< int, int, int, int > getColorsHEX( const std::string &color );
|
|
|
|
SDL_Color getSDLColorHEX( const std::string &color );
|
|
|
|
std::tuple< int, int, int, int > getColorsSDLColor( const SDL_Color &color );
|
|
|
|
SDL_Color getSDLColorTuple( const std::tuple< int, int, int, int > &tuple );
|
2020-08-21 16:32:15 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
class Window {
|
|
|
|
public:
|
2020-08-23 07:50:05 +00:00
|
|
|
Window()
|
|
|
|
: Window( "SDL Window", 640, 480, SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
SDL_WINDOWPOS_UNDEFINED ) {}
|
|
|
|
Window( const std::string &window_name )
|
|
|
|
: Window( window_name, 640, 480, SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
SDL_WINDOWPOS_UNDEFINED ) {}
|
|
|
|
Window( const std::string &window_name, uint32_t width, uint32_t height )
|
|
|
|
: Window( window_name, width, height, SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
SDL_WINDOWPOS_UNDEFINED ) {}
|
|
|
|
Window( const std::string &window_name, uint32_t width, uint32_t height,
|
|
|
|
uint32_t posx, uint32_t posy ) {
|
|
|
|
window = SDL_CreateWindow( window_name.c_str(), posx, posy, width,
|
|
|
|
height, SDL_WINDOW_SHOWN );
|
|
|
|
if ( window == NULL ) {
|
|
|
|
std::cerr << "SDL could not create a window! SDL_Error: "
|
|
|
|
<< SDL_GetError() << std::endl;
|
2020-07-26 20:37:20 +00:00
|
|
|
throw "Couldn't create window";
|
|
|
|
}
|
|
|
|
}
|
2020-08-24 20:14:26 +00:00
|
|
|
void setResizable(bool resizable) {
|
|
|
|
SDL_SetWindowResizable(window, resizable ? SDL_TRUE : SDL_FALSE);
|
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
~Window() {
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_DestroyWindow( window );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
SDL_Window *getWindowPtr() {
|
|
|
|
return window;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
private:
|
|
|
|
SDL_Window *window = NULL;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Renderer {
|
|
|
|
public:
|
|
|
|
Renderer() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
Renderer( Window &window ) {
|
|
|
|
renderer = SDL_CreateRenderer( window.getWindowPtr(), -1,
|
|
|
|
SDL_RENDERER_ACCELERATED );
|
|
|
|
if ( renderer == NULL ) {
|
|
|
|
std::cerr << "SDL could not create a renderer! SDL_Error: "
|
|
|
|
<< SDL_GetError();
|
2020-07-26 20:37:20 +00:00
|
|
|
throw "Couldn't create renderer";
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
~Renderer() {
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_DestroyRenderer( renderer );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
SDL_Renderer *getRendererPtr() {
|
|
|
|
return renderer;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::pair< int, int > getDimensions() const {
|
2020-07-26 20:37:20 +00:00
|
|
|
int width = 0, height = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_GetRendererOutputSize( renderer, &width, &height );
|
|
|
|
return { width, height };
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-07-28 17:35:31 +00:00
|
|
|
int getWidth() const {
|
2020-07-28 12:46:48 +00:00
|
|
|
return getDimensions().first;
|
|
|
|
}
|
2020-07-28 17:35:31 +00:00
|
|
|
int getHeight() const {
|
2020-07-28 12:46:48 +00:00
|
|
|
return getDimensions().second;
|
|
|
|
}
|
2020-07-28 17:35:31 +00:00
|
|
|
int getSmallerSide() const {
|
2020-07-28 12:46:48 +00:00
|
|
|
auto dimensions = getDimensions();
|
2020-08-23 07:50:05 +00:00
|
|
|
return dimensions.first < dimensions.second ? dimensions.first
|
|
|
|
: dimensions.second;
|
2020-07-28 12:46:48 +00:00
|
|
|
}
|
2020-07-28 17:35:31 +00:00
|
|
|
int getLargerSide() const {
|
2020-07-28 12:46:48 +00:00
|
|
|
auto dimensions = getDimensions();
|
2020-08-23 07:50:05 +00:00
|
|
|
return dimensions.first > dimensions.second ? dimensions.first
|
|
|
|
: dimensions.second;
|
2020-07-28 12:46:48 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setBlendMode( SDL_BlendMode blendMode ) {
|
|
|
|
SDL_SetRenderDrawBlendMode( renderer, blendMode );
|
2020-08-21 16:32:15 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setRenderColiders( bool render ) {
|
2020-08-21 16:32:15 +00:00
|
|
|
render_coliders = render;
|
|
|
|
}
|
|
|
|
bool getRenderColiders() {
|
|
|
|
return render_coliders;
|
|
|
|
}
|
2020-09-12 07:36:08 +00:00
|
|
|
void clearRenderer() {
|
|
|
|
SDL_RenderClear( getRendererPtr() );
|
|
|
|
}
|
|
|
|
void presentRenderer() {
|
|
|
|
SDL_RenderPresent( getRendererPtr() );
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
private:
|
|
|
|
SDL_Renderer *renderer = NULL;
|
2020-08-21 16:32:15 +00:00
|
|
|
bool render_coliders = false;
|
2020-07-26 20:37:20 +00:00
|
|
|
};
|
|
|
|
|
2020-08-22 11:17:56 +00:00
|
|
|
class Font {
|
|
|
|
public:
|
|
|
|
Font() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
Font( const std::string &font, int size ) {
|
|
|
|
font_ptr = TTF_OpenFont( font.c_str(), size );
|
|
|
|
if ( font_ptr == NULL ) {
|
|
|
|
std::cerr << "Unable to load font '" << font
|
|
|
|
<< "': TTF Error: " << TTF_GetError() << std::endl;
|
2020-08-22 23:14:59 +00:00
|
|
|
throw "TTF_OpenFont error";
|
|
|
|
}
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
~Font() {
|
|
|
|
TTF_CloseFont( font_ptr );
|
|
|
|
}
|
|
|
|
const TTF_Font *getFont() const {
|
|
|
|
return font_ptr;
|
|
|
|
}
|
|
|
|
TTF_Font *getFont() {
|
|
|
|
return font_ptr;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setOutline( int size ) {
|
|
|
|
TTF_SetFontOutline( font_ptr, size );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
int getOutline() {
|
2020-08-23 07:50:05 +00:00
|
|
|
return TTF_GetFontOutline( font_ptr );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setStyle( int style ) {
|
|
|
|
TTF_SetFontStyle( font_ptr, style );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setHinting( int hinting ) {
|
|
|
|
TTF_SetFontHinting( font_ptr, hinting );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-08-22 11:17:56 +00:00
|
|
|
private:
|
|
|
|
TTF_Font *font_ptr;
|
|
|
|
};
|
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
class Texture {
|
|
|
|
public:
|
|
|
|
Texture() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
Texture( std::shared_ptr< Renderer > &renderer,
|
|
|
|
const std::string &img_path )
|
|
|
|
: Texture( renderer, img_path, "" ) {}
|
|
|
|
Texture( std::shared_ptr< Renderer > &renderer, const std::string &img_path,
|
|
|
|
const std::string &color_key ) {
|
|
|
|
SDL_Surface *surface = IMG_Load( img_path.c_str() );
|
|
|
|
if ( surface == NULL ) {
|
|
|
|
std::cerr << "Unable to load image '" << img_path
|
|
|
|
<< "': IMG Error: " << IMG_GetError() << std::endl;
|
2020-07-26 20:37:20 +00:00
|
|
|
throw "IMG_Load error";
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !color_key.empty() ) {
|
|
|
|
auto colors = getColorsHEX( color_key );
|
|
|
|
SDL_SetColorKey( surface, SDL_TRUE,
|
|
|
|
SDL_MapRGB( surface->format,
|
|
|
|
std::get< 0 >( colors ),
|
|
|
|
std::get< 1 >( colors ),
|
|
|
|
std::get< 2 >( colors ) ) );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
setTextureFromSurface( renderer, surface );
|
|
|
|
}
|
|
|
|
Texture( std::shared_ptr< Renderer > &renderer, Font &font,
|
|
|
|
const std::string &text, const std::string &color = "FFFFFF",
|
|
|
|
const std::string &outline_color = "000000",
|
|
|
|
const int outline_size = -1 ) {
|
|
|
|
if ( outline_size != -1 ) {
|
|
|
|
font.setOutline( outline_size );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-22 11:17:56 +00:00
|
|
|
int og_outline = 0;
|
|
|
|
SDL_Surface *bg_surface = NULL;
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( ( og_outline = font.getOutline() ) != 0 ) {
|
|
|
|
bg_surface = TTF_RenderUTF8_Blended(
|
|
|
|
font.getFont(), text.c_str(), getSDLColorHEX( outline_color ) );
|
|
|
|
if ( bg_surface == NULL ) {
|
|
|
|
std::cerr << "Unable to render text '" << text
|
|
|
|
<< "': TTF Error: " << TTF_GetError() << std::endl;
|
2020-08-22 11:17:56 +00:00
|
|
|
throw "TTF_RenderUTF8_Shaded error";
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
font.setOutline( 0 );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_Surface *surface = TTF_RenderUTF8_Blended(
|
|
|
|
font.getFont(), text.c_str(), getSDLColorHEX( color ) );
|
|
|
|
if ( surface == NULL ) {
|
|
|
|
std::cerr << "Unable to render text '" << text
|
|
|
|
<< "': TTF Error: " << TTF_GetError() << std::endl;
|
2020-08-22 11:17:56 +00:00
|
|
|
throw "TTF_RenderUTF8_Shaded error";
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( og_outline != 0 ) {
|
|
|
|
SDL_Rect rect = { og_outline, og_outline, surface->w, surface->h };
|
|
|
|
SDL_SetSurfaceBlendMode( surface, SDL_BLENDMODE_BLEND );
|
|
|
|
SDL_BlitSurface( surface, NULL, bg_surface, &rect );
|
|
|
|
SDL_FreeSurface( surface );
|
2020-08-22 11:17:56 +00:00
|
|
|
surface = bg_surface;
|
|
|
|
bg_surface = NULL;
|
2020-08-23 07:50:05 +00:00
|
|
|
font.setOutline( og_outline );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
setTextureFromSurface( renderer, surface );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
~Texture() {
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_DestroyTexture( texture );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
SDL_Texture *getTexturePtr() {
|
|
|
|
return texture;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
private:
|
2020-08-23 07:50:05 +00:00
|
|
|
void setTextureFromSurface( std::shared_ptr< Renderer > &renderer,
|
|
|
|
SDL_Surface *surface ) {
|
|
|
|
texture =
|
|
|
|
SDL_CreateTextureFromSurface( renderer->getRendererPtr(), surface );
|
|
|
|
if ( texture == NULL ) {
|
|
|
|
std::cerr << "Unable to create texture from surface! SDL Error: "
|
|
|
|
<< SDL_GetError() << std::endl;
|
2020-08-22 11:17:56 +00:00
|
|
|
throw "Texture error";
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_FreeSurface( surface );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
SDL_Texture *texture = NULL;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CollisionPolygon {
|
|
|
|
public:
|
2020-08-23 07:50:05 +00:00
|
|
|
CollisionPolygon( double x, double y ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
original_x = x;
|
|
|
|
original_y = y;
|
|
|
|
position_x = 0;
|
|
|
|
position_y = 0;
|
|
|
|
}
|
|
|
|
virtual ~CollisionPolygon() {}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual bool colidesWith( const CollisionPolygon &other ) const = 0;
|
2020-07-26 20:37:20 +00:00
|
|
|
virtual bool isCircle() const = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual bool isInfinite() const {
|
|
|
|
return infinite;
|
|
|
|
}
|
|
|
|
virtual void setInfinite() {
|
|
|
|
infinite = true;
|
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
virtual int topmost() const = 0;
|
|
|
|
virtual int bottommost() const = 0;
|
|
|
|
virtual int leftmost() const = 0;
|
|
|
|
virtual int rightmost() const = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void updateCollision( int x, int y, int w, int h ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
position_x = original_x * w + x;
|
|
|
|
position_y = original_y * h + y;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void render( Renderer &renderer,
|
|
|
|
const std::tuple< int, int, int, int > &color ) = 0;
|
|
|
|
virtual void render( Renderer &renderer ) = 0;
|
2020-07-26 20:37:20 +00:00
|
|
|
int getX() const {
|
|
|
|
return position_x;
|
|
|
|
}
|
|
|
|
int getY() const {
|
|
|
|
return position_y;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setColor( const std::string &color ) {
|
|
|
|
sdl_color = getSDLColorHEX( color );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setOutlineColor( const std::string &color ) {
|
|
|
|
sdl_outline = getSDLColorHEX( color );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
protected:
|
|
|
|
double original_x;
|
|
|
|
double original_y;
|
|
|
|
int position_x;
|
|
|
|
int position_y;
|
2020-07-28 17:35:31 +00:00
|
|
|
bool infinite = false;
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_Color sdl_color = { 0, 0, 0, 0 };
|
|
|
|
SDL_Color sdl_outline = { 0, 0, 0, 0 };
|
2020-07-26 20:37:20 +00:00
|
|
|
};
|
|
|
|
|
2020-08-21 19:40:15 +00:00
|
|
|
class Scene;
|
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
class RenderObject {
|
|
|
|
public:
|
2020-09-10 14:50:36 +00:00
|
|
|
RenderObject( const std::shared_ptr< Renderer > &r ) : renderer( r ) {}
|
2020-07-26 20:37:20 +00:00
|
|
|
virtual ~RenderObject() {}
|
|
|
|
virtual void render() = 0;
|
|
|
|
virtual int leftmost() = 0;
|
|
|
|
virtual int topmost() = 0;
|
2020-07-28 17:35:31 +00:00
|
|
|
virtual int rightmost() = 0;
|
|
|
|
virtual int bottommost() = 0;
|
2020-07-26 20:37:20 +00:00
|
|
|
virtual int collisionPushX() = 0;
|
|
|
|
virtual int collisionPushY() = 0;
|
|
|
|
virtual int collisionWidth() = 0;
|
|
|
|
virtual int collisionHeight() = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void specialAction( int code ) = 0;
|
|
|
|
virtual std::pair< std::pair< double, double >,
|
|
|
|
std::pair< double, double > >
|
2020-09-10 14:50:36 +00:00
|
|
|
getDoubleRect() const = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setPos( double x, double y ) = 0;
|
2020-09-10 14:50:36 +00:00
|
|
|
virtual void setPos(const std::pair<double, double> &pos) = 0;
|
2020-08-24 14:33:53 +00:00
|
|
|
virtual std::pair< double, double > getPos() const = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
bool colidesWith( const RenderObject &other ) const {
|
|
|
|
if ( !hasCollisions() || !other.hasCollisions() || getHidden() ||
|
|
|
|
other.getHidden() ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
for ( const auto &x : collisions ) {
|
|
|
|
for ( const auto &y : other.getCollisions() ) {
|
|
|
|
if ( x->colidesWith( *y ) )
|
2020-07-26 20:37:20 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
template < class T > void addCollision( const T &p ) {
|
|
|
|
collisions.push_back( std::make_shared< T >( p ) );
|
|
|
|
collisions.back()->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(),
|
|
|
|
collisionHeight() );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
bool hasCollisions() const {
|
|
|
|
return !collisions.empty();
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
const std::vector< std::shared_ptr< CollisionPolygon > > &
|
|
|
|
getCollisions() const {
|
2020-07-26 20:37:20 +00:00
|
|
|
return collisions;
|
|
|
|
}
|
2020-09-10 14:50:36 +00:00
|
|
|
virtual void setTexture( const std::shared_ptr< Texture > &t ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
texture = t;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setTexture( const std::string &img_path ) {
|
|
|
|
texture = std::make_shared< Texture >( renderer, img_path );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setTexture( Font &font, const std::string &text,
|
|
|
|
const std::string &color = "FFFFFF",
|
|
|
|
const std::string &outline_color = "000000",
|
|
|
|
int outline_size = -1 ) {
|
|
|
|
texture = std::make_shared< Texture >( renderer, font, text, color,
|
|
|
|
outline_color, outline_size );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setColor( const std::string &color ) = 0;
|
|
|
|
virtual void setOutlineColor( const std::string &color ) = 0;
|
2020-08-22 12:29:39 +00:00
|
|
|
virtual void unsetTexture() {
|
|
|
|
texture.reset();
|
|
|
|
}
|
|
|
|
virtual void unsetColor() {
|
|
|
|
polygon.reset();
|
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
// per second, relative to window width
|
2020-08-23 07:50:05 +00:00
|
|
|
void setMovementSpeed( double speed ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
movementSpeed = speed;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void addMovement( int x, int y ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
movementDirection.first += x;
|
|
|
|
movementDirection.second += y;
|
|
|
|
}
|
2020-08-22 12:13:28 +00:00
|
|
|
void resetMovementX() {
|
|
|
|
movementDirection.first = 0;
|
|
|
|
}
|
|
|
|
void resetMovementY() {
|
|
|
|
movementDirection.second = 0;
|
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
void clearColided() {
|
|
|
|
colidedWith.clear();
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void addColided( std::shared_ptr< RenderObject > &obj ) {
|
|
|
|
colidedWith.push_back( obj );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > &getColidedWith() {
|
2020-07-26 20:37:20 +00:00
|
|
|
return colidedWith;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setId( uint64_t input_id ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
id = input_id;
|
|
|
|
}
|
|
|
|
uint64_t getId() {
|
|
|
|
return id;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setHidden( bool hid ) {
|
2020-08-21 16:32:15 +00:00
|
|
|
hidden = hid;
|
|
|
|
}
|
2020-08-21 16:54:42 +00:00
|
|
|
bool getHidden() const {
|
2020-08-21 16:32:15 +00:00
|
|
|
return hidden;
|
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
void destroy() {
|
2020-08-23 07:50:05 +00:00
|
|
|
setHidden( true );
|
2020-08-21 19:40:15 +00:00
|
|
|
kill = true;
|
|
|
|
}
|
|
|
|
bool getKilled() {
|
|
|
|
return kill;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setColiderColor( const std::string &color ) {
|
|
|
|
colider_color = getColorsHEX( color );
|
2020-08-21 16:32:15 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void move( int ticks ) = 0;
|
|
|
|
virtual void custom_move( int ticks ) = 0;
|
2020-07-26 20:37:20 +00:00
|
|
|
virtual void updateSizeAndPosition() = 0;
|
2020-07-28 17:35:31 +00:00
|
|
|
virtual SDL_Rect getRect() = 0;
|
2020-08-24 16:21:03 +00:00
|
|
|
void setPermanent( bool perm = true ) {
|
2020-08-22 11:17:56 +00:00
|
|
|
permanent = perm;
|
2020-08-24 16:21:03 +00:00
|
|
|
setStatic(perm);
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
bool getPermanent() const {
|
|
|
|
return permanent;
|
|
|
|
}
|
2020-08-22 12:13:28 +00:00
|
|
|
virtual void centerX() = 0;
|
2020-08-24 16:21:03 +00:00
|
|
|
virtual std::shared_ptr<RenderObject> copySelf() = 0;
|
|
|
|
bool isStatic() {
|
|
|
|
return is_static;
|
|
|
|
}
|
|
|
|
void setStatic(bool stat = true) {
|
|
|
|
is_static = stat;
|
|
|
|
}
|
2020-09-10 14:50:36 +00:00
|
|
|
std::shared_ptr<Renderer> getRenderer() const {
|
|
|
|
return renderer;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
protected:
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< CollisionPolygon > > collisions;
|
|
|
|
std::shared_ptr< Texture > texture;
|
|
|
|
std::shared_ptr< Renderer > renderer;
|
|
|
|
std::shared_ptr< CollisionPolygon > polygon;
|
2020-09-11 19:34:43 +00:00
|
|
|
double movementSpeed = 0;
|
|
|
|
std::pair< int, int > movementDirection = {0,0};
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > colidedWith;
|
2020-09-11 19:34:43 +00:00
|
|
|
uint64_t id = -1;
|
2020-08-21 16:32:15 +00:00
|
|
|
bool hidden = false;
|
2020-08-21 19:40:15 +00:00
|
|
|
bool kill = false;
|
2020-08-23 07:50:05 +00:00
|
|
|
std::tuple< int, int, int, int > colider_color = { 0x00, 0xFF, 0xFF, 0xFF };
|
2020-09-11 19:34:43 +00:00
|
|
|
uint64_t scene_id = -1;
|
2020-08-22 11:17:56 +00:00
|
|
|
bool permanent = false;
|
2020-08-24 16:21:03 +00:00
|
|
|
bool is_static = true;
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-08-21 19:40:15 +00:00
|
|
|
private:
|
2020-08-23 07:50:05 +00:00
|
|
|
void setSceneID( int id ) {
|
2020-08-21 19:40:15 +00:00
|
|
|
scene_id = id;
|
|
|
|
}
|
|
|
|
friend Scene;
|
2020-07-26 20:37:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Scene {
|
|
|
|
public:
|
2020-08-23 07:50:05 +00:00
|
|
|
Scene( std::shared_ptr< Renderer > &r ) : renderer( r ) {
|
|
|
|
SDL_SetRenderDrawColor( renderer->getRendererPtr(), 0xFF, 0xFF, 0xFF,
|
|
|
|
0xFF );
|
2020-07-26 20:37:20 +00:00
|
|
|
prev_ticks = SDL_GetTicks();
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void addObject( const std::shared_ptr< RenderObject > &obj ) {
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.lock();
|
2020-08-24 16:21:03 +00:00
|
|
|
render_objects.push_back( obj );
|
2020-08-23 07:50:05 +00:00
|
|
|
obj->setSceneID( ++max_object_id );
|
|
|
|
if ( obj->hasCollisions() ) {
|
2020-08-24 16:21:03 +00:00
|
|
|
collision_objects.push_back( obj );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-07-28 17:35:31 +00:00
|
|
|
|
2020-08-24 16:21:03 +00:00
|
|
|
if ( render_objects.size() == 1 ) {
|
2020-07-28 17:35:31 +00:00
|
|
|
leftmost_obj = obj;
|
|
|
|
rightmost_obj = obj;
|
|
|
|
} else {
|
|
|
|
auto rect = obj->getDoubleRect();
|
|
|
|
auto leftmost_rect = leftmost_obj->getDoubleRect();
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( rect.first.first < leftmost_rect.first.first )
|
2020-07-28 17:35:31 +00:00
|
|
|
leftmost_obj = obj;
|
|
|
|
auto rightmost_rect = rightmost_obj->getDoubleRect();
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( rect.first.first + rect.second.first >
|
|
|
|
rightmost_rect.first.first + rightmost_rect.second.first )
|
2020-07-28 17:35:31 +00:00
|
|
|
rightmost_obj = obj;
|
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-09-10 14:50:36 +00:00
|
|
|
void setZIndex( const std::shared_ptr< RenderObject > &obj, int index ) {
|
|
|
|
std::lock_guard<std::mutex> guard(render_mutex);
|
|
|
|
int original_index = 0;
|
|
|
|
for(long unsigned int i = 0; i < render_objects.size(); i++) {
|
|
|
|
if(render_objects[i] == obj) {
|
|
|
|
original_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(original_index == index)
|
|
|
|
return;
|
|
|
|
if(original_index > index)
|
|
|
|
original_index++;
|
|
|
|
render_objects.insert(render_objects.begin() + index, obj);
|
|
|
|
render_objects.erase(render_objects.begin() + original_index);
|
|
|
|
}
|
|
|
|
void moveDownZ( const std::shared_ptr<RenderObject> &obj ) {
|
|
|
|
moveZ(obj, -1);
|
|
|
|
}
|
|
|
|
void moveUpZ( const std::shared_ptr<RenderObject> &obj ) {
|
|
|
|
moveZ(obj, 1);
|
|
|
|
}
|
|
|
|
void moveZ( const std::shared_ptr<RenderObject> &obj, int addition ) {
|
|
|
|
int original_index = 0;
|
|
|
|
for(long unsigned int i = 0; i < render_objects.size(); i++) {
|
|
|
|
if(render_objects[i] == obj) {
|
|
|
|
original_index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::iter_swap(render_objects.begin() + original_index, render_objects.begin() + original_index + addition);
|
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
//TODO addCollision
|
2020-08-23 07:50:05 +00:00
|
|
|
std::shared_ptr< RenderObject > getObject( int index ) {
|
2020-08-24 16:21:03 +00:00
|
|
|
return render_objects[index];
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > getObjects() {
|
2020-08-24 16:21:03 +00:00
|
|
|
return render_objects;
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-09-11 19:34:43 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > getObjects(const std::unordered_set< int > &objectIDs) {
|
|
|
|
std::vector< std::shared_ptr< RenderObject > > ret{};
|
|
|
|
for ( const auto &x : render_objects ) {
|
2020-09-29 16:33:50 +00:00
|
|
|
// check if object exists because of possible race condition
|
|
|
|
if ( x && objectIDs.find( x->getId() ) != objectIDs.end() ) {
|
2020-09-11 19:34:43 +00:00
|
|
|
ret.push_back( x );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
void movement() {
|
2020-08-21 19:40:15 +00:00
|
|
|
checkKilled();
|
|
|
|
render_mutex.lock();
|
2020-07-26 20:37:20 +00:00
|
|
|
int now_ticks = SDL_GetTicks();
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( const auto &x : render_objects ) {
|
2020-08-23 07:50:05 +00:00
|
|
|
x->move( now_ticks - prev_ticks );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
prev_ticks = now_ticks;
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > >
|
|
|
|
getCollisions( RenderObject &r ) {
|
|
|
|
if ( r.getHidden() )
|
2020-08-21 16:54:42 +00:00
|
|
|
return {};
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > ret{};
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( const auto &x : collision_objects ) {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( x->colidesWith( r ) ) {
|
|
|
|
ret.push_back( x );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > >
|
|
|
|
getCollisions( RenderObject &r,
|
|
|
|
const std::unordered_set< int > &objectIDs ) {
|
|
|
|
if ( r.getHidden() )
|
2020-08-22 23:08:10 +00:00
|
|
|
return {};
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > ret{};
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( const auto &x : collision_objects ) {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( objectIDs.find( x->getId() ) != objectIDs.end() &&
|
|
|
|
x->colidesWith( r ) ) {
|
|
|
|
ret.push_back( x );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2020-09-12 07:36:08 +00:00
|
|
|
void renderScene( bool clear_renderer = true ) {
|
2020-08-21 19:40:15 +00:00
|
|
|
checkKilled();
|
|
|
|
render_mutex.lock();
|
2020-09-12 07:36:08 +00:00
|
|
|
if ( clear_renderer )
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_RenderClear( renderer->getRendererPtr() );
|
|
|
|
if ( background && background->getTexturePtr() )
|
|
|
|
SDL_RenderCopy( renderer->getRendererPtr(),
|
|
|
|
background->getTexturePtr(), NULL, NULL );
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( const auto &x : render_objects ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
x->render();
|
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
void presentScene() {
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_RenderPresent( renderer->getRendererPtr() );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setBackground( std::shared_ptr< Texture > bg ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
background = bg;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setBackground( const std::string &img_path ) {
|
|
|
|
background = std::make_shared< Texture >( renderer, img_path );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
void updateSizeAndPosition() {
|
2020-08-21 19:40:15 +00:00
|
|
|
checkKilled();
|
|
|
|
render_mutex.lock();
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( auto &x : render_objects ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
x->updateSizeAndPosition();
|
2020-08-23 07:50:05 +00:00
|
|
|
for ( auto &col : x->getCollisions() ) {
|
|
|
|
col->updateCollision( x->collisionPushX(), x->collisionPushY(),
|
|
|
|
x->collisionWidth(),
|
|
|
|
x->collisionHeight() );
|
2020-08-21 17:49:42 +00:00
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void moveEverything( double x, double y ) {
|
2020-08-21 19:40:15 +00:00
|
|
|
checkKilled();
|
|
|
|
render_mutex.lock();
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( auto &obj : render_objects ) {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( obj->getPermanent() )
|
2020-08-22 23:08:10 +00:00
|
|
|
continue;
|
2020-07-28 17:35:31 +00:00
|
|
|
auto curPos = obj->getDoubleRect();
|
|
|
|
obj->setPos( curPos.first.first + x, curPos.first.second + y );
|
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
2020-07-28 17:35:31 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
const std::shared_ptr< RenderObject > &leftmost() {
|
2020-07-28 17:35:31 +00:00
|
|
|
return leftmost_obj;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
const std::shared_ptr< RenderObject > &rightmost() {
|
2020-07-28 17:35:31 +00:00
|
|
|
return rightmost_obj;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
std::pair< int, int > getDimensions() const {
|
2020-07-28 17:35:31 +00:00
|
|
|
return renderer->getDimensions();
|
|
|
|
}
|
|
|
|
int getWidth() const {
|
|
|
|
return renderer->getWidth();
|
|
|
|
}
|
|
|
|
int getHeight() const {
|
|
|
|
return renderer->getHeight();
|
|
|
|
}
|
2020-08-21 16:32:15 +00:00
|
|
|
Renderer &getRenderer() {
|
|
|
|
return *renderer;
|
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
std::shared_ptr<Renderer> getRendererShared() {
|
|
|
|
return renderer;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setPrevTicks( int ticks ) {
|
2020-08-21 16:54:42 +00:00
|
|
|
prev_ticks = ticks;
|
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
void saveScene() {
|
|
|
|
saved_render_objects.clear();
|
|
|
|
saved_collision_objects.clear();
|
|
|
|
for(auto &obj : render_objects) {
|
|
|
|
if(!obj->isStatic())
|
|
|
|
saved_render_objects.push_back(obj->copySelf());
|
|
|
|
else
|
|
|
|
saved_render_objects.push_back(obj);
|
|
|
|
}
|
|
|
|
for(auto &obj : collision_objects) {
|
|
|
|
if(!obj->isStatic())
|
|
|
|
saved_collision_objects.push_back(obj->copySelf());
|
|
|
|
else
|
|
|
|
saved_collision_objects.push_back(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void resetScene() {
|
|
|
|
render_objects.clear();
|
|
|
|
collision_objects.clear();
|
|
|
|
for(auto &obj : saved_render_objects) {
|
|
|
|
if(!obj->isStatic())
|
|
|
|
render_objects.push_back(obj->copySelf());
|
|
|
|
else
|
|
|
|
render_objects.push_back(obj);
|
|
|
|
}
|
|
|
|
for(auto &obj : saved_collision_objects) {
|
|
|
|
if(!obj->isStatic())
|
|
|
|
collision_objects.push_back(obj->copySelf());
|
|
|
|
else
|
|
|
|
collision_objects.push_back(obj);
|
|
|
|
}
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
private:
|
2020-08-21 19:40:15 +00:00
|
|
|
void checkKilled() {
|
|
|
|
render_mutex.lock();
|
2020-08-23 07:50:05 +00:00
|
|
|
std::vector< int > killed;
|
2020-08-23 13:30:31 +00:00
|
|
|
std::vector< int > killed_collisions;
|
2020-08-24 16:21:03 +00:00
|
|
|
for ( long unsigned int i = 0; i < render_objects.size(); i++ ) {
|
|
|
|
if ( render_objects[i]->getKilled() )
|
2020-08-23 07:50:05 +00:00
|
|
|
killed.push_back( i );
|
2020-08-24 16:21:03 +00:00
|
|
|
if ( i < collision_objects.size() && collision_objects[i]->getKilled() )
|
2020-08-23 13:30:31 +00:00
|
|
|
killed_collisions.push_back( i );
|
2020-08-21 19:40:15 +00:00
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
// reverse so we don't screw up indexing while going thorugh the kill indices
|
2020-08-23 07:50:05 +00:00
|
|
|
std::reverse( killed.begin(), killed.end() );
|
2020-08-23 13:30:31 +00:00
|
|
|
std::reverse( killed_collisions.begin(), killed_collisions.end() );
|
2020-08-23 07:50:05 +00:00
|
|
|
for ( auto &index : killed ) {
|
2020-08-24 16:21:03 +00:00
|
|
|
render_objects.erase( render_objects.begin() + index );
|
2020-08-21 19:40:15 +00:00
|
|
|
}
|
2020-08-23 13:30:31 +00:00
|
|
|
for ( auto &index : killed_collisions ) {
|
2020-08-24 16:21:03 +00:00
|
|
|
collision_objects.erase( collision_objects.begin() + index );
|
2020-08-23 13:30:31 +00:00
|
|
|
}
|
2020-08-21 19:40:15 +00:00
|
|
|
render_mutex.unlock();
|
|
|
|
}
|
|
|
|
|
2020-08-24 16:21:03 +00:00
|
|
|
std::vector< std::shared_ptr< RenderObject > > render_objects;
|
|
|
|
std::vector< std::shared_ptr< RenderObject > > collision_objects;
|
|
|
|
std::vector< std::shared_ptr< RenderObject > > saved_render_objects;
|
|
|
|
std::vector< std::shared_ptr< RenderObject > > saved_collision_objects;
|
2020-08-23 07:50:05 +00:00
|
|
|
std::shared_ptr< Renderer > renderer;
|
|
|
|
std::shared_ptr< Texture > background;
|
2020-07-26 20:37:20 +00:00
|
|
|
int prev_ticks = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
std::shared_ptr< RenderObject > leftmost_obj;
|
|
|
|
std::shared_ptr< RenderObject > rightmost_obj;
|
2020-08-21 19:40:15 +00:00
|
|
|
uint64_t max_object_id = 0;
|
|
|
|
std::mutex render_mutex;
|
2020-07-26 20:37:20 +00:00
|
|
|
};
|
|
|
|
|
2020-08-22 11:17:56 +00:00
|
|
|
class Rect : public CollisionPolygon {
|
|
|
|
public:
|
2020-08-23 07:50:05 +00:00
|
|
|
Rect( double x, double y, double w, double h ) : CollisionPolygon( x, y ) {
|
2020-08-22 11:17:56 +00:00
|
|
|
w_ = w;
|
|
|
|
h_ = h;
|
|
|
|
}
|
|
|
|
virtual ~Rect() {}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual bool colidesWith( const CollisionPolygon &other ) const override;
|
|
|
|
virtual bool isCircle() const override {
|
|
|
|
return false;
|
|
|
|
}
|
2020-08-22 11:17:56 +00:00
|
|
|
virtual int topmost() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return ( !isInfinite() || original_y != -1 ) * getY() +
|
|
|
|
isInfinite() * -1;
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
virtual int bottommost() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return ( !isInfinite() || h_ != -1 ) * ( getY() + pixel_h ) +
|
|
|
|
isInfinite() * -1;
|
2020-08-22 11:17:56 +00:00
|
|
|
};
|
|
|
|
virtual int leftmost() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return ( !isInfinite() || original_x != -1 ) * getX() +
|
|
|
|
isInfinite() * -1;
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
virtual int rightmost() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return ( !isInfinite() || w_ != -1 ) * ( getX() + pixel_w ) +
|
|
|
|
isInfinite() * -1;
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void updateCollision( int x, int y, int w, int h ) override {
|
2020-08-22 11:17:56 +00:00
|
|
|
position_x = original_x * w + x;
|
|
|
|
position_y = original_y * h + y;
|
|
|
|
pixel_w = w_ * w;
|
|
|
|
pixel_h = h_ * h;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void
|
|
|
|
render( Renderer &renderer,
|
|
|
|
const std::tuple< int, int, int, int > &color ) override {
|
2020-08-22 11:17:56 +00:00
|
|
|
auto rect = getRect();
|
|
|
|
// outline with desired color at 50% opacity
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(),
|
|
|
|
std::get< 0 >( color ), std::get< 1 >( color ),
|
|
|
|
std::get< 2 >( color ), 0x80 );
|
|
|
|
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
|
2020-08-22 11:17:56 +00:00
|
|
|
// fill with desired color at 25% opacity
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(),
|
|
|
|
std::get< 0 >( color ), std::get< 1 >( color ),
|
|
|
|
std::get< 2 >( color ), 0x40 );
|
|
|
|
SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void render( Renderer &renderer ) override {
|
2020-08-22 11:17:56 +00:00
|
|
|
auto rect = getRect();
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r,
|
|
|
|
sdl_color.g, sdl_color.b, sdl_color.a );
|
|
|
|
SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
|
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
|
|
|
|
sdl_outline.g, sdl_outline.b, sdl_outline.a );
|
|
|
|
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-08-22 11:17:56 +00:00
|
|
|
private:
|
|
|
|
SDL_Rect getRect() {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !isInfinite() )
|
|
|
|
return { leftmost(), topmost(), pixel_w, pixel_h };
|
2020-08-22 11:17:56 +00:00
|
|
|
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_Rect r = { 0, 0, 0, 0 };
|
|
|
|
if ( ( r.x = leftmost() ) == -1 )
|
2020-08-22 11:17:56 +00:00
|
|
|
r.x = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( ( r.y = topmost() ) == -1 )
|
2020-08-22 11:17:56 +00:00
|
|
|
r.y = 0;
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( rightmost() == -1 )
|
|
|
|
r.w = std::numeric_limits< int >::max();
|
2020-08-22 11:17:56 +00:00
|
|
|
else
|
|
|
|
r.w = pixel_w;
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( bottommost() == -1 )
|
|
|
|
r.h = std::numeric_limits< int >::max();
|
2020-08-22 11:17:56 +00:00
|
|
|
else
|
|
|
|
r.h = pixel_h;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
double w_;
|
|
|
|
double h_;
|
|
|
|
int pixel_w;
|
|
|
|
int pixel_h;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Circle : public CollisionPolygon {
|
|
|
|
public:
|
2020-08-23 07:50:05 +00:00
|
|
|
Circle( double x, double y, double rad ) : CollisionPolygon( x, y ) {
|
2020-08-22 11:17:56 +00:00
|
|
|
original_rad = rad;
|
|
|
|
}
|
|
|
|
virtual ~Circle() {}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual bool colidesWith( const CollisionPolygon &other ) const override;
|
|
|
|
virtual bool isCircle() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
virtual int topmost() const override {
|
|
|
|
return getY() - rad_;
|
|
|
|
}
|
|
|
|
virtual int bottommost() const override {
|
|
|
|
return getY() + rad_;
|
|
|
|
};
|
|
|
|
virtual int leftmost() const override {
|
|
|
|
return getX() - rad_;
|
|
|
|
}
|
|
|
|
virtual int rightmost() const override {
|
|
|
|
return getX() + rad_;
|
|
|
|
}
|
|
|
|
virtual void updateCollision( int x, int y, int w, int h ) override {
|
2020-08-22 11:17:56 +00:00
|
|
|
position_x = original_x * w + x;
|
|
|
|
position_y = original_y * h + y;
|
|
|
|
rad_ = original_rad * w;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void
|
|
|
|
render( Renderer &renderer,
|
|
|
|
const std::tuple< int, int, int, int > &color ) override {
|
|
|
|
std::vector< int > rect = { leftmost(), topmost(), rightmost(),
|
|
|
|
bottommost() };
|
2020-08-22 11:17:56 +00:00
|
|
|
auto center_x = getX();
|
|
|
|
auto center_y = getY();
|
|
|
|
auto radsq = rad_ * rad_;
|
2020-08-23 07:50:05 +00:00
|
|
|
for ( int i = rect[0]; i <= rect[2]; i++ ) {
|
2020-08-22 11:17:56 +00:00
|
|
|
auto xdiff = center_x - i;
|
|
|
|
auto xdist = xdiff * xdiff;
|
2020-08-23 07:50:05 +00:00
|
|
|
auto allowed_rad = sqrt( radsq - xdist );
|
|
|
|
SDL_SetRenderDrawColor(
|
|
|
|
renderer.getRendererPtr(), std::get< 0 >( color ),
|
|
|
|
std::get< 1 >( color ), std::get< 2 >( color ), 0x40 );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y - allowed_rad, i,
|
|
|
|
center_y + allowed_rad );
|
|
|
|
SDL_SetRenderDrawColor(
|
|
|
|
renderer.getRendererPtr(), std::get< 0 >( color ),
|
|
|
|
std::get< 1 >( color ), std::get< 2 >( color ), 0x80 );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y - allowed_rad, i,
|
|
|
|
center_y - allowed_rad + 2 );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y + allowed_rad, i,
|
|
|
|
center_y + allowed_rad - 2 );
|
|
|
|
}
|
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(), 0xFF, 0, 0, 0xFF );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
|
|
|
|
center_x + rad_, center_y );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
|
|
|
|
center_x, center_y + rad_ );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
|
|
|
|
center_x - rad_, center_y );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
|
|
|
|
center_x, center_y - rad_ );
|
|
|
|
}
|
|
|
|
virtual void render( Renderer &renderer ) override {
|
|
|
|
std::vector< int > rect = { leftmost(), topmost(), rightmost(),
|
|
|
|
bottommost() };
|
2020-08-22 11:17:56 +00:00
|
|
|
auto center_x = getX();
|
|
|
|
auto center_y = getY();
|
|
|
|
auto radsq = rad_ * rad_;
|
2020-08-23 07:50:05 +00:00
|
|
|
for ( int i = rect[0]; i <= rect[2]; i++ ) {
|
2020-08-22 11:17:56 +00:00
|
|
|
auto xdiff = center_x - i;
|
|
|
|
auto xdist = xdiff * xdiff;
|
2020-08-23 07:50:05 +00:00
|
|
|
auto allowed_rad = sqrt( radsq - xdist );
|
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r,
|
|
|
|
sdl_color.g, sdl_color.b, sdl_color.a );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y - allowed_rad, i,
|
|
|
|
center_y + allowed_rad );
|
|
|
|
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
|
|
|
|
sdl_outline.g, sdl_outline.b,
|
|
|
|
sdl_outline.a );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y - allowed_rad, i,
|
|
|
|
center_y - allowed_rad + 2 );
|
|
|
|
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
|
|
|
|
center_y + allowed_rad, i,
|
|
|
|
center_y + allowed_rad - 2 );
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-08-22 11:17:56 +00:00
|
|
|
private:
|
|
|
|
int getRadius() const {
|
|
|
|
return rad_;
|
|
|
|
}
|
|
|
|
double original_rad;
|
|
|
|
int rad_;
|
|
|
|
};
|
|
|
|
|
2020-09-11 12:24:54 +00:00
|
|
|
class LineRenderer : public RenderObject {
|
|
|
|
public:
|
|
|
|
LineRenderer() = delete;
|
|
|
|
virtual ~LineRenderer(){};
|
|
|
|
LineRenderer( double x1, double y1, double x2, double y2, const std::shared_ptr< Renderer > &r )
|
|
|
|
: RenderObject( r ) {
|
|
|
|
og_x1 = x1_ = x1;
|
|
|
|
og_y1 = y1_ = y1;
|
|
|
|
og_x2 = x2_ = x2;
|
|
|
|
og_y2 = y2_ = y2;
|
|
|
|
updateSizeAndPosition();
|
|
|
|
}
|
|
|
|
LineRenderer( double x1, double y1, double x2, double y2, const std::shared_ptr< Renderer > &r,
|
|
|
|
const std::string &color )
|
|
|
|
: LineRenderer( x1, y1, x2, y2, r ) {
|
|
|
|
setColor( color );
|
|
|
|
}
|
|
|
|
virtual void setColor( const std::string &color ) override {
|
|
|
|
_color = getColorsHEX( color );
|
|
|
|
}
|
|
|
|
virtual void specialAction( int /*UNUSED*/ ) override{};
|
|
|
|
virtual void render() override {
|
|
|
|
if ( !getHidden() ) {
|
|
|
|
SDL_SetRenderDrawColor( renderer->getRendererPtr(), std::get< 0 >( _color ),
|
|
|
|
std::get< 1 >( _color ), std::get< 2 >( _color ),
|
|
|
|
std::get< 3 >( _color ) );
|
|
|
|
SDL_RenderDrawLine( renderer->getRendererPtr(), pixel_x1, pixel_y1,
|
|
|
|
pixel_x2, pixel_y2 );
|
|
|
|
}
|
|
|
|
if ( hasCollisions() && renderer->getRenderColiders() &&
|
|
|
|
!getHidden() ) {
|
|
|
|
for ( const auto &col : getCollisions() )
|
|
|
|
col->render( *renderer, colider_color );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual void move( int ticks ) override {
|
|
|
|
if ( permanent )
|
|
|
|
return;
|
|
|
|
auto addx =
|
|
|
|
static_cast< double >( movementSpeed * movementDirection.first ) *
|
|
|
|
( static_cast< double >( ticks ) / 1000 );
|
|
|
|
auto addy =
|
|
|
|
static_cast< double >( movementSpeed * movementDirection.second ) *
|
|
|
|
( static_cast< double >( ticks ) / 1000 );
|
|
|
|
if ( std::isnan( addx ) || std::isnan( addy ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
og_x1 += addx;
|
|
|
|
og_x2 += addx;
|
|
|
|
og_y1 += addy;
|
|
|
|
og_y2 += addy;
|
|
|
|
|
|
|
|
custom_move( ticks );
|
|
|
|
|
|
|
|
updateSizeAndPosition();
|
|
|
|
}
|
|
|
|
virtual void custom_move( int /*UNUSED*/ ) override {}
|
|
|
|
virtual void setPos( double x, double y ) override {
|
|
|
|
auto diffx = og_x2 - og_x1;
|
|
|
|
auto diffy = og_y2 - og_y1;
|
|
|
|
og_x1 = x;
|
|
|
|
og_y1 = y;
|
|
|
|
og_x2 = og_x1 + diffx;
|
|
|
|
og_y2 = og_y1 + diffy;
|
|
|
|
updateSizeAndPosition();
|
|
|
|
}
|
|
|
|
virtual void setPos(const std::pair<double, double> &pos) override {
|
|
|
|
setPos(pos.first, pos.second);
|
|
|
|
}
|
|
|
|
virtual std::pair< double, double > getPos() const override {
|
|
|
|
return { og_x1, og_y1 };
|
|
|
|
}
|
|
|
|
virtual int leftmost() override {
|
|
|
|
return pixel_x1 < pixel_x2 ? pixel_x1 : pixel_x2;
|
|
|
|
}
|
|
|
|
virtual int topmost() override {
|
|
|
|
return pixel_y1 < pixel_y2 ? pixel_y1 : pixel_y2;
|
|
|
|
}
|
|
|
|
virtual int rightmost() override {
|
|
|
|
return pixel_x1 > pixel_x2 ? pixel_x1 : pixel_x2;
|
|
|
|
}
|
|
|
|
virtual int bottommost() override {
|
|
|
|
return pixel_y1 > pixel_y2 ? pixel_y1 : pixel_y2;
|
|
|
|
}
|
|
|
|
virtual int collisionPushX() override {
|
|
|
|
return leftmost();
|
|
|
|
}
|
|
|
|
virtual int collisionPushY() override {
|
|
|
|
return topmost();
|
|
|
|
}
|
|
|
|
virtual int collisionWidth() override {
|
|
|
|
return rightmost() - leftmost();
|
|
|
|
}
|
|
|
|
virtual int collisionHeight() override {
|
|
|
|
return bottommost() - topmost();
|
|
|
|
}
|
|
|
|
virtual void updateSizeAndPosition() override {
|
|
|
|
updateXY();
|
|
|
|
auto dimension = renderer->getSmallerSide();
|
|
|
|
pixel_x1 = std::round(x1_ * dimension);
|
|
|
|
pixel_x2 = std::round(x2_ * dimension);
|
|
|
|
pixel_y1 = std::round(y1_ * dimension);
|
|
|
|
pixel_y2 = std::round(y2_ * dimension);
|
|
|
|
for ( auto &x : collisions ) {
|
|
|
|
x->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(), collisionHeight() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual void centerX() override {
|
|
|
|
centerx = true;
|
|
|
|
updateSizeAndPosition();
|
|
|
|
}
|
|
|
|
virtual std::shared_ptr<RenderObject> copySelf() override {
|
|
|
|
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot, create new textures!!!
|
|
|
|
return std::make_shared<LineRenderer>(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual SDL_Rect getRect() override {
|
|
|
|
return {leftmost(), topmost(), rightmost() - leftmost(), bottommost() - topmost()};
|
|
|
|
}
|
|
|
|
virtual std::pair< std::pair< double, double >,
|
|
|
|
std::pair< double, double > >
|
|
|
|
getDoubleRect() const override {
|
|
|
|
return {{og_x1, og_y1}, {og_x2 - og_x1, og_y2 - og_y1}};
|
|
|
|
}
|
|
|
|
void setOutlineColor( const std::string &/*UNUSED*/ ) override {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void updateXY() {
|
|
|
|
if ( !centerx ) {
|
|
|
|
x1_ = og_x1;
|
|
|
|
y1_ = og_y1;
|
|
|
|
x2_ = og_x2;
|
|
|
|
y2_ = og_y2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto width = renderer->getWidth();
|
|
|
|
auto height = renderer->getHeight();
|
|
|
|
if ( width > height ) {
|
|
|
|
auto multiplier = static_cast< double >( width ) /
|
|
|
|
static_cast< double >( height );
|
|
|
|
x1_ = og_x1 + static_cast< double >( multiplier - 1 ) / 2;
|
|
|
|
x2_ = og_x2 + static_cast< double >( multiplier - 1 ) / 2;
|
|
|
|
} else {
|
|
|
|
x1_ = og_x1;
|
|
|
|
x2_ = og_x2;
|
|
|
|
}
|
|
|
|
y1_ = og_y1;
|
|
|
|
y2_ = og_y2;
|
|
|
|
}
|
|
|
|
double og_x1;
|
|
|
|
double og_y1;
|
|
|
|
double x1_;
|
|
|
|
double y1_;
|
|
|
|
double og_x2;
|
|
|
|
double og_y2;
|
|
|
|
double x2_;
|
|
|
|
double y2_;
|
|
|
|
int pixel_x1{};
|
|
|
|
int pixel_y1{};
|
|
|
|
int pixel_x2{};
|
|
|
|
int pixel_y2{};
|
|
|
|
bool centerx = false;
|
|
|
|
std::tuple< int, int, int, int > _color;
|
|
|
|
};
|
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
class RectangleRender : public RenderObject {
|
|
|
|
public:
|
|
|
|
RectangleRender() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual ~RectangleRender(){};
|
|
|
|
RectangleRender( double x, double y, double w, double h,
|
2020-09-10 14:50:36 +00:00
|
|
|
const std::shared_ptr< Renderer > &r )
|
2020-08-23 07:50:05 +00:00
|
|
|
: RenderObject( r ) {
|
2020-08-22 12:13:28 +00:00
|
|
|
og_x = x_ = x;
|
|
|
|
og_y = y_ = y;
|
|
|
|
og_w = w_ = w;
|
|
|
|
og_h = h_ = h;
|
2020-08-22 23:08:10 +00:00
|
|
|
updateSizeAndPosition();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
RectangleRender( double x, double y, double w, double h,
|
2020-09-10 14:50:36 +00:00
|
|
|
const std::shared_ptr< Renderer > &r,
|
|
|
|
const std::shared_ptr< Texture > &t )
|
2020-08-23 07:50:05 +00:00
|
|
|
: RectangleRender( x, y, w, h, r ) {
|
|
|
|
setTexture( t );
|
|
|
|
}
|
|
|
|
RectangleRender( double x, double y, double w, double h,
|
2020-09-10 14:50:36 +00:00
|
|
|
const std::shared_ptr< Renderer > &r,
|
2020-08-23 07:50:05 +00:00
|
|
|
const std::string &img_or_color, bool is_polygon = false )
|
|
|
|
: RectangleRender( x, y, w, h, r ) {
|
|
|
|
if ( !is_polygon ) {
|
|
|
|
setTexture( img_or_color );
|
2020-08-22 11:17:56 +00:00
|
|
|
} else {
|
2020-08-23 07:50:05 +00:00
|
|
|
setColor( img_or_color );
|
2020-09-10 14:50:36 +00:00
|
|
|
color = img_or_color;
|
2020-08-22 11:17:56 +00:00
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setColor( const std::string &color ) override {
|
|
|
|
if ( !polygon ) {
|
|
|
|
polygon = std::make_shared< Rect >( 0, 0, 1, 1 );
|
|
|
|
polygon->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(), collisionHeight() );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
polygon->setColor( color );
|
2020-08-22 12:13:28 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setOutlineColor( const std::string &color ) override {
|
|
|
|
if ( !polygon ) {
|
|
|
|
polygon = std::make_shared< Rect >( 0, 0, 1, 1 );
|
|
|
|
polygon->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(), collisionHeight() );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
polygon->setOutlineColor( color );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void specialAction( int /*UNUSED*/ ) override{};
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual void render() override {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !getHidden() ) {
|
|
|
|
if ( polygon )
|
|
|
|
polygon->render( *renderer );
|
|
|
|
if ( texture != NULL )
|
|
|
|
SDL_RenderCopy( renderer->getRendererPtr(),
|
|
|
|
texture->getTexturePtr(), NULL, &rect );
|
2020-08-22 12:15:12 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( hasCollisions() && renderer->getRenderColiders() &&
|
|
|
|
!getHidden() ) {
|
|
|
|
for ( const auto &col : getCollisions() )
|
|
|
|
col->render( *renderer, colider_color );
|
2020-08-21 16:32:15 +00:00
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void move( int ticks ) override {
|
|
|
|
if ( permanent )
|
2020-08-22 11:17:56 +00:00
|
|
|
return;
|
2020-08-23 07:50:05 +00:00
|
|
|
auto addx =
|
|
|
|
static_cast< double >( movementSpeed * movementDirection.first ) *
|
|
|
|
( static_cast< double >( ticks ) / 1000 );
|
|
|
|
auto addy =
|
|
|
|
static_cast< double >( movementSpeed * movementDirection.second ) *
|
|
|
|
( static_cast< double >( ticks ) / 1000 );
|
|
|
|
if ( std::isnan( addx ) || std::isnan( addy ) )
|
2020-08-22 23:08:10 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
og_x += addx;
|
|
|
|
og_y += addy;
|
2020-08-22 12:13:28 +00:00
|
|
|
|
2020-08-23 07:50:05 +00:00
|
|
|
custom_move( ticks );
|
2020-08-22 12:13:28 +00:00
|
|
|
|
2020-08-22 23:08:10 +00:00
|
|
|
updateSizeAndPosition();
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void custom_move( int /*UNUSED*/ ) override {}
|
|
|
|
virtual std::pair< std::pair< double, double >,
|
|
|
|
std::pair< double, double > >
|
2020-09-10 14:50:36 +00:00
|
|
|
getDoubleRect() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return { { og_x, og_y }, { og_w, og_h } };
|
2020-07-27 18:05:59 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual void setPos( double x, double y ) override {
|
2020-08-22 23:08:10 +00:00
|
|
|
og_x = x;
|
|
|
|
og_y = y;
|
|
|
|
updateSizeAndPosition();
|
2020-07-27 18:05:59 +00:00
|
|
|
}
|
2020-09-10 14:50:36 +00:00
|
|
|
virtual void setPos(const std::pair<double, double> &pos) override {
|
|
|
|
setPos(pos.first, pos.second);
|
|
|
|
}
|
2020-08-24 14:33:53 +00:00
|
|
|
virtual std::pair< double, double > getPos() const override {
|
2020-08-23 07:50:05 +00:00
|
|
|
return { og_x, og_y };
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
|
|
|
virtual int leftmost() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.x;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int topmost() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.y;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int rightmost() override {
|
2020-07-28 17:35:31 +00:00
|
|
|
return rect.x + rect.w;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int bottommost() override {
|
2020-07-28 17:35:31 +00:00
|
|
|
return rect.y + rect.h;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int collisionPushX() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.x;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int collisionPushY() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.y;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int collisionWidth() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.w;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual int collisionHeight() override {
|
2020-07-26 20:37:20 +00:00
|
|
|
return rect.h;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual void updateSizeAndPosition() override {
|
|
|
|
updateXY();
|
2020-07-28 12:46:48 +00:00
|
|
|
auto dimension = renderer->getSmallerSide();
|
2020-08-24 20:14:26 +00:00
|
|
|
rect.x = std::round(x_ * dimension);
|
|
|
|
rect.y = std::round(y_ * dimension);
|
|
|
|
rect.w = std::round((x_ + w_) * dimension) - rect.x;
|
|
|
|
rect.h = std::round((y_ + h_) * dimension) - rect.y;
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( polygon )
|
|
|
|
polygon->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(), collisionHeight() );
|
|
|
|
for ( auto &x : collisions ) {
|
|
|
|
x->updateCollision( collisionPushX(), collisionPushY(),
|
|
|
|
collisionWidth(), collisionHeight() );
|
2020-08-22 23:08:10 +00:00
|
|
|
}
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual SDL_Rect getRect() override {
|
2020-07-28 17:35:31 +00:00
|
|
|
return rect;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
virtual void centerX() override {
|
2020-08-22 12:13:28 +00:00
|
|
|
centerx = true;
|
|
|
|
updateSizeAndPosition();
|
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
virtual std::shared_ptr<RenderObject> copySelf() override {
|
|
|
|
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot, create new textures!!!
|
|
|
|
return std::make_shared<RectangleRender>(*this);
|
|
|
|
}
|
2020-09-10 14:50:36 +00:00
|
|
|
std::string getColor() const {
|
|
|
|
return color;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-27 18:05:59 +00:00
|
|
|
protected:
|
2020-08-22 23:08:10 +00:00
|
|
|
void updateXY() {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !centerx ) {
|
2020-08-22 23:08:10 +00:00
|
|
|
x_ = og_x;
|
|
|
|
y_ = og_y;
|
|
|
|
return;
|
|
|
|
}
|
2020-08-22 12:13:28 +00:00
|
|
|
auto width = renderer->getWidth();
|
|
|
|
auto height = renderer->getHeight();
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( width > height ) {
|
|
|
|
auto multiplier = static_cast< double >( width ) /
|
|
|
|
static_cast< double >( height );
|
|
|
|
x_ = og_x + static_cast< double >( multiplier - 1 ) / 2;
|
2020-08-22 12:13:28 +00:00
|
|
|
} else {
|
|
|
|
x_ = og_x;
|
|
|
|
}
|
2020-08-22 23:08:10 +00:00
|
|
|
y_ = og_y;
|
2020-08-22 12:13:28 +00:00
|
|
|
}
|
|
|
|
double og_x;
|
|
|
|
double og_y;
|
|
|
|
double og_w;
|
|
|
|
double og_h;
|
2020-07-26 20:37:20 +00:00
|
|
|
double x_;
|
|
|
|
double y_;
|
|
|
|
double w_;
|
|
|
|
double h_;
|
2020-08-22 12:13:28 +00:00
|
|
|
bool centerx = false;
|
2020-07-26 20:37:20 +00:00
|
|
|
SDL_Rect rect;
|
2020-09-10 14:50:36 +00:00
|
|
|
std::string color = "";
|
2020-07-26 20:37:20 +00:00
|
|
|
};
|
|
|
|
|
2020-08-23 07:47:31 +00:00
|
|
|
class TextRenderer : public RectangleRender {
|
|
|
|
public:
|
|
|
|
TextRenderer() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
TextRenderer( double x, double y, double w, double h,
|
|
|
|
std::shared_ptr< Renderer > &r )
|
|
|
|
: RectangleRender( x, y, w, h, r ) {}
|
|
|
|
TextRenderer( double x, double y, double w, double h,
|
|
|
|
std::shared_ptr< Renderer > &r, Font &font,
|
|
|
|
const std::string &text, const std::string &color = "FFFFFF",
|
|
|
|
const std::string &outline_color = "000000",
|
|
|
|
int outline_size = -1, int flags = SDLPP_TEXT_CENTER )
|
|
|
|
: RectangleRender( x, y, w, h, r ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
position_flags = flags;
|
2020-08-23 07:50:05 +00:00
|
|
|
setText( font, text, color, outline_color, outline_size );
|
2020-08-23 07:47:31 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setText( Font &font, const std::string &text,
|
|
|
|
const std::string &color = "FFFFFF",
|
|
|
|
const std::string &outline_color = "000000",
|
|
|
|
int outline_size = -1 ) {
|
2020-09-11 19:34:43 +00:00
|
|
|
_text = text;
|
|
|
|
setTextColor(font, color, outline_color, outline_size);
|
|
|
|
}
|
|
|
|
void setTextColor( Font &font, const std::string &color = "FFFFFF",
|
|
|
|
const std::string &outline_color = "000000",
|
|
|
|
int outline_size = -1) {
|
|
|
|
setTexture( font, _text, color, outline_color, outline_size );
|
2020-08-23 07:47:31 +00:00
|
|
|
updateDstRect();
|
|
|
|
}
|
2020-09-11 19:34:43 +00:00
|
|
|
void changeText( const std::string &text ) {
|
|
|
|
_text = text;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
void setFlags( int flags ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
position_flags = flags;
|
|
|
|
updateDstRect();
|
|
|
|
}
|
|
|
|
virtual void render() override {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !getHidden() ) {
|
|
|
|
if ( polygon )
|
|
|
|
polygon->render( *renderer );
|
|
|
|
if ( texture != NULL )
|
|
|
|
SDL_RenderCopy( renderer->getRendererPtr(),
|
|
|
|
texture->getTexturePtr(), NULL, &dst_rect );
|
2020-08-23 07:47:31 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( hasCollisions() && renderer->getRenderColiders() &&
|
|
|
|
!getHidden() ) {
|
|
|
|
for ( const auto &col : getCollisions() )
|
|
|
|
col->render( *renderer, colider_color );
|
2020-08-23 07:47:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual void updateSizeAndPosition() override {
|
|
|
|
RectangleRender::updateSizeAndPosition();
|
|
|
|
updateDstRect();
|
|
|
|
}
|
2020-08-24 16:21:03 +00:00
|
|
|
virtual std::shared_ptr<RenderObject> copySelf() override {
|
|
|
|
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot, create new textures!!!
|
|
|
|
return std::make_shared<TextRenderer>(*this);
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-08-23 07:47:31 +00:00
|
|
|
private:
|
|
|
|
void updateDstRect() {
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !texture )
|
2020-08-23 07:47:31 +00:00
|
|
|
return;
|
|
|
|
int text_width{}, text_height{};
|
2020-08-23 07:50:05 +00:00
|
|
|
SDL_QueryTexture( texture->getTexturePtr(), NULL, NULL, &text_width,
|
|
|
|
&text_height );
|
|
|
|
if ( text_width < rect.w && text_height < rect.h ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.w = text_width;
|
|
|
|
dst_rect.h = text_height;
|
|
|
|
} else {
|
2020-08-23 07:50:05 +00:00
|
|
|
double x_div = static_cast< double >( text_width ) /
|
|
|
|
static_cast< double >( rect.w );
|
|
|
|
double y_div = static_cast< double >( text_height ) /
|
|
|
|
static_cast< double >( rect.h );
|
|
|
|
if ( x_div > y_div ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.w = text_width / x_div;
|
|
|
|
dst_rect.h = text_height / x_div;
|
|
|
|
} else {
|
|
|
|
dst_rect.w = text_width / y_div;
|
|
|
|
dst_rect.h = text_height / y_div;
|
|
|
|
}
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !( position_flags & SDLPP_TEXT_LEFT ||
|
|
|
|
position_flags & SDLPP_TEXT_RIGHT ) ) {
|
|
|
|
dst_rect.x = rect.x + ( rect.w - dst_rect.w ) / 2;
|
|
|
|
} else if ( position_flags & SDLPP_TEXT_LEFT ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.x = rect.x;
|
2020-08-23 07:50:05 +00:00
|
|
|
} else if ( position_flags & SDLPP_TEXT_RIGHT ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.x = rect.x + rect.w - dst_rect.w;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
if ( !( position_flags & SDLPP_TEXT_TOP ||
|
|
|
|
position_flags & SDLPP_TEXT_BOTTOM ) ) {
|
|
|
|
dst_rect.y = rect.y + ( rect.h - dst_rect.h ) / 2;
|
|
|
|
} else if ( position_flags & SDLPP_TEXT_TOP ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.y = rect.y;
|
2020-08-23 07:50:05 +00:00
|
|
|
} else if ( position_flags & SDLPP_TEXT_BOTTOM ) {
|
2020-08-23 07:47:31 +00:00
|
|
|
dst_rect.y = rect.y + rect.h - dst_rect.h;
|
|
|
|
}
|
|
|
|
}
|
2020-09-11 19:34:43 +00:00
|
|
|
std::string _text{};
|
2020-08-23 07:47:31 +00:00
|
|
|
int position_flags = 0;
|
|
|
|
SDL_Rect dst_rect{};
|
|
|
|
};
|
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
class CircleRender : public RenderObject {
|
|
|
|
public:
|
|
|
|
CircleRender() = delete;
|
2020-08-23 07:50:05 +00:00
|
|
|
virtual ~CircleRender(){};
|
|
|
|
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r )
|
|
|
|
: RenderObject( r ) {
|
2020-07-26 20:37:20 +00:00
|
|
|
x_ = x;
|
|
|
|
y_ = y;
|
|
|
|
rad_ = rad;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r,
|
|
|
|
std::shared_ptr< Texture > &t )
|
|
|
|
: CircleRender( x, y, rad, r ) {
|
|
|
|
setTexture( t );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r,
|
|
|
|
const std::string &img_path )
|
|
|
|
: CircleRender( x, y, rad, r ) {
|
|
|
|
auto texture = std::make_shared< Texture >( r, img_path );
|
|
|
|
setTexture( texture );
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
virtual void render();
|
|
|
|
virtual int leftmost() {
|
2020-08-23 07:50:05 +00:00
|
|
|
return x_ - rad_;
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
virtual int topmost() {
|
2020-08-23 07:50:05 +00:00
|
|
|
return y_ - rad_;
|
2020-07-26 20:37:20 +00:00
|
|
|
}
|
|
|
|
virtual int collisionPushX() {
|
|
|
|
return x_;
|
|
|
|
}
|
|
|
|
virtual int collisionPushY() {
|
|
|
|
return y_;
|
|
|
|
}
|
2020-08-23 07:50:05 +00:00
|
|
|
|
2020-07-26 20:37:20 +00:00
|
|
|
private:
|
|
|
|
int x_;
|
|
|
|
int y_;
|
|
|
|
int rad_;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool init();
|
2020-08-23 07:50:05 +00:00
|
|
|
bool init( uint32_t SDL_OPTIONS );
|
|
|
|
bool init( uint32_t SDL_OPTIONS, int IMAGE_OPTIONS );
|
2020-07-26 20:37:20 +00:00
|
|
|
|
2020-08-23 07:50:05 +00:00
|
|
|
template < class T > void testPolymorphism( T &obj );
|
2020-07-26 20:37:20 +00:00
|
|
|
|
|
|
|
} // end of namespace SDLPP
|
|
|
|
|
|
|
|
#endif
|