将一个向量的内容移动到另一个
Moving the contents of one vector to another
所以我有一个向量:
vector<Enemy*> enemies;
这个矢量包含敌人,这些敌人在整个游戏中动态创建。
if(rand() % 1000 > 998)
{
Enemy * enemy = new Enemy(num_of_enemies);
enemies.push_back(enemy);
}
这个存在的问题是,即使敌人已被删除,矢量也会不断增长,这会减慢我的游戏速度。
本质上,我想将矢量的内容移动到一个新的,但只移动实际容纳敌人的元素。
我读到有一个叫做 std::move
的东西,但我不太确定如何正确实施它,或者它是否能成功移动包含敌人的元素,而不仅仅是整个向量。
任何有关结构化代码实现的帮助都将不胜感激。
The problem with this being is that the vector is ever growing even if the enemy has been deleted ...
Essentially I want to move the contents of the vector to a new one ...
在我看来,更简单的方法是从原始向量中删除指向已删除对象的指针,而不是制作副本。
指向不再存在的已删除对象的指针与指向现有对象的指针之间没有区别。因此,您必须跟踪必须从向量中删除的元素。最简单的解决方案是在删除元素后立即将其删除。使用智能指针,这变得容易得多,因为删除指针也会自动删除对象。
std::move
不会帮你解决这个问题。
您可能要考虑完全不使用手动动态分配。您可以改为将 Enemy
个对象存储在向量中。
When the enemy is to be deleted I call the class destructor, and than [sic] I delete
delete
表达式调用析构函数。自己调用它也会有未定义的行为。
这是处理生成和消失敌人的完整工作流程。请注意,根本不涉及任何指针。
生成敌人:
if (if random_float_between_0_and_1() < 0.002)
enemies.push_back(Enemy{arguments});
消灭敌人;根据您在下面的评论,应该看起来像这样:
auto last_iter = std::remove_if(enemies.begin(), enemies.end(), is_dead);
enemies.erase(last_iter, enemies.end());
这里,is_dead
是一个接受 Enemy const&
并确定它是否与玩家或屏幕边界发生碰撞的函数:
bool is_dead(Enemy const& enemy) {
return outside_screen_area(enemy) or near_player(enemy);
}
函数 outside_screen_area
和 near_player
应该很容易实现。
要了解上述代码的工作原理,请参阅 std::remove
and std::vector::erase
的文档。
另一件事:根据 C++11 附带的标准库随机库实现函数 random_float_between_0_and_1
。不要对整数随机数使用 std::rand
或模运算,它们的效果很差(即它们不是真正均匀分布的,并且会产生偏斜的结果)。
首先,如果你想删除随机位置的单个元素,我建议你不要使用像std::vector这样的数据结构。这个操作的复杂度是线性对删除元素后的元素个数
据我了解,您有许多敌人与一个(或多个)玩家并排在 2D 屏幕上移动。如果敌人被玩家击中或离开屏幕,它将被删除。您只需遍历敌人列表即可看到满足这些条件。
在这种情况下,我建议您使用 std::map 来管理您创建的敌人对象。
假设你的 Enemy class 有一个检查删除条件的函数,例如:
bool Enemy::willbeDeleted() /* if true then will be deleted */
然后这里是 class 使用 std::map 来管理你的敌人对象:
EnemyManager.hpp
#include <map>
class EnemyManager {
public:
/*
* Get the Enemy Manager
*/
static EnemyManager& Instance();
/*!
* Delete the instance of EnemyManager
*/
static void deleteInstance();
public:
/* Create an enemy object */
void createEnemy();
/* Check all enemy objects and delete any fulfulling condition */
void checkEnemy();
virtual ~EnemyManager();
private:
/* Make sure we can not call EnemyManager constructor directly */
EnemyManager();
EnemyManager(const EnemyManager& objManager);
/* Instance of EnemyManager */
static EnemyManager* enemyManager;
private:
/* List of current enemy objects */
std::map<int, A*> enemyList_;
/* Identity of already-create object, it increases on creating a new object */
int enemyIndex_;
};
EnemyManager.cpp
#include "EnemyManager.hpp"
#include <vector>
EnemyManager* EnemyManager::enemyManager = 0;
EnemyManager& EnemyManager::Instance()
{
if (0 == enemyManager)
{
enemyManager = new EnemyManager();
}
return *enemyManager;
}
void EnemyManager::deleteInstance()
{
if (0 != enemyManager) delete enemyManager;
}
EnemyManager::EnemyManager() : enemyList_(), enemyIndex_(0)
{}
EnemyManager::~EnemyManager() {
/* Nothing todo */
}
void EnemyManager::createEnemy()
{
enemyList_[enemyIndex_] = new Enemy();
++enemyIndex_;
}
void EnemyManager::checkEnemy()
{
std::map<int, A*>::const_iterator itb = enemyList_.begin(),
ite = enemyList_.end(), it;
// Vector containing id of enemy object to delete
std::vector<int> enemyToDelete;
for (it = itb; it != ite; ++it)
if ((it->second)->willbeDeleted())
enemyToDelete.push_back(it->first);
// Delete enemies and remove them from map
for (std::size_t idx = 0; idx < enemyToDelete.size(); ++idx)
{
delete enemyList_[enemyToDelete[idx]];
enemyList_.erase(enemyToDelete[idx]);
}
}
您可以按如下方式使用此 class:
在 main.cpp
EnemyManager& enemyManager = EnemyManager::Instance();
if(rand() % 1000 > 998)
{
/* Create new enemy */
enemyManager.createEnemy();
}
/* Check all enemies */
enemyManager.checkEnemy();
有两个重要的功能:createEnemy 控制创建新 Enemy 对象的方式,checkEnemy 验证对象并在需要时删除它们并且 enemyList_ 的大小不会永远增加 :)
我相信通过这种方法,删除敌人不会再减慢您的程序。
这种方法的缺点之一是创建的对象数量可能受限于 2^(8*sizeof(enemyIndex_))
所以我有一个向量:
vector<Enemy*> enemies;
这个矢量包含敌人,这些敌人在整个游戏中动态创建。
if(rand() % 1000 > 998)
{
Enemy * enemy = new Enemy(num_of_enemies);
enemies.push_back(enemy);
}
这个存在的问题是,即使敌人已被删除,矢量也会不断增长,这会减慢我的游戏速度。
本质上,我想将矢量的内容移动到一个新的,但只移动实际容纳敌人的元素。
我读到有一个叫做 std::move
的东西,但我不太确定如何正确实施它,或者它是否能成功移动包含敌人的元素,而不仅仅是整个向量。
任何有关结构化代码实现的帮助都将不胜感激。
The problem with this being is that the vector is ever growing even if the enemy has been deleted ...
Essentially I want to move the contents of the vector to a new one ...
在我看来,更简单的方法是从原始向量中删除指向已删除对象的指针,而不是制作副本。
指向不再存在的已删除对象的指针与指向现有对象的指针之间没有区别。因此,您必须跟踪必须从向量中删除的元素。最简单的解决方案是在删除元素后立即将其删除。使用智能指针,这变得容易得多,因为删除指针也会自动删除对象。
std::move
不会帮你解决这个问题。
您可能要考虑完全不使用手动动态分配。您可以改为将 Enemy
个对象存储在向量中。
When the enemy is to be deleted I call the class destructor, and than [sic] I delete
delete
表达式调用析构函数。自己调用它也会有未定义的行为。
这是处理生成和消失敌人的完整工作流程。请注意,根本不涉及任何指针。
生成敌人:
if (if random_float_between_0_and_1() < 0.002) enemies.push_back(Enemy{arguments});
消灭敌人;根据您在下面的评论,应该看起来像这样:
auto last_iter = std::remove_if(enemies.begin(), enemies.end(), is_dead); enemies.erase(last_iter, enemies.end());
这里,
is_dead
是一个接受Enemy const&
并确定它是否与玩家或屏幕边界发生碰撞的函数:bool is_dead(Enemy const& enemy) { return outside_screen_area(enemy) or near_player(enemy); }
函数
outside_screen_area
和near_player
应该很容易实现。要了解上述代码的工作原理,请参阅
std::remove
andstd::vector::erase
的文档。
另一件事:根据 C++11 附带的标准库随机库实现函数 random_float_between_0_and_1
。不要对整数随机数使用 std::rand
或模运算,它们的效果很差(即它们不是真正均匀分布的,并且会产生偏斜的结果)。
首先,如果你想删除随机位置的单个元素,我建议你不要使用像std::vector这样的数据结构。这个操作的复杂度是线性对删除元素后的元素个数
据我了解,您有许多敌人与一个(或多个)玩家并排在 2D 屏幕上移动。如果敌人被玩家击中或离开屏幕,它将被删除。您只需遍历敌人列表即可看到满足这些条件。
在这种情况下,我建议您使用 std::map 来管理您创建的敌人对象。
假设你的 Enemy class 有一个检查删除条件的函数,例如:
bool Enemy::willbeDeleted() /* if true then will be deleted */
然后这里是 class 使用 std::map 来管理你的敌人对象:
EnemyManager.hpp
#include <map>
class EnemyManager {
public:
/*
* Get the Enemy Manager
*/
static EnemyManager& Instance();
/*!
* Delete the instance of EnemyManager
*/
static void deleteInstance();
public:
/* Create an enemy object */
void createEnemy();
/* Check all enemy objects and delete any fulfulling condition */
void checkEnemy();
virtual ~EnemyManager();
private:
/* Make sure we can not call EnemyManager constructor directly */
EnemyManager();
EnemyManager(const EnemyManager& objManager);
/* Instance of EnemyManager */
static EnemyManager* enemyManager;
private:
/* List of current enemy objects */
std::map<int, A*> enemyList_;
/* Identity of already-create object, it increases on creating a new object */
int enemyIndex_;
};
EnemyManager.cpp
#include "EnemyManager.hpp"
#include <vector>
EnemyManager* EnemyManager::enemyManager = 0;
EnemyManager& EnemyManager::Instance()
{
if (0 == enemyManager)
{
enemyManager = new EnemyManager();
}
return *enemyManager;
}
void EnemyManager::deleteInstance()
{
if (0 != enemyManager) delete enemyManager;
}
EnemyManager::EnemyManager() : enemyList_(), enemyIndex_(0)
{}
EnemyManager::~EnemyManager() {
/* Nothing todo */
}
void EnemyManager::createEnemy()
{
enemyList_[enemyIndex_] = new Enemy();
++enemyIndex_;
}
void EnemyManager::checkEnemy()
{
std::map<int, A*>::const_iterator itb = enemyList_.begin(),
ite = enemyList_.end(), it;
// Vector containing id of enemy object to delete
std::vector<int> enemyToDelete;
for (it = itb; it != ite; ++it)
if ((it->second)->willbeDeleted())
enemyToDelete.push_back(it->first);
// Delete enemies and remove them from map
for (std::size_t idx = 0; idx < enemyToDelete.size(); ++idx)
{
delete enemyList_[enemyToDelete[idx]];
enemyList_.erase(enemyToDelete[idx]);
}
}
您可以按如下方式使用此 class: 在 main.cpp
EnemyManager& enemyManager = EnemyManager::Instance();
if(rand() % 1000 > 998)
{
/* Create new enemy */
enemyManager.createEnemy();
}
/* Check all enemies */
enemyManager.checkEnemy();
有两个重要的功能:createEnemy 控制创建新 Enemy 对象的方式,checkEnemy 验证对象并在需要时删除它们并且 enemyList_ 的大小不会永远增加 :)
我相信通过这种方法,删除敌人不会再减慢您的程序。
这种方法的缺点之一是创建的对象数量可能受限于 2^(8*sizeof(enemyIndex_))