1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_CCMPUNITMOTIONMANAGER
#define INCLUDED_CCMPUNITMOTIONMANAGER
#include "simulation2/system/Component.h"
#include "ICmpUnitMotionManager.h"
#include "simulation2/MessageTypes.h"
#include "simulation2/components/ICmpTerrain.h"
#include "simulation2/helpers/Grid.h"
#include "simulation2/system/EntityMap.h"
class CCmpUnitMotion;
class CCmpUnitMotionManager final : public ICmpUnitMotionManager
{
public:
static void ClassInit(CComponentManager& componentManager);
DEFAULT_COMPONENT_ALLOCATOR(UnitMotionManager)
/**
* Maximum value for pushing pressure.
*/
static constexpr int MAX_PRESSURE = 255;
// Persisted state for each unit.
struct MotionState
{
MotionState(ICmpPosition* cmpPos, CCmpUnitMotion* cmpMotion);
// Component references - these must be kept alive for the duration of motion.
// NB: this is generally a super dangerous thing to do,
// but the tight coupling with CCmpUnitMotion makes it workable.
// NB: this assumes that components do _not_ move in memory,
// which is currently a fair assumption but might change in the future.
ICmpPosition* cmpPosition;
CCmpUnitMotion* cmpUnitMotion;
// Position before units start moving
CFixedVector2D initialPos;
// Transient position during the movement.
CFixedVector2D pos;
// Accumulated "pushing" from nearby units.
CFixedVector2D push;
fixed speed;
fixed initialAngle;
fixed angle;
// Used for formations - units with the same control group won't push at a distance.
// (this is required because formations may be tight and large units may end up never settling.
entity_id_t controlGroup = INVALID_ENTITY;
// This is a ad-hoc counter to store under how much pushing 'pressure' an entity is.
// More pressure will slow the unit down and make it harder to push,
// which effectively bogs down groups of colliding units.
uint8_t pushingPressure = 0;
// Meta-flag -> this entity won't push nor be pushed.
// (used for entities that have their obstruction disabled).
bool ignore = false;
// If true, the entity needs to be handled during movement.
bool needUpdate = false;
bool wentStraight = false;
bool wasObstructed = false;
// Clone of the obstruction manager flag for efficiency
bool isMoving = false;
};
// "Template" state, not serialized (cannot be changed mid-game).
// The maximal distance at which units push each other is the combined unit clearances, multipled by this factor,
// itself pre-multiplied by the circle-square correction factor.
entity_pos_t m_PushingRadiusMultiplier;
// Additive modifiers to the maximum pushing distance for moving units and idle units respectively.
entity_pos_t m_MovingPushExtension;
entity_pos_t m_StaticPushExtension;
// Multiplier for the pushing 'spread'.
// This should be understand as the % of the maximum distance where pushing will be "in full force".
entity_pos_t m_MovingPushingSpread;
entity_pos_t m_StaticPushingSpread;
// Pushing forces below this value are ignored - this prevents units moving forever by very small increments.
entity_pos_t m_MinimalPushing;
// Multiplier for pushing pressure strength.
entity_pos_t m_PushingPressureStrength;
// Per-turn reduction in pushing pressure.
entity_pos_t m_PushingPressureDecay;
// These vectors are reconstructed on deserialization.
EntityMap<MotionState> m_Units;
EntityMap<MotionState> m_FormationControllers;
// Turn-local state below, not serialised.
Grid<std::vector<EntityMap<MotionState>::iterator>> m_MovingUnits;
bool m_ComputingMotion;
static std::string GetSchema()
{
return "<a:component type='system'/><empty/>";
}
void Init(const CParamNode& UNUSED(paramNode)) override;
void Deinit() override
{
}
void Serialize(ISerializer& serialize) override;
void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) override;
void HandleMessage(const CMessage& msg, bool global) override;
void Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController) override;
void Unregister(entity_id_t ent) override;
bool ComputingMotion() const override
{
return m_ComputingMotion;
}
bool IsPushingActivated() const override
{
return m_PushingRadiusMultiplier != entity_pos_t::Zero();
}
private:
void OnDeserialized();
void ResetSubdivisions();
void OnTurnStart();
void MoveUnits(fixed dt);
void MoveFormations(fixed dt);
void Move(EntityMap<MotionState>& ents, fixed dt);
void Push(EntityMap<MotionState>::value_type& a, EntityMap<MotionState>::value_type& b, fixed dt);
};
REGISTER_COMPONENT_TYPE(UnitMotionManager)
#endif // INCLUDED_CCMPUNITMOTIONMANAGER
|