diff --git a/CMakeLists.txt b/CMakeLists.txt index 895135281..986ea7173 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,6 +203,7 @@ set(ES_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/animations/Animation.h ${CMAKE_CURRENT_SOURCE_DIR}/src/animations/AnimationController.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/animations/LambdaAnimation.h ${CMAKE_CURRENT_SOURCE_DIR}/src/animations/LaunchAnimation.h ${CMAKE_CURRENT_SOURCE_DIR}/src/animations/MoveCameraAnimation.h diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 6bd70a989..9f5f6f1f1 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -7,12 +7,20 @@ GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255), mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity()) { + for(unsigned char i = 0; i < MAX_ANIMATIONS; i++) + mAnimationMap[i] = NULL; } GuiComponent::~GuiComponent() { mWindow->removeGui(this); + for(unsigned char i = 0; i < MAX_ANIMATIONS; i++) + { + if(mAnimationMap[i]) + delete mAnimationMap[i]; + } + if(mParent) mParent->removeChild(this); @@ -33,8 +41,19 @@ bool GuiComponent::input(InputConfig* config, Input input) void GuiComponent::update(int deltaTime) { - if(mAnimationController) - mAnimationController->update(deltaTime); + for(unsigned char i = 0; i < MAX_ANIMATIONS; i++) + { + AnimationController* anim = mAnimationMap[i]; + if(anim) + { + bool done = anim->update(deltaTime); + if(done) + { + mAnimationMap[i] = NULL; + delete anim; + } + } + } for(unsigned int i = 0; i < getChildCount(); i++) { @@ -186,12 +205,23 @@ void GuiComponent::textInput(const char* text) } } -void GuiComponent::setAnimation(Animation* anim, std::function finishedCallback, bool reverse) +void GuiComponent::setAnimation(Animation* anim, std::function finishedCallback, bool reverse, unsigned char slot) { - mAnimationController = std::shared_ptr(new AnimationController(anim, finishedCallback, reverse)); + assert(slot < MAX_ANIMATIONS); + + AnimationController* oldAnim = mAnimationMap[slot]; + mAnimationMap[slot] = new AnimationController(anim, finishedCallback, reverse); + + if(oldAnim) + delete oldAnim; } -void GuiComponent::stopAnimation() +void GuiComponent::stopAnimation(unsigned char slot) { - mAnimationController.reset(); + assert(slot < MAX_ANIMATIONS); + if(mAnimationMap[slot]) + { + delete mAnimationMap[slot]; + mAnimationMap[slot] = NULL; + } } diff --git a/src/GuiComponent.h b/src/GuiComponent.h index 5118b199e..be58769ee 100644 --- a/src/GuiComponent.h +++ b/src/GuiComponent.h @@ -52,8 +52,8 @@ public: GuiComponent* getChild(unsigned int i) const; // animation will be automatically deleted when it completes or is stopped. - void setAnimation(Animation* animation, std::function finishedCallback = nullptr, bool reverse = false); - void stopAnimation(); + void setAnimation(Animation* animation, std::function finishedCallback = nullptr, bool reverse = false, unsigned char slot = 0); + void stopAnimation(unsigned char slot); virtual unsigned char getOpacity() const; virtual void setOpacity(unsigned char opacity); @@ -78,9 +78,12 @@ protected: Eigen::Vector3f mPosition; Eigen::Vector2f mSize; +public: + const static unsigned char MAX_ANIMATIONS = 4; + private: Eigen::Affine3f mTransform; //Don't access this directly! Use getTransform()! - std::shared_ptr mAnimationController; + AnimationController* mAnimationMap[MAX_ANIMATIONS]; }; #endif diff --git a/src/animations/AnimationController.cpp b/src/animations/AnimationController.cpp index 03b75cccd..3c92105d2 100644 --- a/src/animations/AnimationController.cpp +++ b/src/animations/AnimationController.cpp @@ -13,7 +13,7 @@ AnimationController::~AnimationController() delete mAnimation; } -void AnimationController::update(int deltaTime) +bool AnimationController::update(int deltaTime) { mTime += deltaTime; float t = (float)mTime / mAnimation->getDuration(); @@ -26,13 +26,7 @@ void AnimationController::update(int deltaTime) mAnimation->apply(mReverse ? 1.0f - t : t); if(t == 1.0f) - { - if(mFinishedCallback) - { - // in case mFinishedCallback causes us to be deleted, use a copy - auto copy = mFinishedCallback; - mFinishedCallback = nullptr; - copy(); - } - } + return true; + + return false; } diff --git a/src/animations/AnimationController.h b/src/animations/AnimationController.h index 5ea62b209..de28f62a5 100644 --- a/src/animations/AnimationController.h +++ b/src/animations/AnimationController.h @@ -12,7 +12,8 @@ public: AnimationController(Animation* anim, std::function finishedCallback = nullptr, bool reverse = false); virtual ~AnimationController(); - void update(int deltaTime); + // Returns true if the animation is complete. + bool update(int deltaTime); private: Animation* mAnimation; diff --git a/src/animations/LambdaAnimation.h b/src/animations/LambdaAnimation.h new file mode 100644 index 000000000..d3888c2f1 --- /dev/null +++ b/src/animations/LambdaAnimation.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Animation.h" + +class LambdaAnimation : public Animation +{ +public: + LambdaAnimation(const std::function& func, int duration) : mFunction(func), mDuration(duration) {} + + int getDuration() const override { return mDuration; } + + void apply(float t) override + { + mFunction(t); + } + +private: + std::function mFunction; + int mDuration; +}; diff --git a/src/main.cpp b/src/main.cpp index bc8c9fec9..9e5f6bf6d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -182,7 +182,7 @@ int main(int argc, char* argv[]) bool sleeping = false; unsigned int timeSinceLastEvent = 0; - int lastTime = 0; + int lastTime = SDL_GetTicks(); bool running = true; while(running) @@ -230,8 +230,8 @@ int main(int argc, char* argv[]) deltaTime = 1000; window.update(deltaTime); - Renderer::swapBuffers(); //swap here so we can read the last screen state during updates (see ImageComponent::copyScreen()) window.render(); + Renderer::swapBuffers(); //sleep if we're past our threshold //sleeping entails setting a flag to start skipping frames diff --git a/src/views/ViewController.cpp b/src/views/ViewController.cpp index c5e77061d..e4daa665d 100644 --- a/src/views/ViewController.cpp +++ b/src/views/ViewController.cpp @@ -7,10 +7,13 @@ #include "GridGameListView.h" #include "../animations/LaunchAnimation.h" #include "../animations/MoveCameraAnimation.h" +#include "../animations/LambdaAnimation.h" ViewController::ViewController(Window* window) - : GuiComponent(window), mCurrentView(nullptr), mCamera(Eigen::Affine3f::Identity()), mFadeOpacity(0) + : GuiComponent(window), mCurrentView(nullptr), mCamera(Eigen::Affine3f::Identity()), mFadeOpacity(1) { + // slot 1 so the fade carries over + setAnimation(new LambdaAnimation([&] (float t) { mFadeOpacity = lerp(1.0f, 0.0f, t); }, 900), nullptr, false, 1); mState.viewing = START_SCREEN; } @@ -95,11 +98,13 @@ void ViewController::launch(FileData* game, Eigen::Vector3f center) return; } - game->getSystem()->getTheme()->playSound("gameSelectSound"); Eigen::Affine3f origCamera = mCamera; + origCamera.translation() = -mCurrentView->getPosition(); + center += mCurrentView->getPosition(); + stopAnimation(1); // make sure the fade in isn't still playing setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 1500), [this, origCamera, center, game] { game->getSystem()->launchGame(mWindow, game);