Allow to pick up dropped items.

This commit is contained in:
Felix Ableitner 2013-07-21 10:52:50 +02:00
parent 9401ea53c1
commit 19de12d62a
8 changed files with 79 additions and 15 deletions

View File

@ -173,7 +173,7 @@ Game::keyUp(const sf::Event& event) {
mPlayer->setDirection(Player::Direction::RIGHT, true);
break;
case sf::Keyboard::F:
mPlayer->swapGadgets();
mPlayer->pickUpItem();
break;
default:
break;

View File

@ -41,13 +41,20 @@ World::insertCharacter(std::shared_ptr<Character> character) {
insert(character);
}
void
World::remove(std::shared_ptr<Sprite> drawable) {
Sprite::Category cat = drawable->getCategory();
auto item = std::find(mDrawables[cat].begin(), mDrawables[cat].end(), drawable);
mDrawables[cat].erase(item);
}
/**
* Returns all characters that are within maxDistance from position.
*/
std::vector<std::shared_ptr<Character> >
World::getCharacters(const sf::Vector2f& position, float maxDistance) const {
std::vector<std::shared_ptr<Character> > visible;
for (auto it : mCharacters) {
for (const auto& it : mCharacters) {
if (position == it->getPosition())
continue;
if (thor::squaredLength(position - it->getPosition()) <=
@ -88,7 +95,7 @@ void
World::applyMovement(std::shared_ptr<Sprite> sprite, int elapsed) {
sf::Vector2f offset = sprite->getSpeed() * (elapsed / 1000.0f);
for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) {
for (auto& other : w->second) {
for (const auto& other : w->second) {
if (sprite == other)
continue;
// Ignore anything that is filtered by masks.
@ -135,7 +142,7 @@ World::draw(sf::RenderTarget& target, sf::RenderStates states) const {
screen.left += target.getView().getCenter().x - target.getView().getSize().x / 2;
screen.top += target.getView().getCenter().y - target.getView().getSize().y / 2;
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
for (auto item : v->second) {
for (const auto& item : v->second) {
if (item->isInside(screen))
target.draw(static_cast<sf::Drawable&>(*item), states);
}
@ -184,3 +191,21 @@ World::raycast(const sf::Vector2f& lineStart,
}
return true;
}
/**
* Returns the item closest to position after linear search.
*/
std::shared_ptr<Item>
World::getNearestItem(const sf::Vector2f& position) const {
std::shared_ptr<Item> closest;
float distance = std::numeric_limits<float>::max();
for (const auto& v : mDrawables) {
for (const auto& d : v.second) {
std::shared_ptr<Item> converted = std::dynamic_pointer_cast<Item>(d);
if (converted.get() != nullptr &&
thor::squaredLength(converted->getPosition() - position) < distance)
closest = converted;
}
}
return closest;
}

View File

@ -24,12 +24,14 @@ class World : public sf::Drawable {
public:
void insert(std::shared_ptr<Sprite> drawable);
void insertCharacter(std::shared_ptr<Character> character);
void remove(std::shared_ptr<Sprite> drawable);
void step(int elapsed);
void think(int elapsed);
std::vector<std::shared_ptr<Character> >
getCharacters(const sf::Vector2f& position, float maxDistance) const;
bool raycast(const sf::Vector2f& lineStart,
const sf::Vector2f& lineEnd) const;
std::shared_ptr<Item> getNearestItem(const sf::Vector2f& position) const;
private:

View File

@ -18,6 +18,7 @@
const float Character::VISION_DISTANCE = 500.0f;
const float Character::POINT_REACHED_DISTANCE = 1.0f;
const float Character::ITEM_PICKUP_MAX_DISTANCE_SQUARED = 2500.0f;
/**
* Saves pointer to this instance in static var for think().
@ -259,7 +260,34 @@ Character::getRightGadgetName() const {
return mRightGadget->getName();
}
/**
* Picks up the nearest weapon or gadget, and drops the active weapon (or right gadget).
*
* If no item is nearby, gadgets are swapped instead.
*/
void
Character::swapGadgets() {
Character::pickUpItem() {
std::shared_ptr<Item> item = mWorld.getNearestItem(getPosition());
if (item != nullptr && thor::squaredLength(item->getPosition() - getPosition()) <=
ITEM_PICKUP_MAX_DISTANCE_SQUARED) {
std::shared_ptr<Weapon> weapon = std::dynamic_pointer_cast<Weapon>(item);
if (weapon != nullptr) {
mWorld.insert(mActiveWeapon);
mActiveWeapon->drop(getPosition());
mActiveWeapon = weapon;
mActiveWeapon->setHolder(*this);
}
std::shared_ptr<Gadget> gadget = std::dynamic_pointer_cast<Gadget>(item);
if (gadget != nullptr) {
mWorld.insert(mRightGadget);
mRightGadget->drop(getPosition());
mRightGadget = mLeftGadget;
mLeftGadget = gadget;
}
// TODO: implement (or just make invisible?)
mWorld.remove(item);
}
else {
std::swap(mLeftGadget, mRightGadget);
}
}

View File

@ -63,7 +63,7 @@ protected:
void useRightGadget();
std::string getLeftGadgetName() const;
std::string getRightGadgetName() const;
void swapGadgets();
void pickUpItem();
protected:
@ -76,6 +76,8 @@ private:
/// Distance to a path point where it will be considered as reached (to
/// avoid floating point equality check).
static const float POINT_REACHED_DISTANCE;
/// Maximum distance from character where an item can be picked up.
static const float ITEM_PICKUP_MAX_DISTANCE_SQUARED;
friend class World;
World& mWorld;
Pathfinder& mPathfinder;

View File

@ -16,7 +16,7 @@
Weapon::Weapon(World& world, Character& holder, const Yaml& config) :
Item(sf::Vector2f(80, 30), "weapon.png"),
mWorld(world),
mHolder(holder),
mHolder(&holder),
mName(config.get("name", std::string())),
mProjectile(config.get("bullet", std::string("bullet.yaml"))),
mDamage(config.get("damage", 0)),
@ -142,6 +142,11 @@ Weapon::cancelReload() {
mTimer.restart(sf::milliseconds(mFireInterval));
}
void
Weapon::setHolder(Character& holder) {
mHolder = &holder;
}
/**
* Creates a new projectile and inserts it into the world.
*
@ -149,18 +154,18 @@ Weapon::cancelReload() {
*/
void
Weapon::insertProjectile(float angle) {
sf::Vector2f offset(mHolder.getDirection() * mHolder.getRadius());
sf::Vector2f offset(mHolder->getDirection() * mHolder->getRadius());
float spread = (mHolder.getSpeed() == sf::Vector2f())
float spread = (mHolder->getSpeed() == sf::Vector2f())
? mSpread
: mSpreadMoving;
std::uniform_real_distribution<float> distribution(- spread, spread);
angle += distribution(mGenerator) + 90.0f;
sf::Vector2f direction(thor::rotatedVector(mHolder.getDirection(), angle));
sf::Vector2f direction(thor::rotatedVector(mHolder->getDirection(), angle));
std::shared_ptr<Sprite> projectile(new Bullet(mHolder.getPosition() + offset,
mHolder, direction, mProjectile, mProjectileSpeed,
std::shared_ptr<Sprite> projectile(new Bullet(mHolder->getPosition() + offset,
*mHolder, direction, mProjectile, mProjectileSpeed,
mDamage, mMaxRange));
mWorld.insert(projectile);
}

View File

@ -35,6 +35,7 @@ public:
std::string getName() const;
void reload();
void cancelReload();
void setHolder(Character& holder);
private:
void fire();
@ -42,7 +43,8 @@ private:
private:
World& mWorld;
Character& mHolder;
/// Non-owning pointer instead of reference to allow reassigning.
Character* mHolder;
thor::Timer mTimer;
const std::string mName;

View File

@ -50,7 +50,7 @@ public:
using Character::getHealth;
using Character::getLeftGadgetName;
using Character::getRightGadgetName;
using Character::swapGadgets;
using Character::pickUpItem;
private:
void onThink(int elapsed) override;