Added random weapons for enemies, also added setFirst/SecondWeapon to Character.

This commit is contained in:
Felix Ableitner 2013-08-29 21:39:18 +02:00
parent b45dd01c72
commit 7bb08ed447
14 changed files with 124 additions and 31 deletions

View file

@ -5,6 +5,4 @@ health: 100
speed: 100 speed: 100
radius: 25 radius: 25
size: [50, 50] size: [50, 50]
first_weapon: pistol.yaml
second_weapon: knife.yaml
faction: 1 faction: 1

View file

@ -5,6 +5,4 @@ health: 100
speed: 100 speed: 100
radius: 25 radius: 25
size: [50, 50] size: [50, 50]
first_weapon: pistol.yaml
second_weapon: knife.yaml
faction: 0 faction: 0

View file

@ -55,8 +55,8 @@ Game::Game(tgui::Window& window) :
} }
void Game::initPlayer() { void Game::initPlayer() {
mPlayer = std::shared_ptr < Player mPlayer = std::shared_ptr<Player>(new Player(mWorld, mPathfinder,
> (new Player(mWorld, mPathfinder, mGenerator.getPlayerSpawn())); mGenerator.getPlayerSpawn()));
mPlayer->setLeftGadget(std::shared_ptr < Gadget > (new Heal())); mPlayer->setLeftGadget(std::shared_ptr < Gadget > (new Heal()));
mPlayer->setRightGadget(std::shared_ptr < Gadget > (new Shield())); mPlayer->setRightGadget(std::shared_ptr < Gadget > (new Shield()));
mWorld.insertCharacter(mPlayer); mWorld.insertCharacter(mPlayer);

View file

@ -65,10 +65,11 @@ Generator::generateCurrentAreaIfNeeded(const Vector2f& playerPosition) {
Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2, Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE) / 2,
Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE)); Vector2i(GENERATE_AREA_SIZE, GENERATE_AREA_SIZE));
generateTiles(area); generateTiles(area);
for (const auto& enemyPosition : getEnemySpawns(area)) { for (const auto& enemy : getEnemySpawns(area)) {
float distance = thor::length(enemyPosition - playerPosition); float distance = thor::length(enemy.first - playerPosition);
if (distance > Character::VISION_DISTANCE) if (distance > Character::VISION_DISTANCE)
mWorld.insertCharacter(std::shared_ptr<Enemy>(new Enemy(mWorld, mPathfinder, enemyPosition))); mWorld.insertCharacter(std::shared_ptr<Enemy>(new Enemy(
mWorld, mPathfinder, enemy.first, enemy.second)));
} }
} }
if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) { if (mGenerated[current.x][current.y] && distance <= GENERATE_AREA_RANGE) {
@ -258,23 +259,25 @@ Generator::generateTiles(const sf::IntRect& area) {
* Returns coordinates where enemies should spawn. * Returns coordinates where enemies should spawn.
* *
* @param area Area for which enemy spawns should be returned. * @param area Area for which enemy spawns should be returned.
* @return Pairs of spawn points together with seeds.
*/ */
std::vector<Vector2f> std::vector<std::pair<Vector2f, float> >
Generator::getEnemySpawns(const sf::IntRect& area) { Generator::getEnemySpawns(const sf::IntRect& area) {
auto compare = [](const Vector2f& a, const Vector2f& b) { std::vector<std::pair<Vector2f, float> > spawns;
return a.x < b.x || (a.x == b.x && a.y < b.y);
};
std::set<Vector2f, decltype(compare)> ret(compare);
for (int x = area.left; x < area.left + area.width; x++) { for (int x = area.left; x < area.left + area.width; x++) {
for (int y = area.top; y < area.top + area.height; y++) { for (int y = area.top; y < area.top + area.height; y++) {
if (mCharacterNoise.getNoise(x, y) < -0.85f) { float noise = mCharacterNoise.getNoise(x, y);
if (noise <= -0.85f) {
Vector2i tilePosition = findClosestFloor(Vector2i(x, y)); Vector2i tilePosition = findClosestFloor(Vector2i(x, y));
ret.insert(Vector2f(tilePosition.x * Tile::TILE_SIZE.x, // Bad way to get a pseudo random, but deterministic value.
tilePosition.y * Tile::TILE_SIZE.y)); // Just using noise would be better, but that is not uniformly distributed.
int seed = ((int) noise * 100000) xor x xor y;
spawns.push_back(std::make_pair(Vector2f(tilePosition.x * Tile::TILE_SIZE.x,
tilePosition.y * Tile::TILE_SIZE.y), seed));
} }
} }
} }
return std::vector<Vector2f>(ret.begin(), ret.end()); return spawns;
} }
/** /**

View file

@ -25,7 +25,7 @@ public:
explicit Generator(World& world, Pathfinder& pathfinder); explicit Generator(World& world, Pathfinder& pathfinder);
void generateCurrentAreaIfNeeded(const Vector2f& position); void generateCurrentAreaIfNeeded(const Vector2f& position);
Vector2f getPlayerSpawn() const; Vector2f getPlayerSpawn() const;
std::vector<Vector2f> getEnemySpawns(const sf::IntRect& area); std::vector<std::pair<Vector2f, float> > getEnemySpawns(const sf::IntRect& area);
private: private:
typedef std::map<int, std::map<int, Tile::Type> > array; typedef std::map<int, std::map<int, Tile::Type> > array;

View file

@ -9,12 +9,43 @@
#include <Thor/Vectors.hpp> #include <Thor/Vectors.hpp>
#include "items/Heal.h"
#include "items/Shield.h"
#include "items/Weapon.h"
#include "../util/Yaml.h" #include "../util/Yaml.h"
/**
* Determines items used by this enemy using seed.
*
* @param seed Random value to seed random number generator.
*/
Enemy::Enemy(World& world, Pathfinder& pathfinder, Enemy::Enemy(World& world, Pathfinder& pathfinder,
const Vector2f& position) : const Vector2f& position, float seed) :
Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("enemy.yaml"), world, Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("enemy.yaml"), world,
pathfinder) { pathfinder) {
std::ranlux24_base generator(seed);
// Select primary weapon.
switch (std::uniform_int_distribution<int>(0, 4)(generator)) {
case 0: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::ASSAULT_RIFLE)); break;
case 1: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::AUTO_SHOTGUN)); break;
case 2: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::HMG)); break;
case 3: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::RIFLE)); break;
case 4: setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::SHOTGUN)); break;
}
// Select secondary weapon.
switch (std::uniform_int_distribution<int>(0, 1)(generator)) {
case 0: setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::PISTOL));
case 1: setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::KNIFE));
}
// Select gadget.
switch (std::uniform_int_distribution<int>(0, 1)(generator)) {
case 0: setLeftGadget(std::shared_ptr<Gadget>(new Heal()));
case 1: setLeftGadget(std::shared_ptr<Gadget>(new Shield()));
}
} }
void void

View file

@ -8,14 +8,14 @@
#ifndef DG_ENEMY_H_ #ifndef DG_ENEMY_H_
#define DG_ENEMY_H #define DG_ENEMY_H
#include "../sprites/abstract/Character.h" #include "abstract/Character.h"
class World; class World;
class Enemy : public Character { class Enemy : public Character {
public: public:
explicit Enemy(World& world, Pathfinder& pathfinder, explicit Enemy(World& world, Pathfinder& pathfinder,
const Vector2f& position); const Vector2f& position, float seed);
private: private:
virtual void onThink(int elapsed) override; virtual void onThink(int elapsed) override;

View file

@ -9,6 +9,7 @@
#include <Thor/Vectors.hpp> #include <Thor/Vectors.hpp>
#include "items/Weapon.h"
#include "../util/Yaml.h" #include "../util/Yaml.h"
/** /**
@ -19,6 +20,8 @@ Player::Player(World& world, Pathfinder& pathfinder,
Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("player.yaml"), world, Character(position, CATEGORY_ACTOR, MASK_ALL, Yaml("player.yaml"), world,
pathfinder), pathfinder),
mDirection(0) { mDirection(0) {
setFirstWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::PISTOL));
setSecondWeapon(Weapon::getWeapon(world, *this, Weapon::WeaponType::KNIFE));
} }
Vector2f Vector2f

View file

@ -32,10 +32,6 @@ Character::Character(const Vector2f& position, Category category,
mMaxHealth(config.get("health", 100)), mMaxHealth(config.get("health", 100)),
mCurrentHealth(mMaxHealth), mCurrentHealth(mMaxHealth),
mMovementSpeed(config.get("speed", 0.0f)), mMovementSpeed(config.get("speed", 0.0f)),
mFirstWeapon(new Weapon(world, *this,
Yaml(config.get("first_weapon", std::string())))),
mSecondWeapon(new Weapon(world, *this,
Yaml(config.get("second_weapon", std::string())))),
mActiveWeapon(mFirstWeapon), mActiveWeapon(mFirstWeapon),
mLastPosition(getPosition()), mLastPosition(getPosition()),
mFaction((Faction) config.get("faction", 1)) { mFaction((Faction) config.get("faction", 1)) {
@ -48,12 +44,13 @@ Character::~Character() {
* Subtracts health from Actor. Calls onDeath() when health reaches zero and marks * Subtracts health from Actor. Calls onDeath() when health reaches zero and marks
* object for deletion. * object for deletion.
* *
* @param damage Amount of health to subtract. * @param damage Amount of damage taken.
*/ */
void void
Character::onDamage(int damage) { Character::onDamage(int damage) {
mCurrentHealth -= damage; mCurrentHealth -= damage;
if (mCurrentHealth > mMaxHealth) if (mCurrentHealth > mMaxHealth)
mCurrentHealth = mMaxHealth; mCurrentHealth = mMaxHealth;
@ -232,11 +229,35 @@ Character::selectSecondWeapon() {
mActiveWeapon = mSecondWeapon; mActiveWeapon = mSecondWeapon;
} }
/**
* Returns current player health.
*/
int int
Character::getHealth() const { Character::getHealth() const {
return mCurrentHealth; return mCurrentHealth;
} }
/**
* Sets first weapon to weapon, also replacing active weapon if first weapon
* is active.
*/
void
Character::setFirstWeapon(std::shared_ptr<Weapon> weapon) {
if (mFirstWeapon == mActiveWeapon)
mActiveWeapon = weapon;
mFirstWeapon = weapon;
}
/**
* Sets second weapon to weapon, also replacing active weapon if second weapon
* is active.
*/
void
Character::setSecondWeapon(std::shared_ptr<Weapon> weapon) {
if (mSecondWeapon == mActiveWeapon)
mActiveWeapon = weapon;
mSecondWeapon = weapon;
}
void void
Character::setLeftGadget(std::shared_ptr<Gadget> gadget) { Character::setLeftGadget(std::shared_ptr<Gadget> gadget) {

View file

@ -59,6 +59,8 @@ protected:
void selectFirstWeapon(); void selectFirstWeapon();
void selectSecondWeapon(); void selectSecondWeapon();
int getHealth() const; int getHealth() const;
void setFirstWeapon(std::shared_ptr<Weapon> weapon);
void setSecondWeapon(std::shared_ptr<Weapon> weapon);
void setLeftGadget(std::shared_ptr<Gadget> gadget); void setLeftGadget(std::shared_ptr<Gadget> gadget);
void setRightGadget(std::shared_ptr<Gadget> gadget); void setRightGadget(std::shared_ptr<Gadget> gadget);
void useLeftGadget(); void useLeftGadget();

View file

@ -38,6 +38,31 @@ Weapon::Weapon(World& world, Character& holder, const Yaml& config) :
mRequiresAmmo(!config.get("requires_no_ammo", false)) { mRequiresAmmo(!config.get("requires_no_ammo", false)) {
} }
/**
* Constructs a new instance of the given weapon type and returns it as a
* smart pointer.
*/
std::shared_ptr<Weapon>
Weapon::getWeapon(World& world, Character& holder, WeaponType type) {
switch (type) {
case WeaponType::KNIFE:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("knife.yaml")));
case WeaponType::PISTOL:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("pistol.yaml")));
case WeaponType::ASSAULT_RIFLE:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("assault_rifle.yaml")));
case WeaponType::SHOTGUN:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("shotgun.yaml")));
case WeaponType::AUTO_SHOTGUN:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("auto_shotgun.yaml")));
case WeaponType::RIFLE:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("rifle.yaml")));
case WeaponType::HMG:
return std::shared_ptr<Weapon>(new Weapon(world, holder, Yaml("hmg.yaml")));
default: return std::shared_ptr<Weapon>();
}
}
/** /**
* Pull the trigger. * Pull the trigger.
*/ */

View file

@ -24,8 +24,20 @@ class Particle;
class Yaml; class Yaml;
class Weapon : public Item { class Weapon : public Item {
public:
enum class WeaponType {
KNIFE,
PISTOL,
ASSAULT_RIFLE,
SHOTGUN,
AUTO_SHOTGUN,
RIFLE,
HMG
};
public: public:
explicit Weapon(World& world, Character& holder, const Yaml& config); explicit Weapon(World& world, Character& holder, const Yaml& config);
static std::shared_ptr<Weapon> getWeapon(World& world, Character& holder, WeaponType type);
void pullTrigger(); void pullTrigger();
void releaseTrigger(); void releaseTrigger();

View file

@ -9,8 +9,8 @@
#define DG_LOADER_H_ #define DG_LOADER_H_
#include <Thor/Resources.hpp> #include <Thor/Resources.hpp>
#include "../util/Singleton.h" #include "Singleton.h"
/** /**
* This class allows to set default resource folders and subfolders, which means that these * This class allows to set default resource folders and subfolders, which means that these

View file

@ -7,8 +7,8 @@
#ifndef DG_RESOURCEMANAGER_H_ #ifndef DG_RESOURCEMANAGER_H_
#define DG_RESOURCEMANAGER_H_ #define DG_RESOURCEMANAGER_H_
#include "../util/Singleton.h" #include "Singleton.h"
/** /**
* Loads and manages all resources by providing Singleton access to * Loads and manages all resources by providing Singleton access to