Skip to content

Commit

Permalink
Optimize GameObjectIterator by using static_cast
Browse files Browse the repository at this point in the history
`GameObjectIterator` is only initialized in `GameObjectRange`, where we only pass objects of the needed type index, thus we can safely `static_cast` them (granted that `T` inherits `GameObject`, otherwise a `dynamic_cast` would be needed to perform sidecasts).
  • Loading branch information
Vankata453 committed Nov 9, 2024
1 parent c83bcc8 commit bf7d327
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 29 deletions.
30 changes: 18 additions & 12 deletions src/supertux/game_object_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "game_object_manager.hpp"

template<typename T>
class GameObjectIterator
class GameObjectIterator final
{
public:
typedef std::vector<GameObject* >::const_iterator Iterator;
Expand All @@ -37,8 +37,10 @@ class GameObjectIterator
{
// A dynamic_cast is needed to perform sidecasts (a.k.a. crosscasts)
// T may be one of multiple base classes of the object and need not inherit GameObject
m_object = dynamic_cast<T*>(*m_it);
assert(m_object);
if constexpr (std::is_base_of<GameObject, T>::value)
m_object = static_cast<T*>(*m_it);
else
m_object = dynamic_cast<T*>(*m_it);
}
}

Expand All @@ -47,8 +49,10 @@ class GameObjectIterator
++m_it;
if (m_it != m_end)
{
m_object = dynamic_cast<T*>(*m_it);
assert(m_object);
if constexpr (std::is_base_of<GameObject, T>::value)
m_object = static_cast<T*>(*m_it);
else
m_object = dynamic_cast<T*>(*m_it);
}
return *this;
}
Expand All @@ -60,28 +64,30 @@ class GameObjectIterator
return tmp;
}

T* operator->() {
inline T* get() const { return m_object; }

inline T* operator->() {
return m_object;
}

const T* operator->() const {
inline const T* operator->() const {
return m_object;
}

T& operator*() const {
inline T& operator*() const {
return *m_object;
}

T& operator*() {
inline T& operator*() {
return *m_object;
}

bool operator==(const GameObjectIterator& other) const
inline bool operator==(const GameObjectIterator& other) const
{
return m_it == other.m_it;
}

bool operator!=(const GameObjectIterator& other) const
inline bool operator!=(const GameObjectIterator& other) const
{
return !(*this == other);
}
Expand All @@ -93,7 +99,7 @@ class GameObjectIterator
};

template<typename T>
class GameObjectRange
class GameObjectRange final
{
public:
GameObjectRange(const GameObjectManager& manager) :
Expand Down
7 changes: 3 additions & 4 deletions src/supertux/game_object_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,10 @@ GameObjectManager::update_tilemaps()
{
m_solid_tilemaps.clear();
m_all_tilemaps.clear();
for (auto tilemap : get_objects_by_type_index(typeid(TileMap)))
for (auto& tm : get_objects_by_type<TileMap>())
{
TileMap* tm = static_cast<TileMap*>(tilemap);
if (tm->is_solid()) m_solid_tilemaps.push_back(tm);
m_all_tilemaps.push_back(tm);
if (tm.is_solid()) m_solid_tilemaps.push_back(&tm);
m_all_tilemaps.push_back(&tm);
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/supertux/game_object_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,10 @@ class GameObjectManager : public ExposableClass
int get_object_count(std::function<bool(const T&)> predicate = nullptr) const
{
int total = 0;
for (const auto& obj : get_objects_by_type_index(typeid(T))) {
auto object = static_cast<T*>(obj);
if (object && (predicate == nullptr || predicate(*object)))
{
for (auto& obj : get_objects_by_type<T>())
{
if (predicate == nullptr || predicate(obj))
total += 1;
}
}
return total;
}
Expand Down
4 changes: 2 additions & 2 deletions src/supertux/level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,8 @@ Level::get_players() const
{
std::vector<Player*> players;
for (const auto& sector : m_sectors)
for (const auto& player : sector->get_objects_by_type_index(typeid(Player)))
players.push_back(static_cast<Player*>(player));
for (auto& player : sector->get_objects_by_type<Player>())
players.push_back(&player);

return players;
}
Expand Down
12 changes: 6 additions & 6 deletions src/supertux/sector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ Sector::activate(const Vector& player_pos)

// two-player hack: move other players to main player's position
// Maybe specify 2 spawnpoints in the level?
for (auto player_ptr : get_objects_by_type_index(typeid(Player))) {
Player& player = *static_cast<Player*>(player_ptr);
const auto players = get_objects_by_type<Player>();
for (auto& player : players) {
// spawn smalltux below spawnpoint
if (!player.is_big()) {
player.set_pos(player_pos + Vector(0,32));
Expand All @@ -259,9 +259,9 @@ Sector::activate(const Vector& player_pos)
}

//FIXME: This is a really dirty workaround for this strange camera jump
if (get_players().size() > 0)
if (players.begin() != players.end())
{
Player& player = *(get_players()[0]);
Player& player = *players.begin();
Camera& camera = get_camera();
player.set_pos(player.get_pos()+Vector(-32, 0));
camera.reset(player.get_pos());
Expand Down Expand Up @@ -607,8 +607,8 @@ Sector::free_line_of_sight(const Vector& line_start, const Vector& line_end, boo
bool
Sector::can_see_player(const Vector& eye) const
{
for (auto player_ptr : get_objects_by_type_index(typeid(Player))) {
Player& player = *static_cast<Player*>(player_ptr);
for (auto& player : get_objects_by_type<Player>())
{
// test for free line of sight to any of all four corners and the middle of the player's bounding box
if (free_line_of_sight(eye, player.get_bbox().p1(), false, &player)) return true;
if (free_line_of_sight(eye, Vector(player.get_bbox().get_right(), player.get_bbox().get_top()), false, &player)) return true;
Expand Down

0 comments on commit bf7d327

Please sign in to comment.