Allow to pick up dropped items.
This commit is contained in:
parent
9401ea53c1
commit
19de12d62a
8 changed files with 79 additions and 15 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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() {
|
||||
std::swap(mLeftGadget, mRightGadget);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in a new issue