Register things that need the world size as observers to WorldGrid.
Character and WorldViewport get notified when the world size is set. This way even if world size never changes they still get notified about the proper world size as soon as that information is ready, be it during instantiation or registration. Previously I was having trouble because at the point where Character was instantiated, the world size was not known yet. As such, I had to call a character.update_world_size() function after it became available. The same happened for the viewport, and this looked a bit too brittle from the programmer's perspective. Now you just instantiate the Character and things get sorted out automatically.
This commit is contained in:
parent
0dab671ce4
commit
952a8af9c6
13 changed files with 234 additions and 39 deletions
|
@ -7,9 +7,9 @@ include(TargetArch)
|
|||
include(FindPkgConfig)
|
||||
|
||||
set(common_gcc_flags "-Wall -Wextra -pedantic -Wconversion")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags}")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags} -O0")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${common_gcc_flags}")
|
||||
|
||||
option(CURRY_FORCE_OPENGLES "Try to chose the openGL ES renderer if available. Enable this on Raspberry Pi" OFF)
|
||||
|
@ -67,6 +67,7 @@ add_executable(${PROJECT_NAME}
|
|||
src/movingobject.cpp
|
||||
src/character.cpp
|
||||
src/rect_to_sdl.cpp
|
||||
src/worldsizenotifiable.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 Michele "King_DuckZ" Santullo
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
|
@ -18,15 +18,31 @@
|
|||
*/
|
||||
|
||||
#include "character.hpp"
|
||||
#include <ciso646>
|
||||
|
||||
namespace curry {
|
||||
Character::Character() :
|
||||
m_position(0.0f)
|
||||
namespace {
|
||||
vec2f get_safe_width_height (const Texture& parTex) {
|
||||
return (parTex.texture() ?
|
||||
vector_cast<vec2f>(parTex.width_height())
|
||||
:
|
||||
vec2f(0.0f)
|
||||
);
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
Character::Character (const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) :
|
||||
WorldSizeNotifiable(parDeferredRegister),
|
||||
m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f))
|
||||
{
|
||||
}
|
||||
|
||||
void Character::load (const char* parTexturePath, cloonel::SDLMain& parSDLMain) {
|
||||
const auto old_wh = get_safe_width_height(m_texture);
|
||||
m_texture.load(parTexturePath, parSDLMain);
|
||||
const auto new_wh = vector_cast<vec2f>(m_texture.width_height());
|
||||
if (m_position.get_min() != m_position.get_max())
|
||||
m_position.change_minmax(m_position.get_min(), m_position.get_max() + old_wh - new_wh);
|
||||
}
|
||||
|
||||
void Character::unload() {
|
||||
|
@ -38,11 +54,11 @@ namespace curry {
|
|||
}
|
||||
|
||||
const vec2f& Character::position() const {
|
||||
return m_position;
|
||||
return m_position.get();
|
||||
}
|
||||
|
||||
vec2us Character::width_height() const {
|
||||
return m_texture.width_height();
|
||||
return get_safe_width_height(m_texture);
|
||||
}
|
||||
|
||||
Texture& Character::texture() {
|
||||
|
@ -51,8 +67,8 @@ namespace curry {
|
|||
|
||||
Rect<float> Character::destination_rect (const vec2f& parWorldPos) const {
|
||||
return Rect<float>(
|
||||
m_position - parWorldPos,
|
||||
m_position - parWorldPos + vector_cast<vec2f>(width_height())
|
||||
m_position.get() - parWorldPos,
|
||||
m_position.get() - parWorldPos + vector_cast<vec2f>(width_height())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -62,4 +78,8 @@ namespace curry {
|
|||
vector_cast<vec2f>(width_height())
|
||||
);
|
||||
}
|
||||
|
||||
void Character::world_size_changed (const vec2us&, const vec2i& parPixelSize) {
|
||||
m_position.change_minmax(m_position.get_min(), vector_cast<vec2f>(parPixelSize));
|
||||
}
|
||||
} //namespace curry
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 Michele "King_DuckZ" Santullo
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
|
@ -22,15 +22,18 @@
|
|||
#include "texture.hpp"
|
||||
#include "vector.hpp"
|
||||
#include "rect.hpp"
|
||||
#include "constrained_position.hpp"
|
||||
#include "worldsizenotifiable.hpp"
|
||||
|
||||
namespace cloonel {
|
||||
class SDLMain;
|
||||
} //namespace cloonel
|
||||
|
||||
namespace curry {
|
||||
class Character {
|
||||
class Character : public WorldSizeNotifiable {
|
||||
public:
|
||||
Character();
|
||||
explicit Character (const WorldSizeNotifiable::DeferredRegister& parDeferredRegister);
|
||||
virtual ~Character() noexcept = default;
|
||||
|
||||
void load (const char* parTexturePath, cloonel::SDLMain& parSDLMain);
|
||||
void unload();
|
||||
|
@ -40,9 +43,10 @@ namespace curry {
|
|||
Texture& texture();
|
||||
Rect<float> destination_rect (const vec2f& parWorldPos) const;
|
||||
Rect<float> source_rect() const;
|
||||
virtual void world_size_changed (const vec2us& parSize, const vec2i& parPixelSize);
|
||||
|
||||
private:
|
||||
ConstrainedPosition<vec2f> m_position;
|
||||
Texture m_texture;
|
||||
vec2f m_position;
|
||||
};
|
||||
} //namespace curry
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/algorithm/clamp.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace curry {
|
||||
template <typename T>
|
||||
|
@ -37,20 +38,18 @@ namespace curry {
|
|||
|
||||
template <typename T, typename Constrainer=ScalarConstrainer<T>>
|
||||
class ConstrainedValue {
|
||||
using T_param = typename boost::call_traits<T>::param_type;
|
||||
public:
|
||||
ConstrainedValue (
|
||||
typename boost::call_traits<T>::param_type parMin,
|
||||
typename boost::call_traits<T>::param_type parMax,
|
||||
typename boost::call_traits<T>::param_type parValue
|
||||
);
|
||||
ConstrainedValue (T_param parMin, T_param parMax, T_param parValue);
|
||||
virtual ~ConstrainedValue() noexcept = default;
|
||||
|
||||
void set (typename boost::call_traits<T>::param_type parNew);
|
||||
void set (T_param parNew);
|
||||
typename boost::call_traits<T>::const_reference get() const;
|
||||
void change_minmax (
|
||||
typename boost::call_traits<T>::param_type parMin,
|
||||
typename boost::call_traits<T>::param_type parMax
|
||||
);
|
||||
typename boost::call_traits<T>::const_reference get_min() const;
|
||||
typename boost::call_traits<T>::const_reference get_max() const;
|
||||
void change_minmax (T_param parMin, T_param parMax);
|
||||
|
||||
ConstrainedValue& operator= (T_param parValue);
|
||||
|
||||
private:
|
||||
T m_min;
|
||||
|
@ -60,18 +59,19 @@ namespace curry {
|
|||
|
||||
template <typename T, typename Constrainer>
|
||||
ConstrainedValue<T, Constrainer>::ConstrainedValue (
|
||||
typename boost::call_traits<T>::param_type parMin,
|
||||
typename boost::call_traits<T>::param_type parMax,
|
||||
typename boost::call_traits<T>::param_type parValue
|
||||
T_param parMin,
|
||||
T_param parMax,
|
||||
T_param parValue
|
||||
) :
|
||||
m_min(parMin),
|
||||
m_max(parMax),
|
||||
m_value(parValue)
|
||||
{
|
||||
assert(parMin <= parMax);
|
||||
}
|
||||
|
||||
template <typename T, typename Constrainer>
|
||||
void ConstrainedValue<T, Constrainer>::set (typename boost::call_traits<T>::param_type parNew) {
|
||||
void ConstrainedValue<T, Constrainer>::set (T_param parNew) {
|
||||
m_value = Constrainer()(m_min, m_max, parNew);
|
||||
}
|
||||
|
||||
|
@ -80,13 +80,30 @@ namespace curry {
|
|||
return m_value;
|
||||
}
|
||||
|
||||
template <typename T, typename Constrainer>
|
||||
typename boost::call_traits<T>::const_reference ConstrainedValue<T, Constrainer>::get_min() const {
|
||||
return m_min;
|
||||
}
|
||||
|
||||
template <typename T, typename Constrainer>
|
||||
typename boost::call_traits<T>::const_reference ConstrainedValue<T, Constrainer>::get_max() const {
|
||||
return m_max;
|
||||
}
|
||||
|
||||
template <typename T, typename Constrainer>
|
||||
void ConstrainedValue<T, Constrainer>::change_minmax (
|
||||
typename boost::call_traits<T>::param_type parMin,
|
||||
typename boost::call_traits<T>::param_type parMax
|
||||
T_param parMin,
|
||||
T_param parMax
|
||||
) {
|
||||
assert(parMin <= parMax);
|
||||
m_min = parMin;
|
||||
m_max = parMax;
|
||||
this->set(m_value);
|
||||
}
|
||||
|
||||
template <typename T, typename Constrainer>
|
||||
ConstrainedValue<T, Constrainer>& ConstrainedValue<T, Constrainer>::operator= (T_param parValue) {
|
||||
this->set(parValue);
|
||||
return *this;
|
||||
}
|
||||
} //namespace curry
|
||||
|
|
|
@ -50,8 +50,9 @@ namespace curry {
|
|||
struct IngameScene::LocalData {
|
||||
LocalData (const vec2us& parTileSize, cloonel::SDLMain* parSDLMain) :
|
||||
world(parTileSize),
|
||||
viewport(&world, vec2f(parSDLMain->WidthHeight())),
|
||||
player(parTileSize)
|
||||
viewport(&world, vec2f(parSDLMain->WidthHeight()), WorldSizeNotifiable::DeferredRegister(&world, &viewport)),
|
||||
player(parTileSize),
|
||||
character(WorldSizeNotifiable::DeferredRegister(&world, &character))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,10 @@ namespace curry {
|
|||
return m_texture.get();
|
||||
}
|
||||
|
||||
const SDL_Texture* Texture::texture() const {
|
||||
return m_texture.get();
|
||||
}
|
||||
|
||||
void Texture::load (const char* parPath, cloonel::SDLMain& parSDLMain) {
|
||||
m_texture = load_texture(parPath, parSDLMain, false, RGBA());
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ namespace curry {
|
|||
void load (const char* parPath, cloonel::SDLMain& parSDLMain, RGBA parColorKey);
|
||||
void unload() noexcept;
|
||||
SDL_Texture* texture();
|
||||
const SDL_Texture* texture() const;
|
||||
vec2us width_height() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 Michele "King_DuckZ" Santullo
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "worldgrid.hpp"
|
||||
#include "worldsizenotifiable.hpp"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
@ -59,7 +60,7 @@ namespace curry {
|
|||
new_vec.push_back(tile);
|
||||
}
|
||||
++m_layer_count;
|
||||
m_world_size = parWorldSize;
|
||||
set_world_size(parWorldSize);
|
||||
std::swap(m_layers, new_vec);
|
||||
}
|
||||
|
||||
|
@ -81,7 +82,7 @@ namespace curry {
|
|||
|
||||
m_layer_count = static_cast<uint16_t>(parLayers.size());
|
||||
std::swap(m_layers, new_vec);
|
||||
m_world_size = parWorldSize;
|
||||
set_world_size(parWorldSize);
|
||||
}
|
||||
|
||||
uint16_t WorldGrid::layer_count() const {
|
||||
|
@ -98,6 +99,25 @@ namespace curry {
|
|||
m_layer_count = 0;
|
||||
}
|
||||
|
||||
void WorldGrid::set_world_size (const vec2us& parSize) {
|
||||
if (parSize != m_world_size) {
|
||||
m_world_size = parSize;
|
||||
|
||||
for (auto& observer : m_world_size_watchers) {
|
||||
observer->world_size_changed(m_world_size, world_size_pixel(*this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto WorldGrid::register_observer (WorldSizeNotifiable* parWatcher) -> WorldSizeWatcherTicket {
|
||||
assert(parWatcher);
|
||||
return m_world_size_watchers.Add(parWatcher);
|
||||
}
|
||||
|
||||
void WorldGrid::unregister_observer (WorldSizeWatcherTicket parTicket) {
|
||||
m_world_size_watchers.Remove(parTicket);
|
||||
}
|
||||
|
||||
vec2i world_size_pixel (const WorldGrid& parWorld) {
|
||||
return parWorld.tile_size() * parWorld.world_size();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2016 Michele "King_DuckZ" Santullo
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
|
@ -21,11 +21,16 @@
|
|||
|
||||
#include "vector.hpp"
|
||||
#include "tileindextype.hpp"
|
||||
#include "observersmanager.hpp"
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace curry {
|
||||
class WorldSizeNotifiable;
|
||||
|
||||
class WorldGrid {
|
||||
using WorldSizeWatcherTicket = cloonel::ObserversManager<WorldSizeNotifiable*>::TicketType;
|
||||
|
||||
public:
|
||||
explicit WorldGrid (vec2us parTileSize);
|
||||
|
||||
|
@ -36,10 +41,15 @@ namespace curry {
|
|||
void add_layer (vec2us parWorldSize, const std::vector<TileIndex>& parLayer);
|
||||
void set_layers (vec2us parWorldSize, const std::vector<std::vector<TileIndex>>& parLayers);
|
||||
void unload_layers();
|
||||
WorldSizeWatcherTicket register_observer (WorldSizeNotifiable* parWatcher);
|
||||
void unregister_observer (WorldSizeWatcherTicket parTicket);
|
||||
|
||||
private:
|
||||
void set_world_size (const vec2us& parSize);
|
||||
|
||||
std::size_t tile_count() const;
|
||||
|
||||
cloonel::ObserversManager<WorldSizeNotifiable*> m_world_size_watchers;
|
||||
std::vector<TileIndex> m_layers;
|
||||
vec2us m_tile_size;
|
||||
vec2us m_world_size;
|
||||
|
|
57
src/worldsizenotifiable.cpp
Normal file
57
src/worldsizenotifiable.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
MyCurry 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.
|
||||
|
||||
MyCurry 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 MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "worldsizenotifiable.hpp"
|
||||
#include "worldgrid.hpp"
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
|
||||
namespace curry {
|
||||
WorldSizeNotifiable::WorldSizeNotifiable (const DeferredRegister& parDeferredRegister) :
|
||||
m_ticket(cloonel::ObserversManager<WorldSizeNotifiable*>::Ticket_Null),
|
||||
m_world(parDeferredRegister.world())
|
||||
{
|
||||
assert(m_world);
|
||||
}
|
||||
|
||||
WorldSizeNotifiable::~WorldSizeNotifiable() noexcept {
|
||||
m_world->unregister_observer(m_ticket);
|
||||
}
|
||||
|
||||
WorldSizeNotifiable::DeferredRegister::DeferredRegister (WorldGrid* parWorld, WorldSizeNotifiable* parObj) noexcept :
|
||||
m_notifiable(parObj),
|
||||
m_world(parWorld)
|
||||
{
|
||||
assert(m_notifiable);
|
||||
assert(m_world);
|
||||
}
|
||||
|
||||
WorldSizeNotifiable::DeferredRegister::~DeferredRegister() {
|
||||
assert(m_notifiable);
|
||||
assert(m_world);
|
||||
if (not std::uncaught_exception())
|
||||
m_notifiable->register_to_world(m_world);
|
||||
}
|
||||
|
||||
void WorldSizeNotifiable::register_to_world (WorldGrid* parWorld) {
|
||||
assert(cloonel::ObserversManager<WorldSizeNotifiable*>::Ticket_Null == m_ticket);
|
||||
m_ticket = parWorld->register_observer(this);
|
||||
}
|
||||
} //namespace curry
|
51
src/worldsizenotifiable.hpp
Normal file
51
src/worldsizenotifiable.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
MyCurry 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.
|
||||
|
||||
MyCurry 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 MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "observersmanager.hpp"
|
||||
|
||||
namespace curry {
|
||||
class WorldGrid;
|
||||
|
||||
class WorldSizeNotifiable {
|
||||
public:
|
||||
class DeferredRegister {
|
||||
public:
|
||||
DeferredRegister (WorldGrid* parWorld, WorldSizeNotifiable* parObj) noexcept;
|
||||
~DeferredRegister();
|
||||
WorldGrid* world() const { return m_world; }
|
||||
private:
|
||||
WorldSizeNotifiable* const m_notifiable;
|
||||
WorldGrid* const m_world;
|
||||
};
|
||||
|
||||
virtual void world_size_changed (const vec2us& parSize, const vec2i& parPixelSize) = 0;
|
||||
|
||||
protected:
|
||||
explicit WorldSizeNotifiable (const DeferredRegister& parDeferredRegister);
|
||||
virtual ~WorldSizeNotifiable() noexcept;
|
||||
void register_to_world (WorldGrid* parWorld);
|
||||
|
||||
private:
|
||||
cloonel::ObserversManager<WorldSizeNotifiable*>::TicketType m_ticket;
|
||||
WorldGrid* m_world;
|
||||
};
|
||||
} //namespace curry
|
|
@ -36,8 +36,9 @@ namespace curry {
|
|||
);
|
||||
}
|
||||
} //unnamed namespace
|
||||
WorldViewport::WorldViewport (WorldGrid* parWorld, vec2f parSize) :
|
||||
m_position(vec2f(0.0f), vector_cast<vec2f>(world_size_pixel(*parWorld)) - parSize, vec2f(0.0f)),
|
||||
WorldViewport::WorldViewport (WorldGrid* parWorld, vec2f parSize, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister) :
|
||||
WorldSizeNotifiable(parDeferredRegister),
|
||||
m_position(vec2f(0.0f), vec2f(0.0f), vec2f(0.0f)),
|
||||
m_size(parSize),
|
||||
m_world(parWorld)
|
||||
{
|
||||
|
@ -69,6 +70,10 @@ namespace curry {
|
|||
m_position.set(parPos);
|
||||
}
|
||||
|
||||
void WorldViewport::world_size_changed (const vec2us&, const vec2i& parPixelSize) {
|
||||
m_position.change_minmax(vec2f(0.0f), vector_cast<vec2f>(parPixelSize) - m_size);
|
||||
}
|
||||
|
||||
const TileIndex* WorldViewport::tile (const vec2us& parIndex) const {
|
||||
return world()->tile(parIndex + starting_index(*this));
|
||||
}
|
||||
|
|
|
@ -23,15 +23,18 @@
|
|||
#include "tileindextype.hpp"
|
||||
#include "tileiterator.hpp"
|
||||
#include "constrained_position.hpp"
|
||||
#include "worldsizenotifiable.hpp"
|
||||
|
||||
namespace curry {
|
||||
class WorldGrid;
|
||||
|
||||
class WorldViewport {
|
||||
class WorldViewport : public WorldSizeNotifiable {
|
||||
public:
|
||||
typedef TileIterator iterator;
|
||||
|
||||
WorldViewport (WorldGrid* parWorld, vec2f parSize);
|
||||
WorldViewport (WorldGrid* parWorld, vec2f parSize, const WorldSizeNotifiable::DeferredRegister& parDeferredRegister);
|
||||
virtual ~WorldViewport() noexcept = default;
|
||||
|
||||
const WorldGrid* world() const;
|
||||
const vec2f& position() const;
|
||||
const vec2f& size() const;
|
||||
|
@ -39,6 +42,7 @@ namespace curry {
|
|||
void allow_overscan (bool parAllow);
|
||||
|
||||
void set_position (const vec2f& parPos);
|
||||
virtual void world_size_changed (const vec2us& parSize, const vec2i& parPixelSize) override;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
|
Loading…
Reference in a new issue