0ad/source/simulation2/components/CCmpUnitMotionManager.h

173 lines
5.3 KiB
C
Raw Normal View History

/* Copyright (C) 2025 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 "maths/Fixed.h"
#include "maths/FixedVector2D.h"
#include "simulation2/components/ICmpUnitMotionManager.h"
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
#include "simulation2/helpers/Grid.h"
#include "simulation2/helpers/Position.h"
#include "simulation2/system/Component.h"
#include "simulation2/system/Entity.h"
#include "simulation2/system/EntityMap.h"
#include <cstdint>
#include <string>
#include <vector>
class CCmpUnitMotion;
class ICmpPosition;
class CCmpUnitMotionManager final : public ICmpUnitMotionManager
{
public:
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
static void ClassInit(CComponentManager& componentManager);
DEFAULT_COMPONENT_ALLOCATOR(UnitMotionManager)
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
/**
* Maximum value for pushing pressure.
*/
static constexpr int MAX_PRESSURE = 255;
// Persisted state for each unit.
struct MotionState
{
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
MotionState(ICmpPosition* cmpPos, CCmpUnitMotion* cmpMotion);
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
// Component references - these must be kept alive for the duration of motion.
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
// 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;
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
// Accumulated "pushing" from nearby units.
CFixedVector2D push;
fixed speed;
fixed initialAngle;
fixed angle;
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
// 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;
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
// 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;
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
// 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.
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
bool needUpdate = false;
bool wentStraight = false;
bool wasObstructed = false;
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
// Clone of the obstruction manager flag for efficiency
bool isMoving = false;
};
// "Template" state, not serialized (cannot be changed mid-game).
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
// 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;
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
// 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;
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
// 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&) 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
{
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
return m_PushingRadiusMultiplier != entity_pos_t::Zero();
}
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
private:
UnitMotion pushing improvements The main change is the introduction of a 'pushing pressure' counter on units. This counter increases when units get pushed around, and decreases over time. In essence, units under high pressure move slower & are harder to push around. The major effect is that units can now get bogged down when very dense groups start colliding. This makes movement more realistic, makes unit movement more 'chokepointy', and generally improves the mathematical soundness of the system (lower values are easier to handle for our 200ms turns). Other changes: - The logic to detect units crossing each other's path has been reworked. Units that run towards each other should not more obviously avoid each other. - New parameters: 'Spread' is a measure of how strong the pushing effect is based on distance. With the current settings, static-pushing is rather 'on/off', whereas moving-pushing is more gradual (and thus the max influence distance was increased when moving). - Default values have been tweaked for lower overlap. - Units only looked at other units within their grid region. This led to overlap near grid-borders. Units now look at neighboring grid elements, which largely removes this issue. While this may be slower, the performance of pushing was largely negligible before, so it is unlikely to become a main cause of lag (and overlap was generally disliked by players). - Units no longer orient in the direction of pushing, but instead keep facing their target. This can look slightly odd under very heavy pushing forces, but vastly improves behaviour of very slow units such as rams (since they spend much less time turning around). As a side-effect, clean up angle code following acc780bcbb . Engine changes: - Add a debug rendering mode at compile-time to help understand what is happening. - Make it possible to constexpr initialise fractional fixed numbers by using FromFraction The 'pressure' change was inspired by alre's suggestion at https://wildfiregames.com/forum/topic/56436-for-a-better-unit-movement/#comment-461987 Refs #6127 Differential Revision: https://code.wildfiregames.com/D4439 This was SVN commit r26245.
2022-01-24 07:36:13 -08:00
void OnDeserialized();
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
void ResetSubdivisions();
void OnTurnStart();
void MoveUnits(fixed dt);
void MoveFormations(fixed dt);
void Move(EntityMap<MotionState>& ents, fixed dt);
Add a simple 'pushing' logic to unit motion to improve movement. This implements a form of crowd movement that I've generally called 'unit pushing' in the last few years. Essentially, any two units will push each other away when they're too close. This makes it possible to ignore unit-unit obstructions, and thus makes movement much smoother in crowds. This first iteration of this system only allows pushing between idle units and between moving units (i.e. a moving unit does not affect an idle one). This is because the unitMotion logic to detect it is stuck & needs to use the pathfinders starts breaking: units can fail to move because they are pushed away from their intended movement, and the current logic fails to handle this gracefully. Thankfully, the most value of this patch in terms of player experience is found in the improvements to group movements and shuttling. Other impacts: - As the short pathfinder is called less often, we can increase the starting search range & reduce the # of max turns, both improving collision recovery. - The performance of idle units is slightly worsened, as they must be checked for idle-idle collisions. If needed a 'sleeping' system, as used in physics engine, could be implemented. - In general, however, expect slight performance improvements, as fewer short paths are computed. - Gathering efficiency should increase slightly, since shuttling times are likely reduced slightly. - As a sanity change to improve some edge cases (units that say they're moving, i.e. pushable, but don't actually move), the 'going straight' logic is turned off if a short path has been computed. This requires a few cascading changes to work correctly. Technical notes: - To reduce the cost of the n^2 comparisons that pushing requires, units are only compared within a small square on a grid which is lazily reconstructed each turn. The overhead seems rather small, and this is much simpler than keeping an up-to-date grid. - The design is intended to be parallelisable if needed someday. - The pathfinder's CheckMovement ignores moving units in UnitMotion, as that is now the spec. Idle units are not ignored, which is required for the 'collision' detection to work correctly (see above). Refs #3442 (not fixed - idle units are not pushed by moving units). Fixes #5084 (the overlap can still happen, but units will push each other away). Differential Revision: https://code.wildfiregames.com/D1490 This was SVN commit r25182.
2021-04-02 09:30:59 -07:00
void Push(EntityMap<MotionState>::value_type& a, EntityMap<MotionState>::value_type& b, fixed dt);
};
REGISTER_COMPONENT_TYPE(UnitMotionManager)
#endif // INCLUDED_CCMPUNITMOTIONMANAGER