Merge branch 'dev'

Conflicts:
	CMakeLists.txt
This commit is contained in:
King_DuckZ 2014-08-14 11:30:05 +02:00
commit dff58a98ef
35 changed files with 969 additions and 154 deletions

View file

@ -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)

View file

@ -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@"

View file

@ -20,9 +20,16 @@
#include "character.hpp"
#include "sdlmain.hpp"
#include "texture.hpp"
#include "collider.hpp"
#include "line.hpp"
#include <cassert>
namespace cloonel {
namespace {
void DoNothing (const Line<float, 2>&, 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<float, 2>& 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

View file

@ -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 <string>
#include <memory>
#include <cstdint>
#include <functional>
#include <vector>
namespace cloonel {
class SDLMain;
class Texture;
template <typename T, uint32_t S> class Line;
class Character : public Placeable, public Drawable {
class Character : public Placeable, public Drawable, public DrawableSet {
public:
typedef std::function<void(const Line<float, 2>&, 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<const Drawable*>& parOut ) const { parOut.push_back(this); }
void OnBounce ( const Line<float, 2>& parCollision, const float2& parDirection );
HorzCollisionBar m_bottomBar;
SizeNotifiable<regbehaviours::AutoRegister> m_screenRatio;
BounceCallbackType m_bounceCallback;
const std::unique_ptr<Texture> m_texture;
};
} //unnamed namespace

View file

@ -18,6 +18,11 @@
*/
#include "collider.hpp"
#include "horzcollisionbar.hpp"
#include "line.hpp"
#include "vector.hpp"
#include "collisionbarset.hpp"
#include "vectormath.hpp"
#include <vector>
#include <ciso646>
#include <cassert>
@ -30,6 +35,106 @@
namespace cloonel {
namespace {
typedef std::vector<const CollisionBar*> CollisionBarListType;
typedef std::vector<std::pair<Collider::GroupIDType, CollisionBarListType>> CollisionBarGroupListType;
typedef std::vector<const CollisionBarSet*> CollisionBarSetListType;
typedef std::vector<std::pair<Collider::GroupIDType, CollisionBarSetListType>> 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>
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<float, 2> 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

View file

@ -22,18 +22,38 @@
#include "observersmanager.hpp"
#include <memory>
#include <vector>
#include <utility>
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<std::pair<GroupIDType, std::vector<const CollisionBar*>>> CollisionBarGroupListType;
typedef std::vector<std::pair<GroupIDType, std::vector<const CollisionBarSet*>>> CollisionBarSetsListType;
typedef std::vector<std::pair<GroupIDType, GroupIDType>> RelationshipListType;
RelationshipListType m_relationships;
CollisionBarGroupListType m_collisionBars;
CollisionBarSetsListType m_collisionBarSets;
};
} //namespace cloonel

32
src/collidertypedef.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef id3DF7C722C6AE4978874605F38F26E350
#define id3DF7C722C6AE4978874605F38F26E350
#include <functional>
namespace cloonel {
class HorzCollisionBar;
typedef std::function<void(HorzCollisionBar*)> ColliderRegisterFunc;
typedef std::function<void(HorzCollisionBar*)> ColliderUnregisterFunc;
} //namespace cloonel
#endif

35
src/collisionbarset.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef id0632E9698575456ABDB19F9BB0AFE492
#define id0632E9698575456ABDB19F9BB0AFE492
#include <vector>
namespace cloonel {
class HorzCollisionBar;
class CollisionBarSet {
public:
virtual void CopyBars ( std::vector<const HorzCollisionBar*>& parOut ) const = 0;
};
} //namespace cloonel
#endif

35
src/drawableset.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef idBFBF4D5B34DD49E68B89249AA1D8FCE4
#define idBFBF4D5B34DD49E68B89249AA1D8FCE4
#include <vector>
namespace cloonel {
class Drawable;
class DrawableSet {
public:
virtual void CopyDrawables ( std::vector<const Drawable*>& parOut ) const = 0;
};
} //namespace cloonel
#endif

View file

@ -20,6 +20,9 @@
#include "gameplayscene.hpp"
#include "mover.hpp"
#include "drawable.hpp"
#include "drawableset.hpp"
#include "placeable.hpp"
#include <unordered_set>
namespace cloonel {
///--------------------------------------------------------------------------
@ -32,23 +35,39 @@ namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplayScene::OnUpdate (float parDelta) {
for (auto itMover : m_movers) {
itMover->Update(parDelta);
{
std::unordered_set<Placeable*> notify;
for (auto mover : m_movers) {
mover->CopyPlaceables(notify);
}
m_collider.RunCollisionTests();
for (auto placeable : notify) {
assert(placeable);
placeable->BeginMovement();
}
}
for (auto mover : m_movers) {
mover->Update(parDelta);
}
m_collider.RunCollisionTests(parDelta);
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplayScene::OnRender() {
for (auto itDrawable : m_drawables) {
itDrawable->Draw();
std::vector<const Drawable*> drawables;
for (auto drawableSet : m_drawableSets) {
drawables.clear();
drawableSet->CopyDrawables(drawables);
for (auto drawable : drawables) {
drawable->Draw();
}
}
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void GameplayScene::Destroy() noexcept {
m_collider.Reset();
}
///--------------------------------------------------------------------------

View file

@ -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<Mover*> m_movers;
std::vector<const Drawable*> m_drawables;
std::vector<const DrawableSet*> m_drawableSets;
};
} //namespace cloonel

View file

@ -27,11 +27,12 @@
#include "moverworld.hpp"
#include "tiledwallpaper.hpp"
#include "texture.hpp"
#include "platformsystem.hpp"
#include "platformspawner.hpp"
#include "CloonelJumpConfig.h"
#include <algorithm>
#include <SDL2/SDL_scancode.h>
#include <ciso646>
#include <functional>
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<float, 2>&, const float2&) {
parMover->ResetToBounce();
}
} //unnamed namespace
///--------------------------------------------------------------------------
@ -62,13 +73,15 @@ namespace cloonel {
///--------------------------------------------------------------------------
void GameplaySceneClassic::OnPrepare() {
const float halfRefHeight = static_cast<float>(REFERENCE_HEIGHT) / 2.0f;
Collider& collider = *this->GetCollider();
const float2 charaRefSize(static_cast<float>(REFERENCE_CHARA_WIDTH), static_cast<float>(REFERENCE_CHARA_HEIGHT));
std::unique_ptr<MoverSine> moverSine(new MoverSine());
std::unique_ptr<Character> player(new Character("resources/graphics/player.png", SDLObject(), float2(80.0f, 120.0f)));
std::unique_ptr<Character> player(new Character("resources/graphics/player.png", SDLObject(), charaRefSize));
std::unique_ptr<MoverLeftRight> moverLeftRight(new MoverLeftRight(1.5f, 5.0f, 40.0f));
std::unique_ptr<MoverWorld> moverWorld(new MoverWorld(halfRefHeight));
std::unique_ptr<TiledWallpaper> wallpaper(new TiledWallpaper("resources/graphics/background_tile.png", SDLObject()));
std::unique_ptr<PlatformSystem> platforms(new PlatformSystem("resources/graphics/platform.png", SDLObject(), this, halfRefHeight * 0.9f));
std::unique_ptr<PlatformSpawner> 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<PlatformSystem>(nullptr));
m_platforms = std::move(std::unique_ptr<PlatformSpawner>(nullptr));
m_wallpaper = std::move(std::unique_ptr<TiledWallpaper>(nullptr));
m_moverWorld = std::move(std::unique_ptr<MoverWorld>(nullptr));
m_moverLeftRight = std::move(std::unique_ptr<MoverLeftRight>(nullptr));
m_player = std::move(std::unique_ptr<Character>(nullptr));
m_moverSine = std::move(std::unique_ptr<MoverSine>(nullptr));
}
///--------------------------------------------------------------------------

View file

@ -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<MoverLeftRight> m_moverLeftRight;
std::unique_ptr<MoverWorld> m_moverWorld;
std::unique_ptr<TiledWallpaper> m_wallpaper;
std::unique_ptr<PlatformSystem> m_platforms;
std::unique_ptr<PlatformSpawner> m_platforms;
};
} //namespace cloonel

View file

@ -26,10 +26,10 @@
namespace cloonel {
namespace {
typedef Line<float, 2> 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<bool, Line2D> 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<void()> 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<float, 2>& 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;

View file

@ -29,22 +29,34 @@ namespace cloonel {
class HorzCollisionBar;
class HorzCollisionBar : public Placeable {
friend bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, Line<float, 2>& parOut );
public:
typedef Line<float, 2> Line2D;
typedef std::function<void(const Line2D&, const float2&)> 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<void()> 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<float, 2> m_segment;
std::function<void()> 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<float, 2>& parOut ) __attribute__((pure));
bool Collide ( float parDeltaT, const HorzCollisionBar& parA, const HorzCollisionBar& parB, HorzCollisionBar::Line2D& parOut ) __attribute__((pure));
} //namespace cloonel
#endif

View file

@ -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(); }

View file

@ -7,6 +7,14 @@ namespace cloonel {
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T, uint32_t S>
Line<T, S>::Line (Scalar parValue) :
m_points(Point(parValue))
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T, uint32_t S>
@ -14,13 +22,13 @@ namespace cloonel {
m_points(parStart, parEnd)
{
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T, uint32_t S>
Line<T, S>& Line<T, S>::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 <typename T, uint32_t S>
Line<T, S>& Line<T, S>::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 <typename T, uint32_t S>
std::ostream& operator<< ( std::ostream& parStream, const Line<T, S>& parLine ) {
for (uint32_t z = 0; z < S - 1; ++z) {
parStream << parLine[z] << "-";
}
parStream << parLine[S - 1];
return parStream;
}
#endif
} //namespace cloonel

View file

@ -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);

View file

@ -45,4 +45,10 @@ namespace cloonel {
parPlaceable->OnRegister(*this, currTicket);
return currTicket;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Mover::CopyPlaceables (std::unordered_set<Placeable*>& parOut) {
m_placeables.CopyObservers(parOut);
}
} //namespace cloonel

View file

@ -22,6 +22,7 @@
#include "vector.hpp"
#include "observersmanager.hpp"
#include <unordered_set>
namespace cloonel {
class Placeable;
@ -40,6 +41,7 @@ namespace cloonel {
virtual void Update ( float parDelta );
PlaceableTicketType RegisterPlaceable ( Placeable* parPlaceable, PlaceableTicketType parParent=ObserversManager<Placeable*>::Ticket_Null );
void UnregisterPlaceable ( PlaceableTicketType parID ) noexcept { m_placeables.Remove(parID); }
void CopyPlaceables ( std::unordered_set<Placeable*>& parOut );
protected:
std::size_t PlaceableCount ( void ) const { return m_placeables.size(); }

View file

@ -47,4 +47,10 @@ namespace cloonel {
while (m_alpha >= pitwo)
m_alpha -= pitwo;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void MoverSine::ResetToBounce() {
m_alpha = 0.0f;
}
} //namespace cloonel

View file

@ -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 );

View file

@ -27,6 +27,7 @@
#include <ciso646>
#include <tree.hh>
#include <boost/iterator/transform_iterator.hpp>
#include <unordered_set>
#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<T>& parOut );
private:
TreeIteratorType GetByTicket_AssertPresent ( TicketType parTicket );
@ -161,6 +163,15 @@ namespace cloonel {
assert(m_tree.end() != ret);
return ret;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
void ObserversManager<T>::CopyObservers (std::unordered_set<T>& parOut) {
for (const auto& itm : m_tree) {
parOut.insert(itm.itm);
}
}
} //namespace cloonel
#if defined(OBS_MANAGER_LOG)

View file

@ -58,6 +58,7 @@ namespace cloonel {
///-------------------------------------------------------------------------
PhysicsFSWrapper::~PhysicsFSWrapper() noexcept {
const bool succeeded = static_cast<bool>(PHYSFS_deinit());
(void)succeeded;
assert(succeeded);
}

View file

@ -34,4 +34,9 @@ namespace cloonel {
void Placeable::OnRegister (Mover&, Mover::PlaceableTicketType) {
return;
}
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Placeable::BeginMovement() {
}
} //namespace cloonel

View file

@ -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

View file

@ -19,16 +19,18 @@
#include "platform.hpp"
#include "texture.hpp"
#include "horzcollisionbar.hpp"
#include <cassert>
#include <algorithm>
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

View file

@ -23,31 +23,36 @@
#include "sizenotifiable.hpp"
#include "drawable.hpp"
#include "placeable.hpp"
#include "horzcollisionbar.hpp"
#include "collidertypedef.hpp"
#include <memory>
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<regbehaviours::AutoRegister> m_screenRatio;
float2 m_size;
ColliderRegisterFunc m_registerToCollider;
ColliderUnregisterFunc m_unregisterFromCollider;
std::unique_ptr<HorzCollisionBar> m_collisionTop;
Texture* m_surface;
};
} //namespace cloonel

118
src/platformset.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "platformset.hpp"
#include "platform.hpp"
#include "CloonelJumpConfig.h"
#include <ciso646>
#include <algorithm>
#include <cassert>
#include <memory>
#include <functional>
#include <algorithm>
namespace cloonel {
namespace {
///----------------------------------------------------------------------
///----------------------------------------------------------------------
boost::circular_buffer<Platform>::const_iterator FindFirstVisible (const boost::circular_buffer<Platform>& 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<const HorzCollisionBar*>& 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<const Drawable*>& 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

62
src/platformset.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef idB56C30EE09454EA2864FA6D1607131D5
#define idB56C30EE09454EA2864FA6D1607131D5
#include "collisionbarset.hpp"
#include "drawableset.hpp"
#include "movers/mover.hpp"
#include <list>
#include <boost/circular_buffer.hpp>
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<const HorzCollisionBar*>& parOut ) const;
virtual void CopyDrawables ( std::vector<const Drawable*>& parOut ) const;
boost::circular_buffer<Platform> m_platforms;
SDLMain* const m_sdlmain;
};
} //namespace cloonel
#endif

View file

@ -17,19 +17,21 @@
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#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 <ciso646>
#include <cstdlib>
#include <cassert>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/algorithm/clamp.hpp>
#include <list>
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> 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<PlatformInfo> platforms;
PlatformSet platforms;
Texture texture;
SDLMain* const sdlmain;
std::list<std::pair<Collider::GroupIDType, Collider*>> 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<float>(g_platfWidth), static_cast<float>(g_platfHeight));
// if (m_localdata.platforms.back().platform->TopLeft().y() <= 0.0f) {
// const float2 newPos(static_cast<float>(std::rand() % (refWH.x() - platfWH.x())), static_cast<float>(std::rand() % (refWH.y() - platfWH.y())));
//if (m_localdata->platforms.empty()) {
// const float2 newPos(static_cast<float>(std::rand() % (refWH.x() - platfWH.x())), static_cast<float>(std::rand() % (refWH.y() - platfWH.y())));
// m_localdata->platforms.push_back(Platform(m_localdata->sdlmain, newPos, &m_localdata->texture, static_cast<float2>(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<float>(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<float>(totalPlatf);
const float2 platfWH(static_cast<float>(g_platfWidth), static_cast<float>(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<float>(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

View file

@ -20,33 +20,40 @@
#ifndef id17908979556C47F8A978688BBE4A9D22
#include "placeable.hpp"
#include "collidertypedef.hpp"
#include "collider.hpp"
#include <memory>
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<LocalData> m_localdata;
float m_targetAverage;
};
} //namespace cloonel

View file

@ -24,14 +24,63 @@
#include <SDL2/SDL.h>
#include <stdexcept>
#include <sstream>
#include <ciso646>
#include <cstring>
#include <utility>
#if defined(RASPBERRY_PI)
#include <bcm_host.h>
#endif
namespace cloonel {
namespace {
///----------------------------------------------------------------------
///----------------------------------------------------------------------
std::pair<int, std::string> GetRenderingDriver() {
typedef std::pair<int, std::string> 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<SizeNotifiableBase*> 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<float2>(parReferenceRes), static_cast<float2>(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<int>(wh.x()), static_cast<int>(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,9 +154,17 @@ 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<ushort2>(m_localData->sizeratio.Resolution());
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
std::string SDLMain::GetVideoDriverName() const {
return std::string(SDL_GetCurrentVideoDriver());
}
} //namespace cloonel

View file

@ -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<LocalData> m_localData;
};
} //namespace cloonel

View file

@ -22,20 +22,25 @@
#include "drawable.hpp"
#include "sizenotifiable.hpp"
#include "drawableset.hpp"
#include <memory>
#include <vector>
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<const Drawable*>& parOut ) const { parOut.push_back(this); }
private:
class TileCountNotifiable : public SizeNotifiable<regbehaviours::AutoRegister> {