Compare commits

..

No commits in common. "dev-base" and "dev" have entirely different histories.

17 changed files with 331 additions and 323 deletions

View File

@ -19,8 +19,11 @@ The class `xApplication` is a singleton representing your application, its windo
The interface `xElement` represents any graphical feature to be drawn on the screen. Any number of `xElement` can be pushed to or pulled from the application at any time in order to show them or not. The interface `xElement` represents any graphical feature to be drawn on the screen. Any number of `xElement` can be pushed to or pulled from the application at any time in order to show them or not.
The interface `xOrchestrable` represents any class that can be called during the application scheduling. Any number of `xOrchestrable` can be added or removed from the application at any time in order to execute them or not.
The class `xSprite` represents a sprite that can is a rectangle that can draw either as a single color, an image, or a copy of another sprite. It can be moved over time. Also, it allows you to set a custom clip if this is an image sprite. The class `xSprite` represents a sprite that can is a rectangle that can draw either as a single color, an image, or a copy of another sprite. It can be moved over time. Also, it allows you to set a custom clip if this is an image sprite.
The class `xSpriteAnimation` derives from an image sprite, which clip can change over time. These clips are called _frames_ and have to be set beforehand. It is also an orchestrable (i.e. animates on application ticks), you can start or stop the animation with a specified time interval. Every `xSpriteAnimation` is scheduled by the `xApplication`. The class `xSpriteAnimation` derives from an image sprite, which clip can change over time. These clips are called _frames_ and have to be set beforehand, when ready you can start or stop the animation with a specified delay between frames. Every `xSpriteAnimation` is scheduled on the same dedicated animation thread.
The concurrency model is led simple :
- the main loop schedules rendering and user input
- the animation loop schedules animation frame shifts

View File

@ -4,8 +4,8 @@
#include "../xSDL/xOrchestrable.h" #include "../xSDL/xOrchestrable.h"
#include "../xSDL/xApplication.h" #include "../xSDL/xApplication.h"
#include "../xSDL/xController.h" #include "../xSDL/xController.h"
#include "../xSDL/xDrawable.h" #include "../xSDL/xElement.h"
#include "../xSDL/xSprite.h" #include "../xSDL/xSprite.h"
#include "../xSDL/xSpriteGroup.h" #include "../xSDL/xSpriteAnimation.h"
#endif #endif

View File

@ -139,7 +139,7 @@ bool xApplication::setImage(const char *url){
// // Anti conflit inter-thread // // Anti conflit inter-thread
// _mutex_hit.lock(); // _mutex_hit.try_lock();
// /* (1) On recupere le SDL_Rect destination du sprite courant */ // /* (1) On recupere le SDL_Rect destination du sprite courant */
// int xIndex = -1; // int xIndex = -1;
@ -224,7 +224,7 @@ bool xApplication::setImage(const char *url){
// bool xApplication::hit(string current, int movex, int movey){ // bool xApplication::hit(string current, int movex, int movey){
// if( !this->status() ) return true; // if( !this->status() ) return true;
// _mutex_hit.lock(); // _mutex_hit.try_lock();
// /* (1) On recupere le SDL_Rect destination du sprite courant */ // /* (1) On recupere le SDL_Rect destination du sprite courant */
// xSprite *sprite = NULL; // xSprite *sprite = NULL;
@ -245,29 +245,29 @@ bool xApplication::setImage(const char *url){
/** adds new sprite to draw */ /** adds new sprite to draw */
void xApplication::push(xDrawable* sprite){ void xApplication::push(xElement* sprite){
_mutex_draw.lock(); _mutex_draw.try_lock();
_sprites.insert(sprite); _sprites.insert(sprite);
_mutex_draw.unlock(); _mutex_draw.unlock();
} }
/** removes a sprite to draw (from its address) */ /** removes a sprite to draw (from its address) */
void xApplication::pull(xDrawable* sprite){ void xApplication::pull(xElement* sprite){
_mutex_draw.lock(); _mutex_draw.try_lock();
_sprites.erase(sprite); _sprites.erase(sprite);
_mutex_draw.unlock(); _mutex_draw.unlock();
} }
/** clears the scene */ /** clears the scene */
void xApplication::clear(){ void xApplication::clear(){
_mutex_draw.lock(); _mutex_draw.try_lock();
_sprites.clear(); _sprites.clear();
_mutex_draw.unlock(); _mutex_draw.unlock();
} }
/** Update the scene */ /** Update the scene */
void xApplication::render(){ void xApplication::render(){
_mutex_draw.lock(); _mutex_draw.try_lock();
/* 1. clear scene */ /* 1. clear scene */
SDL_RenderClear(_renderer); SDL_RenderClear(_renderer);
@ -281,8 +281,9 @@ void xApplication::render(){
/* 4. draw every sprite */ /* 4. draw every sprite */
for( set<xDrawable*>::iterator it = _sprites.begin() ; it != _sprites.end() ; it++ ){ set<xElement*>::iterator it;
xDrawable* sprite = *it; for( it = _sprites.begin() ; it != _sprites.end() ; it++ ){
xElement* sprite = *it;
sprite->draw(_renderer); sprite->draw(_renderer);
} }
@ -307,7 +308,7 @@ void xApplication::schedule(){
const uint32_t ticks = SDL_GetTicks(); const uint32_t ticks = SDL_GetTicks();
// trigger tick() on registered orchestrables // trigger tick() on registered orchestrables
_mutex_orchestrate.lock(); _mutex_orchestrate.try_lock();
set<xOrchestrable*>::iterator it; set<xOrchestrable*>::iterator it;
for( it = _orchestrables.begin() ; it != _orchestrables.end() ; it++ ){ for( it = _orchestrables.begin() ; it != _orchestrables.end() ; it++ ){
xOrchestrable* orchestrable = *it; xOrchestrable* orchestrable = *it;
@ -323,13 +324,13 @@ void xApplication::schedule(){
} }
void xApplication::addOrchestrable(xOrchestrable* o){ void xApplication::addOrchestrable(xOrchestrable* o){
_mutex_orchestrate.lock(); _mutex_orchestrate.try_lock();
_orchestrables.insert(o); _orchestrables.insert(o);
_mutex_orchestrate.unlock(); _mutex_orchestrate.unlock();
} }
void xApplication::removeOrchestrable(xOrchestrable* o){ void xApplication::removeOrchestrable(xOrchestrable* o){
_mutex_orchestrate.lock(); _mutex_orchestrate.try_lock();
_orchestrables.erase(o); _orchestrables.erase(o);
_mutex_orchestrate.unlock(); _mutex_orchestrate.unlock();
} }

View File

@ -9,7 +9,7 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <stdexcept> #include <stdexcept>
#include "xDrawable.h" #include "xElement.h"
#include "xController.h" #include "xController.h"
#include "xOrchestrable.h" #include "xOrchestrable.h"
using namespace std; using namespace std;
@ -41,8 +41,8 @@
// bool hit(string current, int movex=0, int movey=0); // Gestion des collisions // bool hit(string current, int movex=0, int movey=0); // Gestion des collisions
/** scene */ /** scene */
void push(xDrawable* sprite); void push(xElement* sprite);
void pull(xDrawable *sprite); void pull(xElement *sprite);
void clear(); void clear();
void render(); void render();
@ -64,24 +64,24 @@
void syncFps(); void syncFps();
// fps management // fps management
uint32_t _lasttick { 0 }; uint32_t _lasttick;
uint32_t _fpstime { (int) 1000.0/60 }; uint32_t _fpstime;
// event management // event management
xController _controller; xController _controller;
// sprites // sprites
set<xDrawable*> _sprites; set<xElement*> _sprites;
// execution pool // execution pool
set<xOrchestrable*> _orchestrables; set<xOrchestrable*> _orchestrables;
// sdl objects // sdl objects
SDL_Window *_window { NULL }; SDL_Window *_window;
SDL_Rect _winrect { 0, 0, 0, 0 }; SDL_Rect _winrect;
SDL_Renderer *_renderer { NULL }; SDL_Renderer *_renderer;
SDL_Texture *_texture { NULL }; SDL_Texture *_texture;
// thread safety // thread safety
mutex _mutex_draw; mutex _mutex_draw;

View File

@ -12,24 +12,29 @@ xController::~xController(){
void xController::handleEvent(SDL_Event* event){ void xController::handleEvent(SDL_Event* event){
_mutex.lock(); _mutex.lock();
for( set<xEventHandler*>::iterator it = _handlers.begin() ; it != _handlers.end() ; it++ ){ map<SDL_EventType, EventHandler>::iterator found = _handlers.find( (SDL_EventType) event->type );
xEventHandler* handler = (*it);
handler->handle(event); // ignore no handler found
if( found == _handlers.end() ){
_mutex.unlock();
return;
} }
(*found->second)(event);
_mutex.unlock(); _mutex.unlock();
} }
// bind a new handler // bind a new handler
void xController::attachEvent(xEventHandler* handler){ void xController::attachEvent(SDL_EventType t, EventHandlerArg){
_mutex.lock(); _mutex.lock();
_handlers.insert(handler); _handlers[ t ] = handler;
_mutex.unlock(); _mutex.unlock();
} }
// removes an existing handler // removes an existing handler
void xController::detachEvent(xEventHandler* handler){ void xController::detachEvent(SDL_EventType t){
_mutex.lock(); _mutex.lock();
_handlers.erase(handler); _handlers.erase(t);
_mutex.unlock(); _mutex.unlock();
} }

View File

@ -3,11 +3,12 @@
#include "SDL.h" #include "SDL.h"
#include <mutex> #include <mutex>
#include <set> #include <map>
#include "xEventHandler.h"
using namespace std; using namespace std;
#define EventHandlerArg void(* handler)(SDL_Event*)
#define EventHandler void(*)(SDL_Event*)
class xController{ class xController{
public: public:
@ -18,12 +19,12 @@
void handleEvent(SDL_Event* event); void handleEvent(SDL_Event* event);
// manage handlers // manage handlers
void attachEvent(xEventHandler* handler); void attachEvent(SDL_EventType t, EventHandlerArg);
void detachEvent(xEventHandler* handler); void detachEvent(SDL_EventType t);
private: private:
// event handlers // event handlers
set<xEventHandler*> _handlers; map<SDL_EventType, EventHandler> _handlers;
// thread safety // thread safety
mutex _mutex; mutex _mutex;

View File

@ -1 +0,0 @@
#include "xDrawable.h"

1
xSDL/xElement.cpp Normal file
View File

@ -0,0 +1 @@
#include "xElement.h"

View File

@ -3,7 +3,7 @@
#include "SDL.h" #include "SDL.h"
struct xDrawable { struct xElement {
virtual void draw(SDL_Renderer* renderer) = 0; virtual void draw(SDL_Renderer* renderer) = 0;
}; };

View File

@ -1 +0,0 @@
#include "xEventHandler.h"

View File

@ -1,16 +0,0 @@
#ifndef DEF_XEVENT_HANDLER_H
#define DEF_XEVENT_HANDLER_H
#include "SDL.h"
using namespace std;
class xEventHandler {
public:
// handles the event
virtual void handle(SDL_Event* event) = 0;
};
#endif

View File

@ -2,56 +2,38 @@
/** clean SDL objects */ /** clean SDL objects */
xSprite::~xSprite(){ xSprite::~xSprite(){
_mutex.lock(); _mutex.try_lock();
SDL_FreeSurface( _surface ); SDL_FreeSurface( _surface );
_mutex.unlock(); _mutex.unlock();
} }
/** copy constructor */ /** empty sprite */
xSprite::xSprite(const xSprite& other){ xSprite::xSprite(){
// copy surface _type = "basic";
if( other._surface != NULL ){
this->setSurface( SDL_ConvertSurface(other._surface, other._surface->format, SDL_SWSURFACE) );
}
this->setClip(other._clip);
this->project(other._projection);
} }
/** color sprite */ /** color sprite */
xSprite::xSprite(const int rgba[]){ xSprite::xSprite(const int rgba[]){
_type = "basic";
this->setSurface(rgba); this->setSurface(rgba);
} }
/** image sprite */ /** image sprite */
xSprite::xSprite(const char *url){ xSprite::xSprite(const char *url){
_type = "basic";
this->setSurface(url); this->setSurface(url);
} }
/** image sprite with clip */ /** texture copy sprite */
xSprite::xSprite(const char *url, SDL_Rect clip){ xSprite::xSprite(SDL_Surface *s){
this->setSurface(url); _type = "basic";
this->setClip(clip); this->setSurface(s);
}
xSprite::xSprite(const char *url, int clip_x, int clip_y, int clip_w, int clip_h){
this->setSurface(url);
this->setClip(clip_x, clip_y, clip_w, clip_h);
}
/** image sprite with clip and projection */
xSprite::xSprite(const char *url, SDL_Rect clip, SDL_Rect projection){
this->setSurface(url);
this->setClip(clip);
this->project(projection);
}
xSprite::xSprite(const char *url, int clip_x, int clip_y, int clip_w, int clip_h, int project_x, int project_y, int project_w, int project_h){
this->setSurface(url);
this->setClip(clip_x, clip_y, clip_w, clip_h);
this->project(project_x, project_y, project_w, project_h);
} }
/** update sprite to rhb color */ /** update sprite to rhb color */
void xSprite::setSurface(const int rgba[]){ void xSprite::setSurface(const int rgba[]){
_mutex.lock(); _mutex.try_lock();
if( _surface != NULL ){ if( _surface != NULL ){
SDL_FreeSurface( _surface ); SDL_FreeSurface( _surface );
_surface = NULL; _surface = NULL;
@ -59,6 +41,8 @@ void xSprite::setSurface(const int rgba[]){
_surface = SDL_CreateRGBSurface(0, 0, 0, 32, rgba[0], rgba[1], rgba[2], rgba[3]); _surface = SDL_CreateRGBSurface(0, 0, 0, 32, rgba[0], rgba[1], rgba[2], rgba[3]);
// On cree la texture a partir de la surface
// _surface = SDL_CreateTextureFromSurface(_manager->renderer(), surf);
if( _surface == NULL ) { if( _surface == NULL ) {
throw runtime_error("[xSprite] setSurface(rgba) -> NULL surface"); throw runtime_error("[xSprite] setSurface(rgba) -> NULL surface");
} }
@ -69,7 +53,7 @@ void xSprite::setSurface(const int rgba[]){
/** update sprite to image */ /** update sprite to image */
void xSprite::setSurface(const char *url){ void xSprite::setSurface(const char *url){
_mutex.lock(); _mutex.try_lock();
if( _surface != NULL ){ if( _surface != NULL ){
SDL_FreeSurface( _surface ); SDL_FreeSurface( _surface );
_surface = NULL; _surface = NULL;
@ -83,9 +67,10 @@ void xSprite::setSurface(const char *url){
_mutex.unlock(); _mutex.unlock();
} }
/** copies an existing surface */ /* [SETTEXTURE] Modification de la texture texture
=========================================================*/
void xSprite::setSurface(SDL_Surface *s){ void xSprite::setSurface(SDL_Surface *s){
_mutex.lock(); _mutex.try_lock();
if( _surface != NULL ){ if( _surface != NULL ){
SDL_FreeSurface( _surface ); SDL_FreeSurface( _surface );
_surface = NULL; _surface = NULL;
@ -99,57 +84,129 @@ void xSprite::setSurface(SDL_Surface *s){
_mutex.unlock(); _mutex.unlock();
} }
const SDL_Surface* xSprite::surface(){
_mutex.lock(); /** move sprite with a (x,y) velocity
SDL_Surface* surface = _surface; * - int[0]: new
* - int[1]: can move on y
*/
// bool* xSprite::move(double xSpeed, double ySpeed){
// _mutex.try_lock();
// bool result[2] = {false, false};
// /* logic variables */
// int incrx = x;
// int incry = y;
// bool moveFasterOnY = abs(x) <= abs(y);
// int signofx = (x==0) ? 0 : x / abs(x);
// int signofy = (y==0) ? 0 : y / abs(y);
// // while velocity not null
// while( incrx != 0 || incry != 0 ){
// result[0] = incrx;
// result[1] = incry;
// /* (3) Si on peut aller a la destination */
// // if( !_manager->hit(this, incrx, incry) ){
// // _dst.x += incrx;
// // _dst.y += incry;
// // // cerr << ">>> not locked <<<" << endl;
// // result[0] = incrx;
// // result[1] = incry;
// // _mutex.unlock();
// // return result;
// // }
// /* (4) Sinon, on decremente les deplacements 'alternativement' */
// if( moveFasterOnY ){ // Si on a plus de mouvement horizontal
// if( signofx != 0 && incrx != 0 ) // si la vel. sur x n'est pas nulle
// incrx -= signofx; // on diminue la vel. sur x
// else if( signofy != 0 && incry != 0 ) // sinon si vel. sur y n'est pas nulle
// incry -= signofy; // on diminue la vel. sur y
// else // sinon, velocite nulle
// return result; // On arrete de chercher
// }else{ // Si on a plus de mouvement vertical
// if( signofy != 0 && incry != 0 ) // si la vel. sur y n'est pas nulle
// incry -= signofy; // on diminue la vel. sur y
// else if( signofx != 0 && incrx != 0 ) // sinon si vel. sur x n'est pas nulle
// incrx -= signofx; // on diminue la vel. sur x
// else // sinon, velocite nulle
// return result; // On arrete de chercher
// }
// // if( !_manager->hit(this, 0, 1) ){
// // cerr << "locked from (" << _dst.x << ", " << _dst.y << ") to (" << incrx << ", " << incry << ")" << endl;
// // }
// }
// // retour
// _mutex.unlock();
// return result;
// }
/** get/set sprite type */
string xSprite::getType(){ return _type; }
void xSprite::setType(string newtype){ _type = newtype; }
/** set default dimensions */
void xSprite::dimensions(){
_mutex.try_lock();
/* extract surface lengths*/
int w = _surface->w;
int h = _surface->h;
_dst = (SDL_Rect){0, 0, w, h};
_src = (SDL_Rect){0, 0, w, h};
_mutex.unlock(); _mutex.unlock();
return surface;
} }
/** set sprite clip */ /** set surface dimensions */
void xSprite::setClip(SDL_Rect clip){ void xSprite::dimensions(SDL_Rect r){
_mutex.lock(); _mutex.try_lock();
_clip = clip; /* extract surface lengths */
int w = _surface->w;
int h = _surface->h;
_src = (SDL_Rect){0, 0, w, h};
/* store destination dimensions */
_dst = (SDL_Rect){r.x, r.y, r.w, r.h};
_mutex.unlock(); _mutex.unlock();
} }
void xSprite::setClip(int x, int y, int w, int h){
setClip( (SDL_Rect){x, y, w, h} );
}
/** gets sprite clip */ /** set surface dimensions + clip */
const SDL_Rect xSprite::clip(){ void xSprite::dimensions(SDL_Rect r, SDL_Rect clip){
_mutex.lock(); _mutex.try_lock();
const SDL_Rect clip = _clip; _src = (SDL_Rect){clip.x, clip.y, clip.w, clip.h};
_dst = (SDL_Rect){r.x, r.y, r.w, r.h};
_mutex.unlock(); _mutex.unlock();
return clip;
} }
/** set sprite projection */ /** returns the surface */
void xSprite::project(SDL_Rect dest){ SDL_Surface *xSprite::surface(){ return _surface; }
_mutex.lock();
_projection = dest; /** return destination dimensions */
_mutex.unlock(); SDL_Rect *xSprite::dst(){ return &_dst; }
}
void xSprite::project(int x, int y, int w, int h){ /** return source dimensions */
project( (SDL_Rect){x, y, w, h} ); SDL_Rect *xSprite::src(){ return &_src; }
}
/** gets sprite projection */
const SDL_Rect xSprite::projection(){
_mutex.lock();
const SDL_Rect projection = _projection;
_mutex.unlock();
return projection;
}
/** draws to renderer */ /** draws to renderer */
void xSprite::draw(SDL_Renderer* renderer){ void xSprite::draw(SDL_Renderer* renderer){
_mutex.lock(); _mutex.try_lock();
SDL_RenderCopy( SDL_RenderCopy(
renderer, renderer,
SDL_CreateTextureFromSurface(renderer, _surface), SDL_CreateTextureFromSurface(renderer, this->surface()),
&_clip, this->src(),
&_projection this->dst()
); );
_mutex.unlock(); _mutex.unlock();
} }

View File

@ -6,54 +6,54 @@
#include <mutex> #include <mutex>
#include "SDL.h" #include "SDL.h"
#include "SDL_image.h" #include "SDL_image.h"
#include "xDrawable.h" #include "xElement.h"
#include "xApplication.h"
using namespace std; using namespace std;
class xSprite : public xDrawable{ class xSprite : public xElement {
public: public:
// copy constructor xSprite(); // empty
xSprite(const xSprite& other); xSprite(const int rgba[]); // color sprite
xSprite(const char *url); // image sprite
// color sprite xSprite(SDL_Surface *s); // copy sprite
xSprite(const int rgba[]); ~xSprite();
// image sprite
xSprite(const char *url);
// image with default clip
xSprite(const char *url, SDL_Rect clip);
// image with default clip
xSprite(const char *url, int clip_x, int clip_y, int clip_w, int clip_h);
// image with default clip and projection
xSprite(const char *url, SDL_Rect clip, SDL_Rect projection);
// image with default clip and projection
xSprite(const char *url, int clip_x, int clip_y, int clip_w, int clip_h, int project_x, int project_y, int project_w, int project_h);
virtual ~xSprite();
// replace surface // replace surface
void setSurface(const int rgba[]); // color sprite void setSurface(const int rgba[]); // color sprite
void setSurface(const char *url); // image sprite void setSurface(const char *url); // image sprite
void setSurface(SDL_Surface *t); // copy surface void setSurface(SDL_Surface *t); // copy surface
const SDL_Surface* surface();
// sets the sprite clip // move the sprite
void setClip(SDL_Rect clip); // const bool* move(double xSpeed, double ySpeed);
void setClip(int x, int y, int w, int h);
const SDL_Rect clip();
// set projection into scene // action to apply on collision
void project(SDL_Rect dest); // virtual void onCollide(vector<bool> from, xSprite* by);
void project(int x, int y, int w, int h);
const SDL_Rect projection();
// implement xDrawable // get/set sprite type
string getType();
void setType(string newtype);
// set dimensions
void dimensions(); // defauts
void dimensions(SDL_Rect r);
void dimensions(SDL_Rect r, SDL_Rect clip); // w/ clip
// getters
SDL_Surface *surface();
SDL_Rect *dst();
SDL_Rect *src();
// implement xElement
virtual void draw(SDL_Renderer* renderer) override; virtual void draw(SDL_Renderer* renderer) override;
private:
SDL_Surface* _surface = NULL;
SDL_Rect _clip { 0, 0, 0, 0 };
SDL_Rect _projection { 0, 0, 0, 0 };
mutex _mutex; protected:
string _type;
SDL_Surface* _surface = NULL;
SDL_Rect _dst;
SDL_Rect _src;
mutex _mutex;
}; };

76
xSDL/xSpriteAnimation.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "xSpriteAnimation.h"
/** clean SDL objects and frames */
xSpriteAnimation::~xSpriteAnimation(){
_mutex.try_lock();
SDL_FreeSurface( _surface );
_frames.erase( _frames.begin(), _frames.end() );
_mutex.unlock();
}
/** builds an animation */
xSpriteAnimation::xSpriteAnimation(const char *url, SDL_Rect dest)
: xSprite( url ){
this->dimensions(dest);
}
/** builds an animation from an existing surface */
xSpriteAnimation::xSpriteAnimation(SDL_Surface *s, SDL_Rect dest)
: xSprite(s) {
this->dimensions(dest);
}
/** adds an animation frame */
void xSpriteAnimation::addFrame(SDL_Rect clip){
_mutex_frames.try_lock();
_frames.push_back( (SDL_Rect){
clip.x,
clip.y,
clip.w,
clip.h
} );
_mutex_frames.unlock();
}
/** clears all frames */
void xSpriteAnimation::clearFrames(){
_mutex_frames.try_lock();
_frames.erase(_frames.begin(), _frames.end());
_mutex_frames.unlock();
}
/** draw to scene */
void xSpriteAnimation::draw(SDL_Renderer* renderer){
_mutex.try_lock();
SDL_RenderCopy(
renderer,
SDL_CreateTextureFromSurface(renderer, this->surface()),
this->src(),
this->dst()
);
_mutex.unlock();
}
/** animation process */
void xSpriteAnimation::tick(const uint32_t ticks){
_mutex_frames.try_lock();
uint32_t time_index = ticks / _interval;
size_t frame_index = time_index % _frames.size();
// update current frame clip
_src = _frames.at(frame_index);
_mutex_frames.unlock();
}
/** adds the animation to the render */
void xSpriteAnimation::start(uint32_t interval){
_interval = interval;
xApplication::get()->addOrchestrable(this);
}
/** stops the animation */
void xSpriteAnimation::stop(){
xApplication::get()->removeOrchestrable(this);
}

41
xSDL/xSpriteAnimation.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef DEF_XSPRITEANIMATION_H
#define DEF_XSPRITEANIMATION_H
#include "SDL.h"
#include <vector>
#include "xSprite.h"
#include "xApplication.h"
#include "xElement.h"
#include "xOrchestrable.h"
using namespace std;
class xSpriteAnimation : public xSprite, public xOrchestrable {
public:
// spritesheet with sprite size
xSpriteAnimation(const char *url, SDL_Rect dest);
xSpriteAnimation(SDL_Surface *s, SDL_Rect dest);
~xSpriteAnimation();
void addFrame(SDL_Rect clip);
void clearFrames();
// animation control handles
void start(uint32_t delay);
void stop();
// implement xElement
void draw(SDL_Renderer* renderer) override;
// implement xOrchestrable
void tick(const uint32_t ticks);
protected:
vector<SDL_Rect> _frames;
mutex _mutex_frames;
// animation
uint32_t _interval;
};
#endif

View File

@ -1,106 +0,0 @@
#include "xSpriteGroup.h"
/** clean SDL objects */
xSpriteGroup::~xSpriteGroup(){
_mutex.lock();
_sprites.clear();
_mutex.unlock();
}
/** default constructor */
xSpriteGroup::xSpriteGroup(){
}
/** adds a sprite to the group */
void xSpriteGroup::add(xSprite* sprite){
_mutex.lock();
_sprites.insert(sprite);
_mutex.unlock();
}
/** removes a sprite from the group */
void xSpriteGroup::remove(xSprite* sprite){
_mutex.lock();
_sprites.erase(sprite);
_mutex.unlock();
}
/** apply relative displace for each sprite */
void xSpriteGroup::displace(int x, int y, int w, int h){
displace( (SDL_Rect){x,y,w,h} );
}
void xSpriteGroup::displace(SDL_Rect relative_displace){
_mutex.lock();
for( set<xSprite*>::iterator it = _sprites.begin() ; it != _sprites.end() ; it++ ) {
xSprite* sprite = (*it);
const SDL_Rect actual_projection = sprite->projection();
sprite->project(
actual_projection.x + relative_displace.x,
actual_projection.y + relative_displace.y,
actual_projection.w + relative_displace.w,
actual_projection.h + relative_displace.h
);
}
_mutex.unlock();
}
/** draws to renderer */
void xSpriteGroup::draw(SDL_Renderer* renderer){
_mutex.lock();
// only draw active sprite if animated
if( _animated ){
// invalid active index
if( _active_sprite >= _sprites.size() ) {
_active_sprite = 0;
_mutex.unlock();
return;
}
set<xSprite*>::iterator at_index = _sprites.begin();
advance(at_index, _active_sprite);
if( at_index == _sprites.end() ){
_mutex.unlock();
return;
}
(*at_index)->draw(renderer);
_mutex.unlock();
return;
}
// else draw every sprite
set<xSprite*>::iterator it;
for( it = _sprites.begin() ; it != _sprites.end() ; it++ ){
(*it)->draw(renderer);
}
_mutex.unlock();
}
/** animation process */
void xSpriteGroup::tick(const uint32_t ticks){
_mutex.lock();
const uint32_t time_index = ticks / _animation_interval;
_active_sprite = time_index % _sprites.size();
_mutex.unlock();
}
/** orchestrate the animation */
void xSpriteGroup::animate(uint32_t interval){
_mutex.lock();
_animated = true;
_animation_interval = interval;
_active_sprite = 0;
xApplication::get()->addOrchestrable(this);
_mutex.unlock();
}
/** stops orchestrating the animation */
void xSpriteGroup::freeze(){
_mutex.lock();
xApplication::get()->removeOrchestrable(this);
_mutex.unlock();
}

View File

@ -1,53 +0,0 @@
#ifndef DEF_XSPRITEGROUP_H
#define DEF_XSPRITEGROUP_H
#include <string>
#include <vector>
#include <mutex>
#include "SDL.h"
#include "SDL_image.h"
#include "xDrawable.h"
#include "xOrchestrable.h"
#include "xApplication.h"
#include "xSprite.h"
using namespace std;
class xSpriteGroup : public xDrawable, public xOrchestrable {
public:
xSpriteGroup();
virtual ~xSpriteGroup();
// manage sprite list
void add(xSprite* sprite);
void remove(xSprite* sprite);
void clear();
// apply relative displace for each sprite
void displace(SDL_Rect relative_displace);
void displace(int x, int y, int w, int h);
// implement xDrawable
virtual void draw(SDL_Renderer* renderer) override;
// implement xOrchestrable
void tick(const uint32_t ticks);
// animation handles
void animate(uint32_t interval);
void freeze();
protected:
set<xSprite*> _sprites;
// if not animated, draw all sprites, else draw one at a time
bool _animated = false;
// active sprite for animation
size_t _active_sprite = 0;
uint32_t _animation_interval = 0;
mutex _mutex;
};
#endif