diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cc5344..4d41f5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ add_executable(${PROJECT_NAME} src/sizenotifiable.cpp src/platform.cpp src/platformsystem.cpp + src/movers/moverworld.cpp ) target_link_libraries(${PROJECT_NAME} diff --git a/src/CloonelJumpConfig.h.in b/src/CloonelJumpConfig.h.in index 33212f0..7f1c57d 100644 --- a/src/CloonelJumpConfig.h.in +++ b/src/CloonelJumpConfig.h.in @@ -29,6 +29,7 @@ #define DEF_WIN_WIDTH REFERENCE_WIDTH #define DEF_WIN_HEIGHT REFERENCE_HEIGHT #define DEF_RANDOM_SEED 1984 +#define MAX_PLATFORMS_ON_SCREEN 8 #define GAME_BASE_PATH "@CMAKE_SOURCE_DIR@" diff --git a/src/gameplaysceneclassic.cpp b/src/gameplaysceneclassic.cpp index ae77fbb..230f7e7 100644 --- a/src/gameplaysceneclassic.cpp +++ b/src/gameplaysceneclassic.cpp @@ -24,9 +24,11 @@ #include "inputbag.hpp" #include "key.hpp" #include "moverleftright.hpp" +#include "moverworld.hpp" #include "tiledwallpaper.hpp" #include "texture.hpp" #include "platformsystem.hpp" +#include "CloonelJumpConfig.h" #include #include #include @@ -59,40 +61,52 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void GameplaySceneClassic::Prepare() { + const float halfRefHeight = static_cast(REFERENCE_HEIGHT) / 2.0f; + std::unique_ptr moverSine(new MoverSine()); std::unique_ptr player(new Character("resources/graphics/player.png", SDLObject(), float2(80.0f, 120.0f))); std::unique_ptr moverLeftRight(new MoverLeftRight(1.5f, 5.0f, 40.0f)); + std::unique_ptr moverWorld(new MoverWorld(halfRefHeight)); std::unique_ptr wallpaper(new TiledWallpaper("resources/graphics/background_tile.png", SDLObject())); - std::unique_ptr platforms(new PlatformSystem("resources/graphics/platform.png", SDLObject(), this)); + std::unique_ptr platforms(new PlatformSystem("resources/graphics/platform.png", SDLObject(), this, halfRefHeight * 0.9f, *moverWorld)); player->Prepare(); moverSine->RegisterPlaceable(player.get()); + moverSine->RegisterPlaceable(moverWorld.get()); //Keep an invisible mover moverLeftRight->RegisterPlaceable(player.get()); + moverWorld->RegisterPlaceable(player.get()); //It compensates the position when the chara goes over the mid + moverWorld->RegisterPlaceable(moverWorld.get()); //The mover has to be in sync with the character wallpaper->Reload(); platforms->Prepare(); std::swap(moverSine, m_moverSine); std::swap(player, m_player); std::swap(moverLeftRight, m_moverLeftRight); + std::swap(moverWorld, m_moverWorld); std::swap(wallpaper, m_wallpaper); std::swap(platforms, m_platforms); AddMover(m_moverSine.get()); AddMover(m_moverLeftRight.get()); AddDrawable(m_wallpaper.get()); + AddMover(m_moverWorld.get()); + m_platforms->AddDrawables(); AddDrawable(m_player.get()); - m_moverSine->SetPower(static_cast(SDLObject()->WidthHeight().y() / 2)); + const float jumpPower = halfRefHeight * 1.29f; + m_moverSine->SetPower(jumpPower); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void GameplaySceneClassic::Destroy() noexcept { - m_moverSine = std::move(std::unique_ptr(nullptr)); - m_player = std::move(std::unique_ptr(nullptr)); - m_moverLeftRight = std::move(std::unique_ptr(nullptr)); - m_wallpaper = std::move(std::unique_ptr(nullptr)); + //Destroy in reverse creation order m_platforms = std::move(std::unique_ptr(nullptr)); + m_wallpaper = std::move(std::unique_ptr(nullptr)); + m_moverWorld = std::move(std::unique_ptr(nullptr)); + m_moverLeftRight = std::move(std::unique_ptr(nullptr)); + m_player = std::move(std::unique_ptr(nullptr)); + m_moverSine = std::move(std::unique_ptr(nullptr)); } ///-------------------------------------------------------------------------- diff --git a/src/gameplaysceneclassic.hpp b/src/gameplaysceneclassic.hpp index 6e2d5d0..31485f2 100644 --- a/src/gameplaysceneclassic.hpp +++ b/src/gameplaysceneclassic.hpp @@ -28,6 +28,7 @@ namespace cloonel { class Character; class MoverSine; class MoverLeftRight; + class MoverWorld; class TiledWallpaper; class Texture; class PlatformSystem; @@ -46,6 +47,7 @@ namespace cloonel { std::unique_ptr m_player; std::unique_ptr m_moverSine; std::unique_ptr m_moverLeftRight; + std::unique_ptr m_moverWorld; std::unique_ptr m_wallpaper; std::unique_ptr m_platforms; }; diff --git a/src/movers/moveroneshot.hpp b/src/movers/moveroneshot.hpp index 8806ab9..888472a 100644 --- a/src/movers/moveroneshot.hpp +++ b/src/movers/moveroneshot.hpp @@ -20,7 +20,7 @@ #ifndef id9CDCF10D483641A2845353C0835F93EC #define id9CDCF10D483641A2845353C0835F93EC -//Move a Placeable by issuind an offset. +//Move a Placeable by issuing an offset. //The offset is applied to the current position of the Placeable you are //moving. //For example issuing 1, then 2 will put your Placeable in position 3, diff --git a/src/movers/moverrelative.hpp b/src/movers/moverrelative.hpp index bca3a68..3321754 100644 --- a/src/movers/moverrelative.hpp +++ b/src/movers/moverrelative.hpp @@ -22,7 +22,7 @@ //Move a Placeable by issuing an offset relative to a base position. //Use this if for example your Placeable is following a mathematical formula or -//if you're giving a position you want it to be at any specific time. +//if you're giving a position you want it to be at at any specific time. //For example issuing 1, then 2 will put your Placeable in position 2, //assuming it started at 0. diff --git a/src/movers/moversine.cpp b/src/movers/moversine.cpp index 3a2b11e..a1bf299 100644 --- a/src/movers/moversine.cpp +++ b/src/movers/moversine.cpp @@ -44,7 +44,7 @@ namespace cloonel { void MoverSine::ApplyMotion (float parDelta) { const float pitwo = static_cast(M_PI) * 2.0f; m_alpha += parDelta * 2.6f; - if (m_alpha >= pitwo) + while (m_alpha >= pitwo) m_alpha -= pitwo; } } //namespace cloonel diff --git a/src/movers/moverworld.cpp b/src/movers/moverworld.cpp new file mode 100644 index 0000000..2932567 --- /dev/null +++ b/src/movers/moverworld.cpp @@ -0,0 +1,39 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "moverworld.hpp" +#include + +namespace cloonel { + MoverWorld::MoverWorld (float parMidPoint) : + Placeable(float2(0.0f)), + m_midPoint(parMidPoint), + m_offs(0.0f) + { + } + + float2 MoverWorld::GetOffset() const { + return float2(0.0f, -m_offs); + } + + void MoverWorld::ApplyMotion (float) { + const auto vertPos = this->GetPos().y(); + m_offs = std::max(0.0f, vertPos - m_midPoint); + } +} //namespace cloonel diff --git a/src/movers/moverworld.hpp b/src/movers/moverworld.hpp new file mode 100644 index 0000000..a13ff88 --- /dev/null +++ b/src/movers/moverworld.hpp @@ -0,0 +1,41 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id47E717F84F3647A69E14C3B695B38F7B +#define id47E717F84F3647A69E14C3B695B38F7B + +#include "moveroneshot.hpp" +#include "placeable.hpp" + +namespace cloonel { + class MoverWorld : public MoverOneShot, public Placeable { + public: + explicit MoverWorld ( float parMidPoint ); + virtual ~MoverWorld ( void ) noexcept = default; + + private: + virtual float2 GetOffset ( void ) const; + virtual void ApplyMotion ( float parDelta ); + + const float m_midPoint; + float m_offs; + }; +} //namespace cloonel + +#endif diff --git a/src/platform.cpp b/src/platform.cpp index a8a00c4..f216229 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -25,8 +25,8 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- Platform::Platform (SDLMain* parSdlMain, const float2& parPos, Texture* parTexture, const float2& parSize) : + Placeable(parPos), m_screenRatio(parSdlMain), - m_position(parPos), m_size(parSize), m_surface(parTexture) { @@ -35,9 +35,9 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - Platform::Platform (Platform&& parOther) : + Platform::Platform (Platform&& parOther) noexcept : + Placeable(parOther.GetPos()), m_screenRatio(std::move(parOther.m_screenRatio)), - m_position(parOther.m_position), m_size(parOther.m_size), m_surface(parOther.m_surface) { @@ -46,6 +46,17 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void Platform::Draw() const { - m_surface->Render(m_position, m_size, m_screenRatio.Ratio(), false); + m_surface->Render(TopLeft(), m_size, m_screenRatio.Ratio(), false); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + Platform& Platform::operator= (const Platform& parOther) { + Drawable::operator= (parOther); + Placeable::operator= (parOther); + + m_size = parOther.m_size; + m_surface = parOther.m_surface; + return *this; } } //namespace cloonel diff --git a/src/platform.hpp b/src/platform.hpp index ed8a2bf..ed1c7ce 100644 --- a/src/platform.hpp +++ b/src/platform.hpp @@ -22,28 +22,28 @@ #include "sizenotifiable.hpp" #include "drawable.hpp" +#include "placeable.hpp" namespace cloonel { class Texture; class SDLMain; - class Platform : public Drawable { + class Platform : public Drawable, public Placeable { public: Platform ( SDLMain* parSdlMain, const float2& parPos, Texture* parTexture, const float2& parSize ); - Platform ( Platform&& parOther ); + Platform ( Platform&& parOther ) noexcept; Platform ( const Platform& ) = delete; virtual ~Platform ( void ) noexcept = default; - Platform& operator= ( Platform&& parOther ) = delete; + Platform& operator= ( const Platform& parOther ); virtual void Draw ( void ) const; - const float2& TopLeft ( void ) const { return m_position; } - float2 BottomRight ( void ) const { return m_position + m_size; } + float2 TopLeft ( void ) const { return GetPos(); } + float2 BottomRight ( void ) const { return TopLeft() + m_size; } private: SizeNotifiable m_screenRatio; - float2 m_position; - const float2 m_size; - Texture* const m_surface; + float2 m_size; + Texture* m_surface; }; } //namespace cloonel diff --git a/src/platformsystem.cpp b/src/platformsystem.cpp index 178170d..066b1e9 100644 --- a/src/platformsystem.cpp +++ b/src/platformsystem.cpp @@ -22,57 +22,149 @@ #include "CloonelJumpConfig.h" #include "texture.hpp" #include "gameplayscene.hpp" +#include "mover.hpp" +#include "circularbuffer.hpp" #include #include #include +#include +#include namespace cloonel { + namespace { + const uint32_t g_platfWidth = 104; + const uint32_t g_platfHeight = 25; + } //unnamed namespace + + struct PlatformInfo { + PlatformInfo ( void ) : + platform(nullptr), + ticket(0) + { + } + PlatformInfo ( const PlatformInfo& ) = delete; + PlatformInfo ( Platform&& parPlatf ) noexcept : + platform(new Platform(std::move(parPlatf))), + ticket(0) + { + } + PlatformInfo ( PlatformInfo&& parOther ) noexcept : + platform(std::move(parOther.platform)), + ticket(parOther.ticket) + { + } + ~PlatformInfo ( void ) noexcept = default; + PlatformInfo& operator= ( const PlatformInfo& ) = delete; + PlatformInfo& operator= ( PlatformInfo&& parOther ) { + platform.swap(parOther.platform); + std::swap(ticket, parOther.ticket); + return *this; + } + + std::unique_ptr platform; + Mover::PlaceableTicketType ticket; + }; + + struct PlatformSystem::LocalData : public boost::noncopyable { + LocalData ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance, Mover& parMover ); + ~LocalData ( void ) noexcept = default; + + Mover& mover; + std::vector platformsBuff; + CircularBuffer::iterator> platforms; + Texture texture; + SDLMain* const sdlmain; + GameplayScene* const scene; + const float maxDistance; + }; + ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - PlatformSystem::PlatformSystem (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene) : - m_sizeRatio(parSDLMain), - m_platforms(), - m_texture(new Texture(parTexturePath, parSDLMain, false)), - m_sdlmain(parSDLMain), - m_scene(parScene) + PlatformSystem::LocalData::LocalData (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance, Mover& parMover) : + mover(parMover), + platformsBuff(MAX_PLATFORMS_ON_SCREEN), + platforms(platformsBuff.begin(), platformsBuff.end()), + texture(parTexturePath, parSDLMain, false), + sdlmain(parSDLMain), + scene(parScene), + maxDistance(parMaxDistance) + { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + PlatformSystem::PlatformSystem (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance, Mover& parMover) : + m_localdata(new LocalData(parTexturePath, parSDLMain, parScene, parMaxDistance, parMover)) { - assert(m_sdlmain); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- PlatformSystem::~PlatformSystem() noexcept { + Destroy(); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void PlatformSystem::SpawnPlatforms() { - const int2 refWH(REFERENCE_WIDTH, REFERENCE_HEIGHT); - const int2 platfWH(110, 30); - if (m_platforms.empty()) { - const float2 newPos(static_cast(std::rand() % (refWH.x() - platfWH.x())), static_cast(std::rand() % (refWH.y() - platfWH.y()))); - m_platforms.push(Platform(m_sdlmain, newPos, m_texture.get(), static_cast(platfWH))); - m_scene->AddDrawable(&m_platforms.back()); - } - } + //const int2 refWH(REFERENCE_WIDTH, REFERENCE_HEIGHT); + //const int2 platfWH(g_platfWidth, g_platfHeight); - ///-------------------------------------------------------------------------- - ///-------------------------------------------------------------------------- - void PlatformSystem::GarbageCollect() { - while (not m_platforms.empty() and m_platforms.front().TopLeft().y() <= 0.0f) { - m_platforms.pop(); - } + // if (m_localdata.platforms.back().platform->TopLeft().y() <= 0.0f) { + // const float2 newPos(static_cast(std::rand() % (refWH.x() - platfWH.x())), static_cast(std::rand() % (refWH.y() - platfWH.y()))); + + //if (m_localdata->platforms.empty()) { + // const float2 newPos(static_cast(std::rand() % (refWH.x() - platfWH.x())), static_cast(std::rand() % (refWH.y() - platfWH.y()))); + // m_localdata->platforms.push_back(Platform(m_localdata->sdlmain, newPos, &m_localdata->texture, static_cast(platfWH))); + + // PlatformInfo& newPlatf = m_localdata->platforms.back(); + // m_localdata->scene->AddDrawable(&newPlatf.platform); + // const Mover::PlaceableTicketType ticket = m_localdata->mover.RegisterPlaceable(&newPlatf.platform); + // newPlatf.ticket = ticket; + //} } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void PlatformSystem::Prepare() { - m_texture->Reload(); + m_localdata->texture.Reload(); + + //Spawn the initial platforms + m_localdata->platforms.reset(); + const size_t totalPlatf = m_localdata->platforms.capacity(); + const auto totalPlatfFloatInv = 1.0f / static_cast(totalPlatf); + const int2 platfWH(g_platfWidth, g_platfHeight); + for (size_t z = 0; z < totalPlatf; ++z) { + const float y = std::min( + static_cast(REFERENCE_HEIGHT) - 25.0f, + static_cast(z) * (static_cast(REFERENCE_HEIGHT) * totalPlatfFloatInv) + ); + const auto rndNum = std::rand() % (REFERENCE_WIDTH - platfWH.x()); + const float2 newPos(static_cast(rndNum), 100.0f + std::min(m_localdata->maxDistance, y)); + m_localdata->platforms.push(Platform(m_localdata->sdlmain, newPos, &m_localdata->texture, static_cast(platfWH))); + } } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void PlatformSystem::Destroy() noexcept { - m_texture->Destroy(); + m_localdata->texture.Destroy(); + + for (size_t z = 0; z < m_localdata->platforms.size(); ++z) { + m_localdata->mover.UnregisterPlaceable(m_localdata->platforms[z].ticket); + } + m_localdata->platforms.reset(); + m_localdata->platformsBuff.clear(); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSystem::AddDrawables() { + for (size_t z = 0; z < m_localdata->platforms.size(); ++z) { + PlatformInfo& newPlatf = m_localdata->platforms[z]; + m_localdata->scene->AddDrawable(newPlatf.platform.get()); + const Mover::PlaceableTicketType ticket = m_localdata->mover.RegisterPlaceable(newPlatf.platform.get()); + newPlatf.ticket = ticket; + } } } //namespace cloonel diff --git a/src/platformsystem.hpp b/src/platformsystem.hpp index b4be75c..7b6324e 100644 --- a/src/platformsystem.hpp +++ b/src/platformsystem.hpp @@ -19,36 +19,31 @@ #ifndef id17908979556C47F8A978688BBE4A9D22 -#include "sizenotifiable.hpp" -#include #include namespace cloonel { - class Platform; class SDLMain; - class Texture; class GameplayScene; + class Mover; class PlatformSystem { public: PlatformSystem ( void ) = delete; - PlatformSystem ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene ); + PlatformSystem ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance, Mover& parMover ); PlatformSystem ( const PlatformSystem& ) = delete; PlatformSystem ( PlatformSystem&& parOther ) = delete; ~PlatformSystem ( void ) noexcept; PlatformSystem& operator= ( const PlatformSystem& ) = delete; void Prepare ( void ); + void AddDrawables ( void ); void Destroy ( void ) noexcept; void SpawnPlatforms ( void ); - void GarbageCollect ( void ); private: - SizeNotifiable m_sizeRatio; - std::queue m_platforms; - const std::unique_ptr m_texture; - SDLMain* const m_sdlmain; - GameplayScene* const m_scene; + struct LocalData; + + const std::unique_ptr m_localdata; }; } //namespace cloonel