diff --git a/CMakeLists.txt b/CMakeLists.txt index 6509b17..e883a38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,15 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11 -Wall -Wextra -pe set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11 -Wall -Wextra -pedantic -Wconversion") option(WITH_BUILTIN_PHYSFS "Force using the version of PhysFS accompanying the code even if a system library is available" OFF) +option(FORCE_OPENGLES "Try to chose the openGL ES renderer if available. Enable this on Raspberry Pi" OFF) +option(RASPBERRY_PI "Compile for Raspberry Pi" OFF) + +if (FORCE_OPENGLES OR RASPBERRY_PI) + add_definitions(-DFORCE_OPENGLES) + if (RASPBERRY_PI) + add_definitions(-DRASPBERRY_PI) + endif(RASPBERRY_PI) +endif (FORCE_OPENGLES OR RASPBERRY_PI) include(FindPkgConfig) PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) @@ -26,9 +35,22 @@ endif(PHYSFS_FOUND) add_definitions( ${PNG_DEFINITIONS} - -DWITH_VERBOSE_OBS_MANAGER +# -DWITH_VERBOSE_OBS_MANAGER + -DWITH_VERBOSE_COLLIDER ) +if (RASPBERRY_PI) + message(STATUS "Will build for Raspberry Pi") + include_directories(SYSTEM + /opt/vc/include + /opt/vc/include/interface/vcos/pthreads + /opt/vc/include/interface/vmcs_host/linux + ) + link_directories( + /opt/vc/lib + ) +endif (RASPBERRY_PI) + include_directories(SYSTEM ${SDL2_INCLUDE_DIR} ${PNG_INCLUDE_DIRS} @@ -76,10 +98,11 @@ add_executable(${PROJECT_NAME} src/horzcollisionbar.cpp src/platform.cpp src/vectormath.cpp - src/platformsystem.cpp + src/platformspawner.cpp src/movers/moverworld.cpp src/line.cpp src/collider.cpp + src/platformset.cpp ) target_link_libraries(${PROJECT_NAME} @@ -87,3 +110,9 @@ target_link_libraries(${PROJECT_NAME} ${PHYSFS_LIBRARY} ${PNG_LIBRARIES} ) + +if (RASPBERRY_PI) + target_link_libraries(${PROJECT_NAME} + bcm_host + ) +endif(RASPBERRY_PI) diff --git a/src/CloonelJumpConfig.h.in b/src/CloonelJumpConfig.h.in index 1d2fc18..99c66d6 100644 --- a/src/CloonelJumpConfig.h.in +++ b/src/CloonelJumpConfig.h.in @@ -21,7 +21,7 @@ #define id5FC1D6EEF9DF41E790068FBC6753035F #define GameName "@PROJECT_NAME@" -#define GameVersionMinor 11 +#define GameVersionMinor 12 #define GameVersionMajor 0 #define REFERENCE_WIDTH 480 @@ -32,6 +32,8 @@ #define MAX_PLATFORMS_ON_SCREEN 24 #define REFERENCE_PLATFORM_WIDTH 104 #define REFERENCE_PLATFORM_HEIGHT 25 +#define REFERENCE_CHARA_WIDTH 55 +#define REFERENCE_CHARA_HEIGHT 70 /* TODO: make this path relative */ #define GAME_BASE_PATH "@CMAKE_SOURCE_DIR@" diff --git a/src/character.cpp b/src/character.cpp index 0e4370f..f59b7e3 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -20,9 +20,16 @@ #include "character.hpp" #include "sdlmain.hpp" #include "texture.hpp" +#include "collider.hpp" +#include "line.hpp" #include namespace cloonel { + namespace { + void DoNothing (const Line&, const float2&) { + } + } //unnamed namespace + ///------------------------------------------------------------------------- ///------------------------------------------------------------------------- Character::Character (const std::string& parPath, SDLMain* parMain, float2 parSize) : @@ -30,9 +37,11 @@ namespace cloonel { Drawable(parSize), m_bottomBar(float2(0.0f), parSize.x()), m_screenRatio(parMain), + m_bounceCallback(&DoNothing), m_texture(new Texture(parPath, parMain, false)) { assert(parMain); + m_bottomBar.SetCallback(std::bind(&Character::OnBounce, this, std::placeholders::_1, std::placeholders::_2)); } ///------------------------------------------------------------------------- @@ -42,9 +51,11 @@ namespace cloonel { Drawable(parSize), m_bottomBar(float2(0.0f), parSize.x()), m_screenRatio(parMain), + m_bounceCallback(&DoNothing), m_texture(new Texture(parPath, parMain, false)) { assert(parMain); + m_bottomBar.SetCallback(std::bind(&Character::OnBounce, this, std::placeholders::_1, std::placeholders::_2)); } ///------------------------------------------------------------------------- @@ -52,6 +63,12 @@ namespace cloonel { Character::~Character() noexcept { } + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + void Character::RegisterForCollision (ColliderRegisterFunc parRegisterCollision) { + parRegisterCollision(&m_bottomBar); + } + ///------------------------------------------------------------------------- ///------------------------------------------------------------------------- void Character::Prepare() { @@ -72,4 +89,27 @@ namespace cloonel { void Character::Draw() const { m_texture->Render(GetPos(), WidthHeight(), m_screenRatio.Ratio(), true); } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + void Character::OnRegister (Mover& parMover, Mover::PlaceableTicketType parParentTicket) { + parMover.RegisterPlaceable(&m_bottomBar, parParentTicket); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + void Character::SetOnBounceCallback (BounceCallbackType parCallb) { + m_bounceCallback = parCallb; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + void Character::OnBounce (const Line& parCollision, const float2& parDirection) { + if (parDirection.y() < 0.0f) { + const float2 newPos(GetPos().x(), parCollision.Start().y()); + this->SetAbsolutePosition(newPos); + m_bottomBar.SetAbsolutePosition(newPos); + m_bounceCallback(parCollision, parDirection); + } + } } //namespace cloonel diff --git a/src/character.hpp b/src/character.hpp index d758723..97f44a8 100644 --- a/src/character.hpp +++ b/src/character.hpp @@ -22,29 +22,47 @@ #include "placeable.hpp" #include "drawable.hpp" +#include "drawableset.hpp" #include "vector.hpp" #include "sizenotifiable.hpp" #include "horzcollisionbar.hpp" +#include "collidertypedef.hpp" #include #include +#include +#include +#include namespace cloonel { class SDLMain; class Texture; + template class Line; - class Character : public Placeable, public Drawable { + class Character : public Placeable, public Drawable, public DrawableSet { public: + typedef std::function&, const float2&)> BounceCallbackType; + Character ( const std::string& parPath, SDLMain* parMain, float2 parSize ); - Character ( const std::string&& parPath, SDLMain* parMai, float2 parSize ); + Character ( const std::string&& parPath, SDLMain* parMain, float2 parSize ); + Character ( const Character& ) = delete; virtual ~Character ( void ) noexcept; void Prepare ( void ); void Destroy ( void ) noexcept; virtual void Draw ( void ) const; + void RegisterForCollision ( ColliderRegisterFunc parRegisterCollision ); + void SetOnBounceCallback ( BounceCallbackType parCallb ); private: + //Overrides + virtual void OnRegister ( Mover& parMover, Mover::PlaceableTicketType parParentTicket ); + virtual void CopyDrawables ( std::vector& parOut ) const { parOut.push_back(this); } + + void OnBounce ( const Line& parCollision, const float2& parDirection ); + HorzCollisionBar m_bottomBar; SizeNotifiable m_screenRatio; + BounceCallbackType m_bounceCallback; const std::unique_ptr m_texture; }; } //unnamed namespace diff --git a/src/collider.cpp b/src/collider.cpp index eb54051..78439af 100644 --- a/src/collider.cpp +++ b/src/collider.cpp @@ -18,6 +18,11 @@ */ #include "collider.hpp" +#include "horzcollisionbar.hpp" +#include "line.hpp" +#include "vector.hpp" +#include "collisionbarset.hpp" +#include "vectormath.hpp" #include #include #include @@ -30,6 +35,106 @@ namespace cloonel { namespace { + typedef std::vector CollisionBarListType; + typedef std::vector> CollisionBarGroupListType; + typedef std::vector CollisionBarSetListType; + typedef std::vector> CollisionBarSetsListType; + + const CollisionBarListType g_emptyBars; + const CollisionBarSetListType g_emptySets; + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + const CollisionBarListType& findGroup (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) { + for (const auto& itm : parList) { + if (itm.first == parID) { + return itm.second; + } + } + return g_emptyBars; + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + const CollisionBarSetListType& findGroup (const CollisionBarSetsListType& parList, Collider::GroupIDType parID) { + for (const auto& itm : parList) { + if (itm.first == parID) { + return itm.second; + } + } + return g_emptySets; + } + +#if !defined(NDEBUG) + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + bool isGroupRegistered (const CollisionBarGroupListType& parList, Collider::GroupIDType parID) { + const CollisionBarListType& result = findGroup(parList, parID); + return &g_emptyBars != &result; + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + bool isGroupRegistered (const CollisionBarSetsListType& parList, Collider::GroupIDType parID) { + const CollisionBarSetListType& result = findGroup(parList, parID); + return &g_emptySets != &result; + } +#endif + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + template + typename L::value_type::second_type& findOrAddGroup (L& parList, Collider::GroupIDType parID) { + for (auto& itm : parList) { + if (itm.first == parID) { + return itm.second; + } + } + parList.push_back(std::make_pair(parID, typename L::value_type::second_type())); + assert(parList.back().first == parID); + return parList.back().second; + } + + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + void collide (float parDeltaT, const CollisionBarListType& parGroup1, const CollisionBarListType& parGroup2) { + Line overlap; + for (const auto& bar1 : parGroup1) { + assert(bar1); + for (const auto& bar2 : parGroup2) { + assert(bar2); + if (bar2 == bar1) + continue; + + if (Collide(parDeltaT, *bar1, *bar2, overlap)) { +#if defined(VERBOSE_COLLIDER) + std::cout << "Collider: Collision "; + std::cout << "between " << bar1 << " and " << bar2 << "\n"; +#endif + const auto& offs1 = bar1->GetOffset(); + const auto& offs2 = bar2->GetOffset(); + float2 dir1, dir2; + if (offs1 == float2(0.0f) and offs2 == float2(0.0f)) { + dir1 = dir2 = float2(0.0f); + } + else if (offs1 == float2(0.0f)) { + dir2 = normalized(offs2); + dir1 = -1.0f * dir2; + } + else if (offs2 == float2(0.0f)) { + dir1 = normalized(offs1); + dir2 = -1.0f * dir1; + } + else { + dir1 = normalized(offs1); + dir2 = normalized(offs2); + } + bar1->InvokeCallback(overlap, dir1); + bar2->InvokeCallback(overlap, dir2); + } + } + } + } } //unnamed namespace ///-------------------------------------------------------------------------- @@ -44,7 +149,103 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void Collider::RunCollisionTests() { + void Collider::RunCollisionTests (float parDeltaT) const { + CollisionBarGroupListType collectedGroups; + //For each CollisionBarSet list+ID + for (const auto& set : m_collisionBarSets) { + //Get or make a list for the currend ID + CollisionBarListType& newList = findOrAddGroup(collectedGroups, set.first); + //For each CollisionBarSet with the current ID + for (auto setObject : set.second) { +#if !defined(NDEBUG) + const size_t oldListSize = newList.size(); + const CollisionBar* const lastCollisionBar = (oldListSize == 0 ? nullptr : newList.back()); +#endif + //Get the collision bars in the current list + setObject->CopyBars(newList); + + //Make sure the CollisionBarSet didn't tamper with elements already in the list + assert(oldListSize <= newList.size()); + assert(0 == oldListSize or newList[oldListSize - 1] == lastCollisionBar); + } + } + + for (const auto& relationship : m_relationships) { + const CollisionBarListType& group1 = findGroup(m_collisionBars, relationship.first); + const CollisionBarListType& group2 = (relationship.first == relationship.second ? group1 : findGroup(m_collisionBars, relationship.second)); + const CollisionBarListType& group1a = findGroup(collectedGroups, relationship.first); + const CollisionBarListType& group2a = (relationship.first == relationship.second ? group1a : findGroup(collectedGroups, relationship.second)); + + collide(parDeltaT, group1, group2); + collide(parDeltaT, group1, group2a); + collide(parDeltaT, group1a, group2); + collide(parDeltaT, group1a, group2a); + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::TieGroups (GroupIDType parGroup1, GroupIDType parGroup2) { +#if defined(VERBOSE_COLLIDER) + std::cout << "Collider: Tying group " << parGroup1 << " to " << parGroup2 << " for collision tests\n"; +#endif + assert(m_relationships.end() == std::find(m_relationships.begin(), m_relationships.end(), std::make_pair(parGroup1, parGroup2))); + assert(m_relationships.end() == std::find(m_relationships.begin(), m_relationships.end(), std::make_pair(parGroup2, parGroup1))); + assert(isGroupRegistered(m_collisionBars, parGroup1) or isGroupRegistered(m_collisionBarSets, parGroup1)); + assert(isGroupRegistered(m_collisionBars, parGroup2) or isGroupRegistered(m_collisionBarSets, parGroup2)); + m_relationships.push_back(std::make_pair(parGroup1, parGroup2)); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::RegisterBar (GroupIDType parGroup, const CollisionBar* parBar) { +#if defined(VERBOSE_COLLIDER) + std::cout << "Collider: Registering bar " << parBar << " in group " << parGroup << "\n"; +#endif + CollisionBarListType& group = findOrAddGroup(m_collisionBars, parGroup); + assert(isGroupRegistered(m_collisionBars, parGroup)); + assert(parBar); + group.push_back(parBar); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::UnregisterBar (GroupIDType parGroup, const CollisionBar* parBar) { + assert(isGroupRegistered(m_collisionBars, parGroup)); + CollisionBarListType& group = findOrAddGroup(m_collisionBars, parGroup); + auto itdele = std::find(group.begin(), group.end(), parBar); + assert(itdele != group.end()); + group.erase(itdele); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::Reset() noexcept { + m_relationships.clear(); + m_collisionBars.clear(); + m_collisionBarSets.clear(); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::RegisterBarSet (GroupIDType parGroup, const CollisionBarSet* parSet) { +#if defined(VERBOSE_COLLIDER) + std::cout << "Collider: Registering bar set " << parSet << " in group " << parGroup << "\n"; +#endif + CollisionBarSetListType& group = findOrAddGroup(m_collisionBarSets, parGroup); + assert(isGroupRegistered(m_collisionBarSets, parGroup)); + assert(parSet); + group.push_back(parSet); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Collider::UnregisterBarSet (GroupIDType parGroup, const CollisionBarSet* parSet) { + assert(isGroupRegistered(m_collisionBarSets, parGroup)); + CollisionBarSetListType& group = findOrAddGroup(m_collisionBarSets, parGroup); + auto itdele = std::find(group.begin(), group.end(), parSet); + assert(itdele != group.end()); + group.erase(itdele); } } //namespace cloonel diff --git a/src/collider.hpp b/src/collider.hpp index a43bcff..577d877 100644 --- a/src/collider.hpp +++ b/src/collider.hpp @@ -22,18 +22,38 @@ #include "observersmanager.hpp" #include +#include +#include namespace cloonel { class HorzCollisionBar; + class CollisionBarSet; + + typedef HorzCollisionBar CollisionBar; class Collider { public: + typedef int GroupIDType; + Collider ( void ); ~Collider ( void ) noexcept; - void RunCollisionTests ( void ); + void RunCollisionTests ( float parDeltaT ) const; + void TieGroups ( GroupIDType parGroup1, GroupIDType parGroup2 ); + void RegisterBar ( GroupIDType parGroup, const CollisionBar* parBar ); + void UnregisterBar ( GroupIDType parGroup, const CollisionBar* parBar ); + void RegisterBarSet ( GroupIDType parGroup, const CollisionBarSet* parSet ); + void UnregisterBarSet ( GroupIDType parGroup, const CollisionBarSet* parSet ); + void Reset ( void ) noexcept; private: + typedef std::vector>> CollisionBarGroupListType; + typedef std::vector>> CollisionBarSetsListType; + typedef std::vector> RelationshipListType; + + RelationshipListType m_relationships; + CollisionBarGroupListType m_collisionBars; + CollisionBarSetsListType m_collisionBarSets; }; } //namespace cloonel diff --git a/src/collidertypedef.hpp b/src/collidertypedef.hpp new file mode 100644 index 0000000..759725a --- /dev/null +++ b/src/collidertypedef.hpp @@ -0,0 +1,32 @@ +/* + 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 id3DF7C722C6AE4978874605F38F26E350 +#define id3DF7C722C6AE4978874605F38F26E350 + +#include + +namespace cloonel { + class HorzCollisionBar; + typedef std::function ColliderRegisterFunc; + typedef std::function ColliderUnregisterFunc; +} //namespace cloonel + +#endif diff --git a/src/collisionbarset.hpp b/src/collisionbarset.hpp new file mode 100644 index 0000000..563d6ed --- /dev/null +++ b/src/collisionbarset.hpp @@ -0,0 +1,35 @@ +/* + 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 id0632E9698575456ABDB19F9BB0AFE492 +#define id0632E9698575456ABDB19F9BB0AFE492 + +#include + +namespace cloonel { + class HorzCollisionBar; + + class CollisionBarSet { + public: + virtual void CopyBars ( std::vector& parOut ) const = 0; + }; +} //namespace cloonel + +#endif diff --git a/src/drawableset.hpp b/src/drawableset.hpp new file mode 100644 index 0000000..975169e --- /dev/null +++ b/src/drawableset.hpp @@ -0,0 +1,35 @@ +/* + 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 idBFBF4D5B34DD49E68B89249AA1D8FCE4 +#define idBFBF4D5B34DD49E68B89249AA1D8FCE4 + +#include + +namespace cloonel { + class Drawable; + + class DrawableSet { + public: + virtual void CopyDrawables ( std::vector& parOut ) const = 0; + }; +} //namespace cloonel + +#endif diff --git a/src/gameplayscene.cpp b/src/gameplayscene.cpp index 9826819..2b48d56 100644 --- a/src/gameplayscene.cpp +++ b/src/gameplayscene.cpp @@ -20,6 +20,9 @@ #include "gameplayscene.hpp" #include "mover.hpp" #include "drawable.hpp" +#include "drawableset.hpp" +#include "placeable.hpp" +#include namespace cloonel { ///-------------------------------------------------------------------------- @@ -32,23 +35,39 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void GameplayScene::OnUpdate (float parDelta) { - for (auto itMover : m_movers) { - itMover->Update(parDelta); + { + std::unordered_set notify; + for (auto mover : m_movers) { + mover->CopyPlaceables(notify); + } + for (auto placeable : notify) { + assert(placeable); + placeable->BeginMovement(); + } } - m_collider.RunCollisionTests(); + for (auto mover : m_movers) { + mover->Update(parDelta); + } + m_collider.RunCollisionTests(parDelta); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void GameplayScene::OnRender() { - for (auto itDrawable : m_drawables) { - itDrawable->Draw(); + std::vector drawables; + for (auto drawableSet : m_drawableSets) { + drawables.clear(); + drawableSet->CopyDrawables(drawables); + for (auto drawable : drawables) { + drawable->Draw(); + } } } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void GameplayScene::Destroy() noexcept { + m_collider.Reset(); } ///-------------------------------------------------------------------------- diff --git a/src/gameplayscene.hpp b/src/gameplayscene.hpp index bbc2b3e..b4a7d38 100644 --- a/src/gameplayscene.hpp +++ b/src/gameplayscene.hpp @@ -27,7 +27,7 @@ namespace cloonel { class Mover; - class Drawable; + class DrawableSet; class GameplayScene : public GameBase { public: @@ -35,12 +35,12 @@ namespace cloonel { virtual ~GameplayScene ( void ) noexcept = default; void AddMover ( Mover* parMover ) { assert(parMover); m_movers.push_back(parMover); } - void AddDrawable ( const Drawable* parDrawable ) { assert(parDrawable); m_drawables.push_back(parDrawable); } + void AddDrawableSet ( const DrawableSet* parSet ) { assert(parSet); m_drawableSets.push_back(parSet); } virtual void Destroy ( void ) noexcept; protected: - Collider* GetCollider ( void ); + Collider* GetCollider ( void ) { return &m_collider; } private: virtual void OnRender ( void ); @@ -49,7 +49,7 @@ namespace cloonel { Collider m_collider; std::vector m_movers; - std::vector m_drawables; + std::vector m_drawableSets; }; } //namespace cloonel diff --git a/src/gameplaysceneclassic.cpp b/src/gameplaysceneclassic.cpp index 09fc604..5281773 100644 --- a/src/gameplaysceneclassic.cpp +++ b/src/gameplaysceneclassic.cpp @@ -27,11 +27,12 @@ #include "moverworld.hpp" #include "tiledwallpaper.hpp" #include "texture.hpp" -#include "platformsystem.hpp" +#include "platformspawner.hpp" #include "CloonelJumpConfig.h" #include #include #include +#include namespace cloonel { namespace { @@ -39,6 +40,16 @@ namespace cloonel { GameAction_Left, GameAction_Right }; + + enum { + CollisionID_Platforms, + CollisionID_Player, + CollisionID_Enemies + }; + + void OnCharacterBounce (MoverSine* parMover, const Line&, const float2&) { + parMover->ResetToBounce(); + } } //unnamed namespace ///-------------------------------------------------------------------------- @@ -62,13 +73,15 @@ namespace cloonel { ///-------------------------------------------------------------------------- void GameplaySceneClassic::OnPrepare() { const float halfRefHeight = static_cast(REFERENCE_HEIGHT) / 2.0f; + Collider& collider = *this->GetCollider(); + const float2 charaRefSize(static_cast(REFERENCE_CHARA_WIDTH), static_cast(REFERENCE_CHARA_HEIGHT)); 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 player(new Character("resources/graphics/player.png", SDLObject(), charaRefSize)); 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, halfRefHeight * 0.9f)); + std::unique_ptr platforms(new PlatformSpawner("resources/graphics/platform.png", SDLObject(), this, halfRefHeight * 0.9f)); player->Prepare(); platforms->Prepare(); @@ -80,6 +93,14 @@ namespace cloonel { moverWorld->RegisterPlaceable(platforms.get()); wallpaper->Reload(); + { + auto regPlayerCollision(std::bind(&Collider::RegisterBar, &collider, CollisionID_Player, std::placeholders::_1)); + player->RegisterForCollision(regPlayerCollision); + } + platforms->RegisterForCollision(collider, CollisionID_Platforms); + + player->SetOnBounceCallback(std::bind(&OnCharacterBounce, moverSine.get(), std::placeholders::_1, std::placeholders::_2)); + std::swap(moverSine, m_moverSine); std::swap(player, m_player); std::swap(moverLeftRight, m_moverLeftRight); @@ -89,13 +110,16 @@ namespace cloonel { AddMover(m_moverSine.get()); AddMover(m_moverLeftRight.get()); - AddDrawable(m_wallpaper.get()); + AddDrawableSet(m_wallpaper.get()); AddMover(m_moverWorld.get()); - m_platforms->AddDrawables(); - AddDrawable(m_player.get()); + AddDrawableSet(m_platforms->GetDrawableSet()); + AddDrawableSet(m_player.get()); - const float jumpPower = halfRefHeight * 1.29f; + const float jumpPower = halfRefHeight * 0.71f; m_moverSine->SetPower(jumpPower); + + collider.TieGroups(CollisionID_Platforms, CollisionID_Player); + //collider.TieGroups(CollisionID_Enemies, CollisionID_Player); } ///-------------------------------------------------------------------------- @@ -104,13 +128,12 @@ namespace cloonel { GameplayScene::Destroy(); //Destroy in reverse creation order - m_platforms = std::move(std::unique_ptr(nullptr)); + 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 686779c..796e2ba 100644 --- a/src/gameplaysceneclassic.hpp +++ b/src/gameplaysceneclassic.hpp @@ -31,7 +31,7 @@ namespace cloonel { class MoverWorld; class TiledWallpaper; class Texture; - class PlatformSystem; + class PlatformSpawner; class GameplaySceneClassic : public GameplayScene { public: @@ -49,7 +49,7 @@ namespace cloonel { std::unique_ptr m_moverLeftRight; std::unique_ptr m_moverWorld; std::unique_ptr m_wallpaper; - std::unique_ptr m_platforms; + std::unique_ptr m_platforms; }; } //namespace cloonel diff --git a/src/horzcollisionbar.cpp b/src/horzcollisionbar.cpp index 04f9bf8..76704c4 100644 --- a/src/horzcollisionbar.cpp +++ b/src/horzcollisionbar.cpp @@ -26,10 +26,10 @@ namespace cloonel { namespace { - typedef Line Line2D; + typedef HorzCollisionBar::Line2D Line2D; float calculateOverlappingTime ( float parDeltaT, float parAY, float parBY, float parDeltaA, float parDeltaB ) __attribute__((pure)); - void DoNothing ( void ) __attribute__((pure)); + void DoNothing ( const Line2D&, const float2& ) __attribute__((pure)); std::pair getOverlap ( float parDeltaT, const Line2D& parA, const Line2D& parB, const float2& parDeltaA, const float2& parDeltaB ) __attribute__((pure)); ///---------------------------------------------------------------------- @@ -41,8 +41,8 @@ namespace cloonel { ///reference time frame. ///---------------------------------------------------------------------- float calculateOverlappingTime (float parDeltaT, float parAY, float parBY, float parDeltaA, float parDeltaB) { - const float deltaDiff = std::max(parDeltaA, parDeltaB) - std::min(parDeltaA, parDeltaB); - assert(deltaDiff >= 0.0f); + //const float deltaDiff = std::max(parDeltaA, parDeltaB) - std::min(parDeltaA, parDeltaB); + const float deltaDiff = std::abs(parDeltaA - parDeltaB); if (deltaDiff <= 0.00001f) return 0.0f; @@ -67,13 +67,13 @@ namespace cloonel { const auto& retStart = (midpointA.Start().x() > midpointB.Start().x() ? midpointA.Start() : midpointB.Start()); const auto& retEnd = (midpointA.End().x() < midpointB.End().x() ? midpointA.End() : midpointB.End()); - return std::make_pair(true, Line2D(retStart, retEnd)); + return std::make_pair(true, Line2D(retStart, float2(retEnd.x(), retStart.y()))); } ///---------------------------------------------------------------------- ///no-op ///---------------------------------------------------------------------- - void DoNothing() { + void DoNothing (const HorzCollisionBar::Line2D&, const float2&) { } } //unnamed namespace @@ -82,6 +82,7 @@ namespace cloonel { HorzCollisionBar::HorzCollisionBar (const float2& parFrom, float parLength) : Placeable(parFrom), m_segment(parFrom, float2(1.0f, 0.0f), parLength), + m_offset(0.0f), m_callback(&DoNothing) { assert(parLength != 0.0f); @@ -89,7 +90,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void HorzCollisionBar::SetCallback (std::function parCallback) { + void HorzCollisionBar::SetCallback (CallbackType parCallback) { m_callback = parCallback; } @@ -101,10 +102,28 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - bool Collide (float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut) { - const auto offsetA = parA.GetPos() - parA.m_segment.Start(); - const auto offsetB = parB.GetPos() - parB.m_segment.Start(); - const auto overlap(getOverlap(parDeltaT, parA.m_segment, parB.m_segment, offsetA, offsetB)); + void HorzCollisionBar::InvokeCallback (const Line2D& parOverlap, const float2& parDirection) const { + m_callback(parOverlap, parDirection); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void HorzCollisionBar::AddOffset (const float2& parOffset) noexcept { + Placeable::AddOffset(parOffset); + m_segment += parOffset; + m_offset += parOffset; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void HorzCollisionBar::BeginMovement() { + m_offset = float2(0.0f); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + bool Collide (float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut) { + const auto overlap(getOverlap(parDeltaT, parA.m_segment, parB.m_segment, parA.GetOffset(), parB.GetOffset())); if (overlap.first) { parOut = overlap.second; diff --git a/src/horzcollisionbar.hpp b/src/horzcollisionbar.hpp index 88c13c5..71e046b 100644 --- a/src/horzcollisionbar.hpp +++ b/src/horzcollisionbar.hpp @@ -29,22 +29,34 @@ namespace cloonel { class HorzCollisionBar; class HorzCollisionBar : public Placeable { - friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut ); + public: + typedef Line Line2D; + typedef std::function CallbackType; + public: HorzCollisionBar ( const float2& parFrom, float parLength ); - ~HorzCollisionBar ( void ) noexcept = default; + virtual ~HorzCollisionBar ( void ) noexcept = default; float2 From ( void ) const { return this->GetPos(); } float2 To ( void ) const; - void SetCallback ( std::function parCallback ); + void SetCallback ( CallbackType parCallback ); + void InvokeCallback ( const Line2D& parOverlap, const float2& parDirection ) const; + const float2& GetOffset ( void ) const noexcept { return m_offset; } + + //Overrides + virtual void AddOffset ( const float2& parOffset ) noexcept; + virtual void BeginMovement ( void ); private: - Line m_segment; - std::function m_callback; + friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line2D& parOut ); + + Line2D m_segment; + float2 m_offset; + CallbackType m_callback; }; - bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line& parOut ) __attribute__((pure)); + bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut ) __attribute__((pure)); } //namespace cloonel #endif diff --git a/src/line.hpp b/src/line.hpp index d0b37fd..9b12d3a 100644 --- a/src/line.hpp +++ b/src/line.hpp @@ -31,9 +31,10 @@ namespace cloonel { typedef T Scalar; Line ( void ) {} + explicit Line ( Scalar parValue ); Line ( const Line& parOther ); Line ( const Point& parStart, const Point& parEnd ); - Line ( const Point& parStart, const Point& parDirection, Scalar parLength ) : Line(parStart, parDirection * parLength) { } + Line ( const Point& parStart, const Point& parDirection, Scalar parLength ) : Line(parStart, parStart + parDirection * parLength) { } ~Line ( void ) noexcept = default; Point& Start ( void ) { return m_points.x(); } diff --git a/src/line.inl b/src/line.inl index 91e6929..6aae70b 100644 --- a/src/line.inl +++ b/src/line.inl @@ -7,6 +7,14 @@ namespace cloonel { { } + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + Line::Line (Scalar parValue) : + m_points(Point(parValue)) + { + } + ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- template @@ -14,13 +22,13 @@ namespace cloonel { m_points(parStart, parEnd) { } + ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- template Line& Line::operator+= (const Point& parRhs) { - for (uint32_t z = 0; z < S; ++z) { - m_points[z] += parRhs; - } + m_points.x() += parRhs; + m_points.y() += parRhs; return *this; } @@ -28,9 +36,8 @@ namespace cloonel { ///-------------------------------------------------------------------------- template Line& Line::operator-= (const Point& parRhs) { - for (uint32_t z = 0; z < S; ++z) { - m_points[z] -= parRhs; - } + m_points.x() -= parRhs; + m_points.y() -= parRhs; return *this; } @@ -109,4 +116,17 @@ namespace cloonel { const T dotproduct = dot(linePerp, pt); return (dotproduct <= T(0)); } + +#if !defined(NDEBUG) + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + std::ostream& operator<< ( std::ostream& parStream, const Line& parLine ) { + for (uint32_t z = 0; z < S - 1; ++z) { + parStream << parLine[z] << "-"; + } + parStream << parLine[S - 1]; + return parStream; + } +#endif } //namespace cloonel diff --git a/src/main.cpp b/src/main.cpp index 1edfad4..d03f5db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,8 @@ int main (int, char* parArgv[]) { physfs.Append(GAME_BASE_PATH "/resources/", "resources"); sdlmain.Init(); + std::cout << "Using renderer \"" << sdlmain.GetRendererName() << "\" "; + std::cout << "and video driver \"" << sdlmain.GetVideoDriverName() << "\"\n"; cloonel::GameplaySceneClassic game(&sdlmain); RunMainLoop(game); diff --git a/src/movers/mover.cpp b/src/movers/mover.cpp index 234ddfc..7da8bf0 100644 --- a/src/movers/mover.cpp +++ b/src/movers/mover.cpp @@ -45,4 +45,10 @@ namespace cloonel { parPlaceable->OnRegister(*this, currTicket); return currTicket; } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Mover::CopyPlaceables (std::unordered_set& parOut) { + m_placeables.CopyObservers(parOut); + } } //namespace cloonel diff --git a/src/movers/mover.hpp b/src/movers/mover.hpp index e0e6a63..5e3e7d8 100644 --- a/src/movers/mover.hpp +++ b/src/movers/mover.hpp @@ -22,6 +22,7 @@ #include "vector.hpp" #include "observersmanager.hpp" +#include namespace cloonel { class Placeable; @@ -40,6 +41,7 @@ namespace cloonel { virtual void Update ( float parDelta ); PlaceableTicketType RegisterPlaceable ( Placeable* parPlaceable, PlaceableTicketType parParent=ObserversManager::Ticket_Null ); void UnregisterPlaceable ( PlaceableTicketType parID ) noexcept { m_placeables.Remove(parID); } + void CopyPlaceables ( std::unordered_set& parOut ); protected: std::size_t PlaceableCount ( void ) const { return m_placeables.size(); } diff --git a/src/movers/moversine.cpp b/src/movers/moversine.cpp index a1bf299..cf86823 100644 --- a/src/movers/moversine.cpp +++ b/src/movers/moversine.cpp @@ -47,4 +47,10 @@ namespace cloonel { while (m_alpha >= pitwo) m_alpha -= pitwo; } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void MoverSine::ResetToBounce() { + m_alpha = 0.0f; + } } //namespace cloonel diff --git a/src/movers/moversine.hpp b/src/movers/moversine.hpp index d6ccaa3..a11fefd 100644 --- a/src/movers/moversine.hpp +++ b/src/movers/moversine.hpp @@ -29,6 +29,7 @@ namespace cloonel { ~MoverSine ( void ) noexcept = default; void SetPower ( float parPower ) noexcept { m_power = parPower; } + void ResetToBounce ( void ); private: virtual void ApplyMotion ( float parDelta ); diff --git a/src/observersmanager.hpp b/src/observersmanager.hpp index 3d1c865..926c532 100644 --- a/src/observersmanager.hpp +++ b/src/observersmanager.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #if defined (WITH_VERBOSE_OBS_MANAGER) && defined(__GNUC__) && __GNUC__ >= 2 && !defined(NDEBUG) # define OBS_MANAGER_LOG @@ -78,6 +79,7 @@ namespace cloonel { std::size_t size ( void ) const { return m_tree.size(); } iterator begin ( void ) { return iterator(m_tree.begin(), &TicketedWrapperToItm); } iterator end ( void ) { return iterator(m_tree.end(), &TicketedWrapperToItm); } + void CopyObservers ( std::unordered_set& parOut ); private: TreeIteratorType GetByTicket_AssertPresent ( TicketType parTicket ); @@ -161,6 +163,15 @@ namespace cloonel { assert(m_tree.end() != ret); return ret; } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + void ObserversManager::CopyObservers (std::unordered_set& parOut) { + for (const auto& itm : m_tree) { + parOut.insert(itm.itm); + } + } } //namespace cloonel #if defined(OBS_MANAGER_LOG) diff --git a/src/physicsfswrapper.cpp b/src/physicsfswrapper.cpp index 21949dc..40facf1 100644 --- a/src/physicsfswrapper.cpp +++ b/src/physicsfswrapper.cpp @@ -58,6 +58,7 @@ namespace cloonel { ///------------------------------------------------------------------------- PhysicsFSWrapper::~PhysicsFSWrapper() noexcept { const bool succeeded = static_cast(PHYSFS_deinit()); + (void)succeeded; assert(succeeded); } diff --git a/src/placeable.cpp b/src/placeable.cpp index a196317..6daa7f5 100644 --- a/src/placeable.cpp +++ b/src/placeable.cpp @@ -34,4 +34,9 @@ namespace cloonel { void Placeable::OnRegister (Mover&, Mover::PlaceableTicketType) { return; } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void Placeable::BeginMovement() { + } } //namespace cloonel diff --git a/src/placeable.hpp b/src/placeable.hpp index 1969160..3a870a2 100644 --- a/src/placeable.hpp +++ b/src/placeable.hpp @@ -27,12 +27,14 @@ namespace cloonel { class Placeable { public: float2 GetPos ( void ) const noexcept; - void AddOffset ( const float2& parOffset ) noexcept; + virtual void AddOffset ( const float2& parOffset ) noexcept; + virtual void SetAbsolutePosition ( const float2& parPos ) noexcept; virtual void OnRegister ( Mover& parMover, Mover::PlaceableTicketType parParentTicket ); + virtual void BeginMovement ( void ); protected: explicit Placeable ( float2 parPos ); - ~Placeable ( void ) noexcept = default; + virtual ~Placeable ( void ) noexcept = default; private: float2 m_pos; @@ -49,6 +51,12 @@ namespace cloonel { inline float2 Placeable::GetPos() const noexcept { return m_pos; } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + inline void Placeable::SetAbsolutePosition (const float2& parPos) noexcept { + m_pos = parPos; + } } //namespace cloonel #endif diff --git a/src/platform.cpp b/src/platform.cpp index c6cc049..78ac61b 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -19,16 +19,18 @@ #include "platform.hpp" #include "texture.hpp" +#include "horzcollisionbar.hpp" #include +#include namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- Platform::Platform (SDLMain* parSdlMain, const float2& parPos, Texture* parTexture, const float2& parSize) : Placeable(parPos), - m_collisionTop(parPos, parSize.x()), m_screenRatio(parSdlMain), m_size(parSize), + m_collisionTop(new HorzCollisionBar(parPos, parSize.x())), m_surface(parTexture) { assert(m_surface); @@ -38,13 +40,18 @@ namespace cloonel { ///-------------------------------------------------------------------------- Platform::Platform (Platform&& parOther) noexcept : Placeable(parOther.GetPos()), - m_collisionTop(parOther.m_collisionTop), m_screenRatio(std::move(parOther.m_screenRatio)), m_size(parOther.m_size), + m_collisionTop(std::move(parOther.m_collisionTop)), m_surface(parOther.m_surface) { } + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + Platform::~Platform() noexcept { + } + ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void Platform::Draw() const { @@ -65,6 +72,6 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- void Platform::OnRegister (Mover& parMover, Mover::PlaceableTicketType parParentTicket) { - parMover.RegisterPlaceable(&m_collisionTop, parParentTicket); + parMover.RegisterPlaceable(m_collisionTop.get(), parParentTicket); } } //namespace cloonel diff --git a/src/platform.hpp b/src/platform.hpp index cf7e0c6..9d7c267 100644 --- a/src/platform.hpp +++ b/src/platform.hpp @@ -23,31 +23,36 @@ #include "sizenotifiable.hpp" #include "drawable.hpp" #include "placeable.hpp" -#include "horzcollisionbar.hpp" +#include "collidertypedef.hpp" +#include namespace cloonel { class Texture; class SDLMain; + class HorzCollisionBar; class Platform : public Drawable, public Placeable { public: Platform ( SDLMain* parSdlMain, const float2& parPos, Texture* parTexture, const float2& parSize ); Platform ( Platform&& parOther ) noexcept; Platform ( const Platform& ) = delete; - virtual ~Platform ( void ) noexcept = default; + virtual ~Platform ( void ) noexcept; Platform& operator= ( const Platform& parOther ); float2 TopLeft ( void ) const { return GetPos(); } float2 BottomRight ( void ) const { return TopLeft() + m_size; } + const HorzCollisionBar* TopCollisionBar ( void ) const { return m_collisionTop.get(); } //Overrides virtual void Draw ( void ) const; virtual void OnRegister ( Mover& parMover, Mover::PlaceableTicketType parParentTicket ); private: - HorzCollisionBar m_collisionTop; SizeNotifiable m_screenRatio; float2 m_size; + ColliderRegisterFunc m_registerToCollider; + ColliderUnregisterFunc m_unregisterFromCollider; + std::unique_ptr m_collisionTop; Texture* m_surface; }; } //namespace cloonel diff --git a/src/platformset.cpp b/src/platformset.cpp new file mode 100644 index 0000000..5c86129 --- /dev/null +++ b/src/platformset.cpp @@ -0,0 +1,118 @@ +/* + 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 "platformset.hpp" +#include "platform.hpp" +#include "CloonelJumpConfig.h" +#include +#include +#include +#include +#include +#include + +namespace cloonel { + namespace { + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + boost::circular_buffer::const_iterator FindFirstVisible (const boost::circular_buffer& parPlatforms) { + auto curr = parPlatforms.begin(); + while (curr != parPlatforms.end() and curr->TopLeft().y() < 0.0f) { + ++curr; + } + return curr; + } + } //unnamed namespace + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + PlatformSet::PlatformSet (SDLMain* parSdl) : + m_platforms(MAX_PLATFORMS_ON_SCREEN), + m_sdlmain(parSdl) + { + assert(m_sdlmain); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + PlatformSet::~PlatformSet() noexcept { + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::Add (const float2& parPos, const float2& parSize, Texture* parTexture) { + m_platforms.push_back(Platform(m_sdlmain, parPos, parTexture, parSize)); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::CopyBars (std::vector& parOut) const { + auto eleCopy = FindFirstVisible(m_platforms); + const size_t count = m_platforms.end() - eleCopy; + parOut.reserve(parOut.size() + count); + while (m_platforms.end() != eleCopy) { + parOut.push_back(eleCopy->TopCollisionBar()); + ++eleCopy; + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::CopyDrawables (std::vector& parOut) const { + auto eleCopy = FindFirstVisible(m_platforms); + const size_t count = m_platforms.end() - eleCopy; + parOut.reserve(parOut.size() + count); + while (m_platforms.end() != eleCopy) { + parOut.push_back(&*eleCopy); + ++eleCopy; + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + size_t PlatformSet::CountFreePlatforms() const { + size_t freePlatforms = 0; + for (const auto& platf : m_platforms) { + if (platf.GetPos().y() < 0.0f) + ++freePlatforms; + else + break; + } + return MAX_PLATFORMS_ON_SCREEN - m_platforms.size() + freePlatforms; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::clear() noexcept { + m_platforms.clear(); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::SendBeginMovement() noexcept { + std::for_each(m_platforms.begin(), m_platforms.end(), std::bind(&Platform::BeginMovement, std::placeholders::_1)); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSet::SendAddOffset (const float2& parOffset) noexcept { + std::for_each(m_platforms.begin(), m_platforms.end(), std::bind(&Platform::AddOffset, std::placeholders::_1, parOffset)); + } +} //namespace cloonel diff --git a/src/platformset.hpp b/src/platformset.hpp new file mode 100644 index 0000000..ca13553 --- /dev/null +++ b/src/platformset.hpp @@ -0,0 +1,62 @@ +/* + 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 idB56C30EE09454EA2864FA6D1607131D5 +#define idB56C30EE09454EA2864FA6D1607131D5 + +#include "collisionbarset.hpp" +#include "drawableset.hpp" +#include "movers/mover.hpp" +#include +#include + +namespace cloonel { + class SDLMain; + class Platform; + class Texture; + + class PlatformSet : public CollisionBarSet, public DrawableSet { + public: + PlatformSet ( SDLMain* parSdl ); + PlatformSet ( const PlatformSet& ) = delete; + ~PlatformSet ( void ) noexcept; + PlatformSet& operator= ( const PlatformSet& ) = delete; + + void Add ( const float2& parPos, const float2& parSize, Texture* parTexture ); + size_t CountFreePlatforms ( void ) const; + void SendBeginMovement ( void ) noexcept; + void SendAddOffset ( const float2& parOffset ) noexcept; + + size_t size ( void ) const { return m_platforms.size(); } + bool empty ( void ) const { return m_platforms.empty(); } + void clear ( void ) noexcept; + const Platform& back ( void ) { return m_platforms.back(); } + + private: + //Overrides + virtual void CopyBars ( std::vector& parOut ) const; + virtual void CopyDrawables ( std::vector& parOut ) const; + + boost::circular_buffer m_platforms; + SDLMain* const m_sdlmain; + }; +} //namespace cloonel + +#endif diff --git a/src/platformsystem.cpp b/src/platformspawner.cpp similarity index 54% rename from src/platformsystem.cpp rename to src/platformspawner.cpp index 7f1c915..f4da94e 100644 --- a/src/platformsystem.cpp +++ b/src/platformspawner.cpp @@ -17,19 +17,21 @@ along with CloonelJump. If not, see . */ -#include "platformsystem.hpp" +#include "platformspawner.hpp" #include "platform.hpp" #include "CloonelJumpConfig.h" #include "texture.hpp" #include "gameplayscene.hpp" #include "mover.hpp" +#include "collider.hpp" +#include "platformset.hpp" #include #include #include #include #include -#include #include +#include namespace cloonel { namespace { @@ -59,52 +61,22 @@ namespace cloonel { } } //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 { + struct PlatformSpawner::LocalData : public boost::noncopyable { LocalData ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance ); ~LocalData ( void ) noexcept = default; - boost::circular_buffer platforms; + PlatformSet platforms; Texture texture; - SDLMain* const sdlmain; + std::list> registeredTo; GameplayScene* const scene; const float maxDistance; }; ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - PlatformSystem::LocalData::LocalData (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance) : - platforms(MAX_PLATFORMS_ON_SCREEN), + PlatformSpawner::LocalData::LocalData (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance) : + platforms(parSDLMain), texture(parTexturePath, parSDLMain, false), - sdlmain(parSDLMain), scene(parScene), maxDistance(parMaxDistance) { @@ -112,85 +84,91 @@ namespace cloonel { ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - PlatformSystem::PlatformSystem (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance) : + PlatformSpawner::PlatformSpawner (const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance) : Placeable(float2(0.0f)), - m_localdata(new LocalData(parTexturePath, parSDLMain, parScene, parMaxDistance)) + m_localdata(new LocalData(parTexturePath, parSDLMain, parScene, parMaxDistance)), + m_targetAverage(parMaxDistance / 5.25f) //TODO: change this value to make up for the difficulty { } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - PlatformSystem::~PlatformSystem() noexcept { + PlatformSpawner::~PlatformSpawner() noexcept { Destroy(); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void PlatformSystem::SpawnPlatforms() { - //const int2 refWH(REFERENCE_WIDTH, REFERENCE_HEIGHT); - //const int2 platfWH(g_platfWidth, g_platfHeight); + void PlatformSpawner::SpawnPlatforms() { + const float2 platfWH(static_cast(g_platfWidth), static_cast(g_platfHeight)); - // 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; + size_t freePlatforms = m_localdata->platforms.CountFreePlatforms(); + float prevPlatf = (m_localdata->platforms.empty() ? 0.0f : m_localdata->platforms.back().GetPos().y() + GetPos().y()); + //FIXME: platform's height shouldn't grow unbounded, they should have the + //screen-relative position only. Change the movers as appropriate. + //std::cout << "Top platform is at index " << m_localdata->platforms.size() - 1 << ", prevPlatf = " << prevPlatf << " "; + //if (not m_localdata->platforms.empty()) { + //std::cout << "top pos is " << m_localdata->platforms.back().platform->GetPos() << ", system's pos is " << GetPos() << "\n"; //} + while (static_cast(REFERENCE_HEIGHT) - prevPlatf >= m_targetAverage) { + assert(freePlatforms > 0); + const auto newPos(PositionForNewPlatf(prevPlatf, m_targetAverage, m_localdata->maxDistance, freePlatforms)); + --freePlatforms; + prevPlatf = newPos.y(); + + m_localdata->platforms.Add(newPos, platfWH, &m_localdata->texture); + } } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void PlatformSystem::Prepare() { + void PlatformSpawner::Prepare() { m_localdata->texture.Reload(); //Spawn the initial platforms m_localdata->platforms.clear(); - const size_t totalPlatf = MAX_PLATFORMS_ON_SCREEN; - //const auto totalPlatfFloatInv = 1.0f / static_cast(totalPlatf); - const float2 platfWH(static_cast(g_platfWidth), static_cast(g_platfHeight)); - float prevPlatf = 0.0f; - const float averageTarget = m_localdata->maxDistance / 5.25f; //TODO: change this value to make up for the difficulty - for (size_t z = 0; z < totalPlatf; ++z) { - const auto newPos(PositionForNewPlatf(prevPlatf, averageTarget, m_localdata->maxDistance, totalPlatf - z)); - prevPlatf = newPos.y(); - - m_localdata->platforms.push_back(Platform(m_localdata->sdlmain, newPos, &m_localdata->texture, platfWH)); - - if (static_cast(REFERENCE_HEIGHT) - newPos.y() < averageTarget) - break; - } + this->SpawnPlatforms(); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void PlatformSystem::Destroy() noexcept { + void PlatformSpawner::Destroy() noexcept { m_localdata->texture.Destroy(); + for (const auto& unregPair : m_localdata->registeredTo) { + unregPair.second->UnregisterBarSet(unregPair.first, &m_localdata->platforms); + } + m_localdata->registeredTo.clear(); m_localdata->platforms.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()); - newPlatf.ticket = Mover::NullTicket; - } + void PlatformSpawner::BeginMovement() { + m_localdata->platforms.SendBeginMovement(); } ///-------------------------------------------------------------------------- ///-------------------------------------------------------------------------- - void PlatformSystem::OnRegister (Mover& parMover, Mover::PlaceableTicketType parTicket) { - for (size_t z = 0; z < m_localdata->platforms.size(); ++z) { - assert(m_localdata->platforms[z].platform != nullptr); - m_localdata->platforms[z].ticket = parMover.RegisterPlaceable(m_localdata->platforms[z].platform.get(), parTicket); - } + void PlatformSpawner::AddOffset (const float2& parOffset) noexcept { + m_localdata->platforms.SendAddOffset(parOffset); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSpawner::SetAbsolutePosition (const float2&) noexcept { + assert(false); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void PlatformSpawner::RegisterForCollision (Collider& parCollider, Collider::GroupIDType parGroupID) { + parCollider.RegisterBarSet(parGroupID, &m_localdata->platforms); + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + const DrawableSet* PlatformSpawner::GetDrawableSet() const { + return &m_localdata->platforms; } } //namespace cloonel diff --git a/src/platformsystem.hpp b/src/platformspawner.hpp similarity index 56% rename from src/platformsystem.hpp rename to src/platformspawner.hpp index 2c2af45..9252094 100644 --- a/src/platformsystem.hpp +++ b/src/platformspawner.hpp @@ -20,33 +20,40 @@ #ifndef id17908979556C47F8A978688BBE4A9D22 #include "placeable.hpp" +#include "collidertypedef.hpp" +#include "collider.hpp" #include namespace cloonel { class SDLMain; class GameplayScene; + class DrawableSet; - class PlatformSystem : public Placeable { + class PlatformSpawner : public Placeable { public: - PlatformSystem ( void ) = delete; - PlatformSystem ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance ); - PlatformSystem ( const PlatformSystem& ) = delete; - PlatformSystem ( PlatformSystem&& parOther ) = delete; - ~PlatformSystem ( void ) noexcept; - PlatformSystem& operator= ( const PlatformSystem& ) = delete; + PlatformSpawner ( void ) = delete; + PlatformSpawner ( const char* parTexturePath, SDLMain* parSDLMain, GameplayScene* parScene, float parMaxDistance ); + PlatformSpawner ( const PlatformSpawner& ) = delete; + PlatformSpawner ( PlatformSpawner&& parOther ) = delete; + virtual ~PlatformSpawner ( void ) noexcept; + PlatformSpawner& operator= ( const PlatformSpawner& ) = delete; void Prepare ( void ); - void AddDrawables ( void ); void Destroy ( void ) noexcept; void SpawnPlatforms ( void ); - - //Overrides - virtual void OnRegister ( Mover& parOut, Mover::PlaceableTicketType parTicket ); + void RegisterForCollision ( Collider& parCollider, Collider::GroupIDType parGroupID ); + const DrawableSet* GetDrawableSet ( void ) const; private: struct LocalData; + //Overrides + virtual void BeginMovement ( void ); + virtual void AddOffset ( const float2& parOffset ) noexcept; + virtual void SetAbsolutePosition ( const float2& ) noexcept; + const std::unique_ptr m_localdata; + float m_targetAverage; }; } //namespace cloonel diff --git a/src/sdlmain.cpp b/src/sdlmain.cpp index 44c0d52..2d0d9df 100644 --- a/src/sdlmain.cpp +++ b/src/sdlmain.cpp @@ -24,14 +24,63 @@ #include #include #include +#include +#include +#include + +#if defined(RASPBERRY_PI) +#include +#endif namespace cloonel { + namespace { + ///---------------------------------------------------------------------- + ///---------------------------------------------------------------------- + std::pair GetRenderingDriver() { + typedef std::pair RetPairType; + + const int count = SDL_GetNumRenderDrivers(); + int opengles = -1; + int opengles2 = -1; + int opengl = -1; + SDL_RendererInfo info; + for (int z = 0; z < count; ++z) { + const int ret = SDL_GetRenderDriverInfo(z, &info); + if (0 == ret) { + if (std::strcmp("opengles", info.name) == 0) + opengles = z; + else if (std::strcmp("opengles2", info.name) == 0) + opengles2 = z; + else if (std::strcmp("opengl", info.name) == 0) + opengl = z; + } + } +#if !defined(FORCE_OPENGLES) + if (opengl > -1) + return RetPairType(opengl, "opengl"); +#endif + if (opengles2 > -1) + return RetPairType(opengles2, "opengles2"); + if (opengles > -1) + return RetPairType(opengles, "opengles"); +#if defined(FORCE_OPENGLES) + if (opengl > -1) + return RetPairType(opengl, "opengl"); +#endif + + return RetPairType(-1, "default"); + } + } //unnamed namespace + struct SDLMain::LocalData { SDL_Window* window; SDL_Renderer* renderer; SizeRatio sizeratio; ObserversManager resChangeNotifList; bool initialized; +#if defined(RASPBERRY_PI) + bool bcmInitialized; +#endif }; ///------------------------------------------------------------------------ @@ -41,12 +90,19 @@ namespace cloonel { m_localData(new LocalData) { m_localData->sizeratio.SetOriginal(static_cast(parReferenceRes), static_cast(parRes)); + m_localData->initialized = false; +#if defined(RASPBERRY_PI) + m_localData->bcmInitialized = false; +#endif } ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ SDLMain::~SDLMain() noexcept { ClearIFN(*m_localData); +#if defined(RASPBERRY_PI) + assert(not m_localData->bcmInitialized); +#endif } ///------------------------------------------------------------------------ @@ -59,6 +115,12 @@ namespace cloonel { ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ void SDLMain::InitSDL (LocalData& parInitSDL) { +#if defined(RASPBERRY_PI) + assert(not parInitSDL.bcmInitialized); + bcm_host_init(); + parInitSDL.bcmInitialized = true; +#endif + parInitSDL.window = nullptr; parInitSDL.renderer = nullptr; parInitSDL.initialized = false; @@ -67,13 +129,19 @@ namespace cloonel { throw std::runtime_error(SDL_GetError()); parInitSDL.initialized = true; +#if defined(FORCE_OPENGLES) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#endif + const float2 wh(m_localData->sizeratio.Resolution()); SDL_Window* const win = SDL_CreateWindow(m_gameName.c_str(), 100, 100, static_cast(wh.x()), static_cast(wh.y()), SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (!win) throw std::runtime_error(SDL_GetError()); parInitSDL.window = win; - SDL_Renderer* const renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + const auto rendererDriver = GetRenderingDriver(); + m_rendererName = rendererDriver.second; + SDL_Renderer* const renderer = SDL_CreateRenderer(win, rendererDriver.first, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (!renderer) throw std::runtime_error(SDL_GetError()); parInitSDL.renderer = renderer; @@ -86,8 +154,16 @@ namespace cloonel { SDL_DestroyRenderer(parInitSDL.renderer); if (parInitSDL.window) SDL_DestroyWindow(parInitSDL.window); - if (parInitSDL.initialized) + if (parInitSDL.initialized) { + parInitSDL.initialized = false; SDL_Quit(); + } +#if defined(RASPBERRY_PI) + if (parInitSDL.bcmInitialized) { + parInitSDL.bcmInitialized = false; + bcm_host_deinit(); + } +#endif } ///------------------------------------------------------------------------ @@ -151,4 +227,10 @@ namespace cloonel { ushort2 SDLMain::WidthHeight() const noexcept { return static_cast(m_localData->sizeratio.Resolution()); } + + ///------------------------------------------------------------------------ + ///------------------------------------------------------------------------ + std::string SDLMain::GetVideoDriverName() const { + return std::string(SDL_GetCurrentVideoDriver()); + } } //namespace cloonel diff --git a/src/sdlmain.hpp b/src/sdlmain.hpp index 74e8ffd..dc05b8c 100644 --- a/src/sdlmain.hpp +++ b/src/sdlmain.hpp @@ -42,6 +42,8 @@ namespace cloonel { size_t RegisterForResChange ( SizeNotifiableBase* parNotif ); void UnregisterForResChange ( size_t parID ) noexcept; void SwapRegisteredForResChange ( size_t parID, SizeNotifiableBase* parNotif ); + const std::string& GetRendererName ( void ) const { return m_rendererName; } + std::string GetVideoDriverName ( void ) const; private: struct LocalData; @@ -50,6 +52,7 @@ namespace cloonel { void ClearIFN ( LocalData& parData ) noexcept; const std::string m_gameName; + std::string m_rendererName; std::unique_ptr m_localData; }; } //namespace cloonel diff --git a/src/tiledwallpaper.hpp b/src/tiledwallpaper.hpp index 4ba4b6d..be2b9e5 100644 --- a/src/tiledwallpaper.hpp +++ b/src/tiledwallpaper.hpp @@ -22,20 +22,25 @@ #include "drawable.hpp" #include "sizenotifiable.hpp" +#include "drawableset.hpp" #include +#include namespace cloonel { class Texture; class SDLMain; - class TiledWallpaper : public Drawable { + class TiledWallpaper : public Drawable, public DrawableSet { public: TiledWallpaper ( const std::string&& parPath, SDLMain* parMain ); virtual ~TiledWallpaper ( void ) noexcept; void Reload ( void ); void Destroy ( void ) noexcept; + + //Overrides virtual void Draw ( void ) const; + virtual void CopyDrawables ( std::vector& parOut ) const { parOut.push_back(this); } private: class TileCountNotifiable : public SizeNotifiable {