diff --git a/source/Game.cpp b/source/Game.cpp index 8ba2da1..d925ed3 100644 --- a/source/Game.cpp +++ b/source/Game.cpp @@ -86,7 +86,6 @@ Game::loop() { } Character::think(elapsed); - mWorld.checkDelete(); mWorld.step(elapsed); diff --git a/source/World.cpp b/source/World.cpp index 3c0f61c..a94ab61 100755 --- a/source/World.cpp +++ b/source/World.cpp @@ -18,11 +18,12 @@ */ void World::insert(std::shared_ptr drawable) { +#ifndef NDEBUG Sprite::Category cat = drawable->getCategory(); auto item = std::find(mDrawables[cat].begin(), mDrawables[cat].end(), drawable); - if (item == mDrawables[cat].end()) { - mDrawables[cat].push_back(drawable); - } + assert(item == mDrawables[cat].end()); +#endif + mDrawables[drawable->getCategory()].push_back(drawable); } /** @@ -38,29 +39,46 @@ World::remove(std::shared_ptr drawable) { } } +/** + * Checks for collisions and applies movement, also removes sprites if + * Sprite::getDelete returns true. + * + * This method can be improved by only testing each pair of sprites once, + * and using the result for both. Applying movement should be done in + * testCollision, always applying the part that causes no collision. + */ void World::step(int elapsed) { for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) { - for (auto spriteA : v->second) { - sf::Vector2f speed = spriteA->getSpeed(); - speed *= elapsed / 1000.0f; - bool overlap = false; - for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) { - for (auto spriteB : w->second) { - if (spriteA == spriteB) { - continue; - } - if (!spriteA->collisionEnabled(spriteB->getCategory()) || !spriteB->collisionEnabled(spriteA->getCategory())) { - continue; - } - if (testCollision(spriteA, spriteB, elapsed)) { - spriteA->onCollide(spriteB); - overlap = true; + for (auto it = v->second.begin(); it != v->second.end(); ) { + auto spriteA = *it; + if (spriteA->getDelete()) { + remove(spriteA); + } + else { + sf::Vector2f speed = spriteA->getSpeed(); + speed *= elapsed / 1000.0f; + bool overlap = false; + for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) { + for (auto spriteB : w->second) { + if (spriteA == spriteB) { + continue; + } + // Ignore anything that is filtered by masks. + if (!spriteA->collisionEnabled(spriteB->getCategory()) || + !spriteB->collisionEnabled(spriteA->getCategory())) { + continue; + } + if (testCollision(spriteA, spriteB, elapsed)) { + spriteA->onCollide(spriteB); + overlap = true; + } } } - } - if (!overlap) { - spriteA->setPosition(spriteA->getPosition() + speed); + if (!overlap) { + spriteA->setPosition(spriteA->getPosition() + speed); + } + it++; } } } @@ -132,23 +150,6 @@ World::testCollision(std::shared_ptr spriteA, return false; } -/** - * Deletes any sprites which return true for getDelete(). - */ -void -World::checkDelete() { - for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) { - for (auto item = v->second.begin(); item != v->second.end(); ) { - if ((*item)->getDelete()) { - item = v->second.erase(item); - } - else { - item++; - } - } - } -} - /** * Draws all elements in the group. */ diff --git a/source/World.h b/source/World.h index 91bac8d..a8e2a8f 100755 --- a/source/World.h +++ b/source/World.h @@ -30,9 +30,8 @@ public: void insert(std::shared_ptr drawable); void remove(std::shared_ptr drawable); void step(int elapsed); - void checkDelete(); -// Private functions. +// Private types. private: class Interval { public: @@ -43,6 +42,8 @@ private: float getLength(); }; +// Private functions. +private: void draw(sf::RenderTarget& target, sf::RenderStates states) const; bool testCollision(std::shared_ptr spriteA, std::shared_ptr spriteB, int elapsed) const;