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);
|
mPlayer->setDirection(Player::Direction::RIGHT, true);
|
||||||
break;
|
break;
|
||||||
case sf::Keyboard::F:
|
case sf::Keyboard::F:
|
||||||
mPlayer->swapGadgets();
|
mPlayer->pickUpItem();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -41,13 +41,20 @@ World::insertCharacter(std::shared_ptr<Character> character) {
|
||||||
insert(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.
|
* Returns all characters that are within maxDistance from position.
|
||||||
*/
|
*/
|
||||||
std::vector<std::shared_ptr<Character> >
|
std::vector<std::shared_ptr<Character> >
|
||||||
World::getCharacters(const sf::Vector2f& position, float maxDistance) const {
|
World::getCharacters(const sf::Vector2f& position, float maxDistance) const {
|
||||||
std::vector<std::shared_ptr<Character> > visible;
|
std::vector<std::shared_ptr<Character> > visible;
|
||||||
for (auto it : mCharacters) {
|
for (const auto& it : mCharacters) {
|
||||||
if (position == it->getPosition())
|
if (position == it->getPosition())
|
||||||
continue;
|
continue;
|
||||||
if (thor::squaredLength(position - it->getPosition()) <=
|
if (thor::squaredLength(position - it->getPosition()) <=
|
||||||
|
@ -88,7 +95,7 @@ void
|
||||||
World::applyMovement(std::shared_ptr<Sprite> sprite, int elapsed) {
|
World::applyMovement(std::shared_ptr<Sprite> sprite, int elapsed) {
|
||||||
sf::Vector2f offset = sprite->getSpeed() * (elapsed / 1000.0f);
|
sf::Vector2f offset = sprite->getSpeed() * (elapsed / 1000.0f);
|
||||||
for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) {
|
for (auto w = mDrawables.begin(); w != mDrawables.end(); w++) {
|
||||||
for (auto& other : w->second) {
|
for (const auto& other : w->second) {
|
||||||
if (sprite == other)
|
if (sprite == other)
|
||||||
continue;
|
continue;
|
||||||
// Ignore anything that is filtered by masks.
|
// 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.left += target.getView().getCenter().x - target.getView().getSize().x / 2;
|
||||||
screen.top += target.getView().getCenter().y - target.getView().getSize().y / 2;
|
screen.top += target.getView().getCenter().y - target.getView().getSize().y / 2;
|
||||||
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
|
for (auto v = mDrawables.begin(); v != mDrawables.end(); v++) {
|
||||||
for (auto item : v->second) {
|
for (const auto& item : v->second) {
|
||||||
if (item->isInside(screen))
|
if (item->isInside(screen))
|
||||||
target.draw(static_cast<sf::Drawable&>(*item), states);
|
target.draw(static_cast<sf::Drawable&>(*item), states);
|
||||||
}
|
}
|
||||||
|
@ -184,3 +191,21 @@ World::raycast(const sf::Vector2f& lineStart,
|
||||||
}
|
}
|
||||||
return true;
|
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:
|
public:
|
||||||
void insert(std::shared_ptr<Sprite> drawable);
|
void insert(std::shared_ptr<Sprite> drawable);
|
||||||
void insertCharacter(std::shared_ptr<Character> character);
|
void insertCharacter(std::shared_ptr<Character> character);
|
||||||
|
void remove(std::shared_ptr<Sprite> drawable);
|
||||||
void step(int elapsed);
|
void step(int elapsed);
|
||||||
void think(int elapsed);
|
void think(int elapsed);
|
||||||
std::vector<std::shared_ptr<Character> >
|
std::vector<std::shared_ptr<Character> >
|
||||||
getCharacters(const sf::Vector2f& position, float maxDistance) const;
|
getCharacters(const sf::Vector2f& position, float maxDistance) const;
|
||||||
bool raycast(const sf::Vector2f& lineStart,
|
bool raycast(const sf::Vector2f& lineStart,
|
||||||
const sf::Vector2f& lineEnd) const;
|
const sf::Vector2f& lineEnd) const;
|
||||||
|
std::shared_ptr<Item> getNearestItem(const sf::Vector2f& position) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
const float Character::VISION_DISTANCE = 500.0f;
|
const float Character::VISION_DISTANCE = 500.0f;
|
||||||
const float Character::POINT_REACHED_DISTANCE = 1.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().
|
* Saves pointer to this instance in static var for think().
|
||||||
|
@ -259,7 +260,34 @@ Character::getRightGadgetName() const {
|
||||||
return mRightGadget->getName();
|
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
|
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);
|
std::swap(mLeftGadget, mRightGadget);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ protected:
|
||||||
void useRightGadget();
|
void useRightGadget();
|
||||||
std::string getLeftGadgetName() const;
|
std::string getLeftGadgetName() const;
|
||||||
std::string getRightGadgetName() const;
|
std::string getRightGadgetName() const;
|
||||||
void swapGadgets();
|
void pickUpItem();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -76,6 +76,8 @@ private:
|
||||||
/// Distance to a path point where it will be considered as reached (to
|
/// Distance to a path point where it will be considered as reached (to
|
||||||
/// avoid floating point equality check).
|
/// avoid floating point equality check).
|
||||||
static const float POINT_REACHED_DISTANCE;
|
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;
|
friend class World;
|
||||||
World& mWorld;
|
World& mWorld;
|
||||||
Pathfinder& mPathfinder;
|
Pathfinder& mPathfinder;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
Weapon::Weapon(World& world, Character& holder, const Yaml& config) :
|
Weapon::Weapon(World& world, Character& holder, const Yaml& config) :
|
||||||
Item(sf::Vector2f(80, 30), "weapon.png"),
|
Item(sf::Vector2f(80, 30), "weapon.png"),
|
||||||
mWorld(world),
|
mWorld(world),
|
||||||
mHolder(holder),
|
mHolder(&holder),
|
||||||
mName(config.get("name", std::string())),
|
mName(config.get("name", std::string())),
|
||||||
mProjectile(config.get("bullet", std::string("bullet.yaml"))),
|
mProjectile(config.get("bullet", std::string("bullet.yaml"))),
|
||||||
mDamage(config.get("damage", 0)),
|
mDamage(config.get("damage", 0)),
|
||||||
|
@ -142,6 +142,11 @@ Weapon::cancelReload() {
|
||||||
mTimer.restart(sf::milliseconds(mFireInterval));
|
mTimer.restart(sf::milliseconds(mFireInterval));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Weapon::setHolder(Character& holder) {
|
||||||
|
mHolder = &holder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new projectile and inserts it into the world.
|
* Creates a new projectile and inserts it into the world.
|
||||||
*
|
*
|
||||||
|
@ -149,18 +154,18 @@ Weapon::cancelReload() {
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Weapon::insertProjectile(float angle) {
|
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
|
? mSpread
|
||||||
: mSpreadMoving;
|
: mSpreadMoving;
|
||||||
std::uniform_real_distribution<float> distribution(- spread, spread);
|
std::uniform_real_distribution<float> distribution(- spread, spread);
|
||||||
angle += distribution(mGenerator) + 90.0f;
|
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,
|
std::shared_ptr<Sprite> projectile(new Bullet(mHolder->getPosition() + offset,
|
||||||
mHolder, direction, mProjectile, mProjectileSpeed,
|
*mHolder, direction, mProjectile, mProjectileSpeed,
|
||||||
mDamage, mMaxRange));
|
mDamage, mMaxRange));
|
||||||
mWorld.insert(projectile);
|
mWorld.insert(projectile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
std::string getName() const;
|
std::string getName() const;
|
||||||
void reload();
|
void reload();
|
||||||
void cancelReload();
|
void cancelReload();
|
||||||
|
void setHolder(Character& holder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fire();
|
void fire();
|
||||||
|
@ -42,7 +43,8 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
World& mWorld;
|
World& mWorld;
|
||||||
Character& mHolder;
|
/// Non-owning pointer instead of reference to allow reassigning.
|
||||||
|
Character* mHolder;
|
||||||
|
|
||||||
thor::Timer mTimer;
|
thor::Timer mTimer;
|
||||||
const std::string mName;
|
const std::string mName;
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
using Character::getHealth;
|
using Character::getHealth;
|
||||||
using Character::getLeftGadgetName;
|
using Character::getLeftGadgetName;
|
||||||
using Character::getRightGadgetName;
|
using Character::getRightGadgetName;
|
||||||
using Character::swapGadgets;
|
using Character::pickUpItem;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onThink(int elapsed) override;
|
void onThink(int elapsed) override;
|
||||||
|
|
Reference in a new issue