This commit is contained in:
2016-02-10 01:16:38 +01:00
parent 5cea3bed3a
commit d931660c56
13 changed files with 181 additions and 100 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ struct EntityWrapper
EntityWrapper FirstChildByName(const std::string& name);
EntityWrapper FirstParentWithComponent(const std::string& componentType);
bool IsChildOf(EntityWrapper potentialParent);
bool Valid();
bool Valid() const;
ComponentWrapper operator[](const char* componentName);
bool operator==(const EntityWrapper& e) const;
+2 -1
View File
@@ -5,6 +5,7 @@
#include <functional>
#include <list>
#include <tuple>
#include <set>
#include "../Common.h"
#include "Event.h"
@@ -107,7 +108,7 @@ private:
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
ContextRelays_t m_ContextRelays;
std::vector<BaseEventRelay*> m_RelaysToSubscribe;
std::vector<std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe;
std::unordered_map<BaseEventRelay*, std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe;
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
std::shared_ptr<EventQueue_t> m_EventQueueRead;
+1 -3
View File
@@ -5,9 +5,7 @@
#include "../Common.h"
#include "AABB.h"
//Fwd declarations.
class Ray;
#include "Ray.h"
namespace OctSpace
{
+1 -1
View File
@@ -68,7 +68,7 @@ protected:
const std::string m_ComponentType;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) = 0;
};
class ImpureSystem : public virtual System
+116 -13
View File
@@ -13,17 +13,23 @@
#include "Input/EInputCommand.h"
#include "Core/EntityFile.h"
#include "Core/EntityFileParser.h"
#include "Core/Octree.h"
#include "Collision/EntityAABB.h"
class WeaponBehaviour;
class WeaponSystem : public PureSystem, ImpureSystem
{
public:
WeaponSystem(SystemParams params, IRenderer* renderer);
WeaponSystem(SystemParams params, IRenderer* renderer, Octree<EntityAABB>* collisionOctree);
virtual void Update(double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) override;
private:
SystemParams m_SystemParams;
IRenderer* m_Renderer;
Octree<EntityAABB>* m_CollisionOctree;
std::unordered_map<EntityWrapper, std::shared_ptr<WeaponBehaviour>> m_ActiveWeapons;
@@ -38,12 +44,18 @@ private:
void selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot);
};
class WeaponBehaviour
class WeaponBehaviour : protected System
{
public:
WeaponBehaviour(EntityWrapper weaponEntity)
: m_Entity(weaponEntity)
WeaponBehaviour(SystemParams systemParams, Octree<EntityAABB>* collisionOctree, EntityWrapper weaponEntity)
: System(systemParams)
, m_CollisionOctree(collisionOctree)
, m_Entity(weaponEntity)
{ }
virtual ~WeaponBehaviour() = default;
WeaponBehaviour(const WeaponBehaviour&) = delete;
WeaponBehaviour& operator=(const WeaponBehaviour &) = delete;
virtual void Fire() = 0;
virtual void CeaseFire() { }
@@ -51,15 +63,19 @@ public:
virtual void Update(double dt) { }
protected:
Octree<EntityAABB>* m_CollisionOctree;
EntityWrapper m_Entity;
};
class AssaultWeaponBehaviour : public WeaponBehaviour
{
public:
AssaultWeaponBehaviour(EntityWrapper weaponEntity)
: WeaponBehaviour(weaponEntity)
{ }
AssaultWeaponBehaviour(SystemParams systemParams, Octree<EntityAABB>* collisionOctree, EntityWrapper weaponEntity)
: WeaponBehaviour(systemParams, collisionOctree, weaponEntity)
{
m_RayRed = ResourceManager::Load<EntityFile>("Schema/Entities/RayRed.xml");
m_RayBlue = ResourceManager::Load<EntityFile>("Schema/Entities/RayBlue.xml");
}
virtual void Fire() override
{
@@ -73,6 +89,25 @@ public:
m_Firing = false;
}
virtual void Reload() override
{
ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"];
int& magAmmo = cAssaultWeapon["MagazineAmmo"];
int magSize = cAssaultWeapon["MagazineSize"];
int& ammo = cAssaultWeapon["Ammo"];
// Don't reload if we're already fully loaded
if (magAmmo == magSize) {
return;
}
// Throw away rounds in magazine to incentivise ammo sharing
int toLoad = glm::min(magSize, ammo);
magAmmo = toLoad;
ammo -= toLoad;
}
virtual void Update(double dt) override
{
if (!m_Firing) {
@@ -82,7 +117,7 @@ public:
m_TimeSinceLastFire += dt;
ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"];
if (m_TimeSinceLastFire > (double)cAssaultWeapon["RPM"] / 60.0) {
if (m_TimeSinceLastFire >= 1.0 / ((double)cAssaultWeapon["RPM"] / 60.0)) {
fireRound();
}
}
@@ -90,7 +125,8 @@ public:
private:
bool m_Firing = false;
double m_TimeSinceLastFire = 0.0;
ComponentWrapper m_Component;
EntityFile* m_RayRed = nullptr;
EntityFile* m_RayBlue = nullptr;
void fireRound()
{
@@ -99,18 +135,85 @@ private:
int& magAmmo = cAssaultWeapon["MagazineAmmo"];
int ammo = cAssaultWeapon["Ammo"];
// Reload if our magazine is empty and we have ammo to fill it with
if (magAmmo <= 0 && ammo > 0) {
CeaseFire();
// Reload if our magazine is empty
if (magAmmo <= 0) {
Reload();
return;
}
// Fire
magAmmo -= 1;
spawnTracer();
m_TimeSinceLastFire = 0.0;
}
void spawnTracer()
{
ComponentWrapper cTeam = m_Entity["Team"];
ComponentInfo::EnumType team = cTeam["Team"];
// Select the right color of effect
EntityFile* rayFile = nullptr;
if (team == cTeam["Team"].Enum("Red")) {
rayFile = m_RayRed;
}
if (team == cTeam["Team"].Enum("Blue")) {
rayFile = m_RayBlue;
}
if (rayFile == nullptr) {
return;
}
// Create the entity
EntityFileParser parser(rayFile);
EntityID rayID = parser.MergeEntities(m_World);
EntityWrapper ray(m_World, rayID);
// Figure out where to put it
EntityWrapper attachment;
if (m_Entity == LocalPlayer || true) {
// Spawn the effect from the weapon view model for the local player
attachment = m_Entity.FirstChildByName("WeaponMuzzle");
}
// TODO: Spawn the effect from the weapon world model once it exists
glm::mat4 transformation = Transform::AbsoluteTransformation(attachment);
glm::vec3 _scale;
glm::vec3 translation;
glm::quat _orientation;
glm::vec3 _skew;
glm::vec4 _perspective;
glm::decompose(transformation, _scale, _orientation, translation, _skew, _perspective);
// Matrix to euler angles
glm::vec3 euler;
euler.y = glm::asin(-transformation[0][2]);
if (cos(euler.y) != 0) {
euler.x = atan2(transformation[1][2], transformation[2][2]);
euler.z = atan2(transformation[0][1], transformation[0][0]);
} else {
euler.x = atan2(-transformation[2][0], transformation[1][1]);
euler.z = 0;
}
// TODO: Spread?
(glm::vec3&)ray["Transform"]["Position"] = translation;
(glm::vec3&)ray["Transform"]["Orientation"] = euler;
glm::vec3& scale = ray["Transform"]["Scale"];
scale.z = traceRayDistance(translation, glm::quat(euler) * glm::vec3(0.f, 0.f, -1.f));
}
float traceRayDistance(glm::vec3 origin, glm::vec3 direction)
{
OctSpace::Output result;
if (m_CollisionOctree->RayCollides(Ray(origin, direction), result)) {
return result.CollideDistance;
} else {
return 0.f;
}
}
};
#endif
@@ -4,5 +4,6 @@
<MagazineSize>32</MagazineSize>
<Ammo>360</Ammo>
<MaxAmmo>360</MaxAmmo>
<RPM>40</RPM>
<BaseDamage>5</BaseDamage>
<RPM>120</RPM>
</AssaultWeapon>
@@ -18,6 +18,7 @@
<xs:element name="MaxAmmo" type="t:int" minOccurs="0">
<xs:annotation><xs:documentation>Maximum ammo able to be carried</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="BaseDamage" type="t:double" minOccurs="0"/>
<xs:element name="RPM" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>Rate of fire in rounds per minute</xs:documentation></xs:annotation>
</xs:element>
+5 -2
View File
@@ -6,6 +6,9 @@
<Origin X="0" Y="0.772000015" Z="0"/>
<Size X="1" Y="1.60000002" Z="1"/>
</c:AABB>
<c:AssaultWeapon>
<RPM>600</RPM>
</c:AssaultWeapon>
<c:Collidable/>
<c:DashAbility>
<CoolDownMaxTimer>2</CoolDownMaxTimer>
@@ -118,7 +121,7 @@
<Entity name="WeaponMuzzle">
<Components>
<c:Transform>
<Position X="0.215000004" Y="-0.153000012" Z="-0.266000003"/>
<Position X="0.215000004" Y="-0.153000012" Z="-0.923000038"/>
</c:Transform>
</Components>
<Children/>
@@ -145,7 +148,7 @@
<Components>
<c:Animation>
<Name>Hold Pos</Name>
<Time>0.79606322555778508</Time>
<Time>0.86415395295813102</Time>
<Speed>1</Speed>
</c:Animation>
<c:HiddenForLocalPlayer/>
+1 -2
View File
@@ -54,7 +54,7 @@ bool EntityWrapper::IsChildOf(EntityWrapper potentialParent)
return false;
}
bool EntityWrapper::Valid()
bool EntityWrapper::Valid() const
{
if (this->World == nullptr) {
return false;
@@ -65,7 +65,6 @@ bool EntityWrapper::Valid()
}
if (!this->World->ValidEntity(this->ID)) {
this->ID = EntityID_Invalid;
return false;
}
+8 -6
View File
@@ -10,10 +10,9 @@ BaseEventRelay::~BaseEventRelay()
void EventBroker::Unsubscribe(BaseEventRelay& relay) // ?
{
auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName);
relay.m_Broker = nullptr;
if (m_IsProcessing) {
m_RelaysToUnsubscribe.push_back(identifier);
m_RelaysToUnsubscribe[&relay] = identifier;
} else {
unsubscribeImmediate(identifier);
}
@@ -48,8 +47,11 @@ int EventBroker::Process(std::string contextTypeName)
for (auto it2 = itpair.first; it2 != itpair.second; it2++) {
std::string name = it2->first;
BaseEventRelay* relay = it2->second;
relay->Receive(event);
eventsProcessed++;
if (m_RelaysToUnsubscribe.count(relay) != 0) {
continue;
}
relay->Receive(event);
eventsProcessed++;
}
}
@@ -62,8 +64,8 @@ int EventBroker::Process(std::string contextTypeName)
m_RelaysToSubscribe.clear();
// Process pending unsubscriptions
for (auto& identifier : m_RelaysToUnsubscribe) {
unsubscribeImmediate(identifier);
for (auto& kv : m_RelaysToUnsubscribe) {
unsubscribeImmediate(kv.second);
}
m_RelaysToUnsubscribe.clear();
+1 -1
View File
@@ -103,7 +103,7 @@ Game::Game(int argc, char* argv[])
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer);
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer, m_OctreeCollision);
m_SystemPipeline->AddSystem<LifetimeSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<CapturePointSystem>(updateOrderLevel);
// Populate Octree with collidables
+3
View File
@@ -71,6 +71,9 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
{
// When a player is actually spawned (since the actual spawning is handled on the server)
if (!IsClient) {
return false;
}
// Check if a player already exists
if (m_PlayerEntities.count(e.PlayerID) != 0) {
+39 -69
View File
@@ -1,13 +1,15 @@
#include "Systems/WeaponSystem.h"
WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer)
WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree<EntityAABB>* collisionOctree)
: System(params)
, PureSystem("Player")
, ImpureSystem()
, m_SystemParams(params)
, m_Renderer(renderer)
, m_CollisionOctree(collisionOctree)
{
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned);
}
void WeaponSystem::Update(double dt)
@@ -15,41 +17,48 @@ void WeaponSystem::Update(double dt)
}
void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt)
void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt)
{
// Update potential weapon behaviour for player
//auto it = m_ActiveWeapons.find(entity);
//if (it != m_ActiveWeapons.end()) {
// //if (it->first.Valid()) {
// it->second->Update(dt);
// //} else {
// // m_ActiveWeapons.erase(it);
// //}
//}
}
bool WeaponSystem::OnInputCommand(Events::InputCommand& e)
{
EntityWrapper player = e.Player;
if (e.PlayerID == -1) {
player = LocalPlayer;
}
// Make sure player is alive
if (!e.Player.Valid()) {
if (!player.Valid()) {
return false;
}
// Weapon selection
if (e.Command == "SelectWeapon") {
selectWeapon(e.Player, static_cast<ComponentInfo::EnumType>(e.Value));
}
// Only shoot client-side!
if (!IsClient) {
return false;
}
// Only shoot if the player is alive
if (!e.Player.Valid()) {
return false;
}
if (e.Command == "PrimaryFire" && e.Value > 0) {
Events::Shoot eShoot;
if (e.PlayerID == -1) {
eShoot.Player = LocalPlayer;
} else {
eShoot.Player = e.Player;
if (e.Value != 0) {
selectWeapon(player, static_cast<ComponentInfo::EnumType>(e.Value));
}
}
// Fire
if (e.Command == "PrimaryFire") {
if (m_ActiveWeapons.find(player) != m_ActiveWeapons.end()) {
auto weapon = m_ActiveWeapons.at(player);
if (e.Value > 0) {
weapon->Fire();
} else {
weapon->CeaseFire();
}
}
m_EventBroker->Publish(eShoot);
}
return true;
@@ -60,7 +69,11 @@ void WeaponSystem::selectWeapon(EntityWrapper player, ComponentInfo::EnumType sl
// Primary
if (slot == 1) {
// TODO: if class...
m_ActiveWeapons[player] = std::make_shared<AssaultWeaponBehaviour>();
if (m_ActiveWeapons.count(player) == 0) {
m_ActiveWeapons.insert(std::make_pair(player, std::make_shared<AssaultWeaponBehaviour>(m_SystemParams, m_CollisionOctree, player)));
} else {
m_ActiveWeapons.erase(player);
}
}
// Secondary
@@ -83,49 +96,6 @@ bool WeaponSystem::OnShoot(Events::Shoot& eShoot)
return false;
}
// TODO: Weapon firing effects here
auto rayRed = ResourceManager::Load<EntityFile>("Schema/Entities/RayRed.xml");
auto rayBlue = ResourceManager::Load<EntityFile>("Schema/Entities/RayBlue.xml");
EntityWrapper weapon = eShoot.Player.FirstChildByName("WeaponMuzzle");
if (weapon.Valid()) {
EntityWrapper ray;
if ((ComponentInfo::EnumType)eShoot.Player["Team"]["Team"] == eShoot.Player["Team"]["Team"].Enum("Red")) {
EntityFileParser parser(rayRed);
EntityID rayID = parser.MergeEntities(m_World);
ray = EntityWrapper(m_World, rayID);
} else {
EntityFileParser parser(rayBlue);
EntityID rayID = parser.MergeEntities(m_World);
ray = EntityWrapper(m_World, rayID);
}
glm::mat4 transformation = Transform::AbsoluteTransformation(weapon);
glm::vec3 scale;
glm::vec3 translation;
glm::quat orientation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(transformation, scale, orientation, translation, skew, perspective);
// Matrix to euler angles
glm::vec3 euler;
euler.y = glm::asin(-transformation[0][2]);
if (cos(euler.y) != 0) {
euler.x = atan2(transformation[1][2], transformation[2][2]);
euler.z = atan2(transformation[0][1], transformation[0][0]);
} else {
euler.x = atan2(-transformation[2][0], transformation[1][1]);
euler.z = 0;
}
//LOG_DEBUG("rotation: %f %f %f", euler.x, euler.y, euler.z);
(glm::vec3&)ray["Transform"]["Position"] = translation;
(glm::vec3&)ray["Transform"]["Orientation"] = euler;
//(glm::vec3&)ray["Transform"]["Orientation"] = Transform::AbsoluteOrientationEuler(weapon);
}
// Only run further picking code for the local player!
if (eShoot.Player != LocalPlayer) {
return false;