Use the terrain-only grid for terrain edges in the short pathfinder algorithm. This grid is updated on each terrain change, whereas the passability grid is updated once a turn. This caused OOS on rejoin, fixes #3292.

However, using the terrain-only grid reveals one discrepancy between the
short pathfinder (which uses unit radii) and the long one (which uses
unit clearances). So I implemented the change proposed by sanderd17 in
#3294, which is removing unit radius and using only the pathfinder
clearance. Refs #3294
Now some tweaking has to be done in the templates, so that units get a
passability class suited to their apparent size. In the meantime the
unit motion is quite bugged.

This was SVN commit r16867.
This commit is contained in:
Nicolas Auvray 2015-07-18 08:37:49 +00:00
parent 35071dd44b
commit 128a603287
89 changed files with 121 additions and 336 deletions

View File

@ -872,7 +872,7 @@ Formation.prototype.GetEstimatedOrientation = function(pos)
};
/**
* Set formation controller's radius and speed based on its current members.
* Set formation controller's speed based on its current members.
*/
Formation.prototype.ComputeMotionParameters = function()
{
@ -881,10 +881,6 @@ Formation.prototype.ComputeMotionParameters = function()
for each (var ent in this.members)
{
var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
if (cmpObstruction)
maxRadius = Math.max(maxRadius, cmpObstruction.GetUnitRadius());
var cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion);
if (cmpUnitMotion)
minSpeed = Math.min(minSpeed, cmpUnitMotion.GetWalkSpeed());
@ -892,7 +888,6 @@ Formation.prototype.ComputeMotionParameters = function()
minSpeed *= this.GetSpeedMultiplier();
var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
cmpUnitMotion.SetUnitRadius(maxRadius);
cmpUnitMotion.SetSpeed(minSpeed);
// TODO: we also need to do something about PassabilityClass, CostClass

View File

@ -136,7 +136,6 @@ function TestFormationExiting(mode)
});
AddMock(controller, IID_UnitMotion, {
SetUnitRadius: function(r) { },
SetSpeed: function(speed) { },
MoveToPointRange: function(x, z, minRange, maxRange) { },
GetPassabilityClassName: function() { return "default"; },
@ -281,7 +280,6 @@ function TestMoveIntoFormationWhileAttacking()
});
AddMock(controller, IID_UnitMotion, {
SetUnitRadius: function(r) { },
SetSpeed: function(speed) { },
MoveToPointRange: function(x, z, minRange, maxRange) { },
IsInTargetRange: function(target, min, max) { return true; },

View File

@ -30,9 +30,6 @@
<History>The most powerful hero of them all - son of Philip II, king of Macedonia (336 BC - 323 BC). After conquering the rest of the Thracians and quelling the unrest of the Greeks, Alexander embarked on a world-conquest march. Defeating the Persian forces at Granicus (334 BC), Issus (333 BC) and Gaugamela (331 BC), he became master of the Persian Empire. Entering India, he defeated king Porus at Hydaspes (326 BC), but his weary troops made him halt. Died in Babylon at the age of 33 while planning a campaign against Arabia.</History>
<Icon>units/hele_hero_alexander.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<StatusBars>
<BarWidth>6.0</BarWidth>
<BarHeight>0.6</BarHeight>

View File

@ -22,9 +22,6 @@
<History>The most powerful hero of them all - son of Philip II, king of Macedonia (336 BC - 323 BC). After conquering the rest of the Thracians and quelling the unrest of the Greeks, Alexander embarked on a world-conquest march. Defeating the Persian forces at Granicus (334 BC), Issus (333 BC) and Gaugamela (331 BC), he became master of the Persian Empire. Entering India, he defeated king Porus at Hydaspes (326 BC), but his weary troops made him halt. Died in Babylon at the age of 33 while planning a campaign against Arabia.</History>
<Icon>units/hele_hero_demetrius.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<StatusBars>
<BarWidth>6.0</BarWidth>
<BarHeight>0.6</BarHeight>

View File

@ -30,9 +30,6 @@
<History>The most powerful hero of them all - son of Philip II, king of Macedonia (336 BC - 323 BC). After conquering the rest of the Thracians and quelling the unrest of the Greeks, Alexander embarked on a world-conquest march. Defeating the Persian forces at Granicus (334 BC), Issus (333 BC) and Gaugamela (331 BC), he became master of the Persian Empire. Entering India, he defeated king Porus at Hydaspes (326 BC), but his weary troops made him halt. Died in Babylon at the age of 33 while planning a campaign against Arabia.</History>
<Icon>units/hele_hero_leonidas.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<StatusBars>
<BarWidth>6.0</BarWidth>
<BarHeight>0.6</BarHeight>

View File

@ -9,9 +9,6 @@
<SpecificName>Camel</SpecificName>
<Icon>gaia/fauna_camel.png</Icon>
</Identity>
<Obstruction>
<Unit radius="1.75"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -19,9 +19,6 @@
<GenericName>Nile Crocodile</GenericName>
<Icon>gaia/fauna_crocodile.png</Icon>
</Identity>
<Obstruction>
<Unit radius="2.4"/>
</Obstruction>
<Position>
<Anchor>pitch-roll</Anchor>
</Position>

View File

@ -49,9 +49,6 @@
<Loot>
<xp>75</xp>
</Loot>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -15,9 +15,6 @@
<SpecificName>African Elephant (Infant)</SpecificName>
<Icon>gaia/fauna_elephant_african_infant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="1.5"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -49,9 +49,6 @@
<Loot>
<xp>60</xp>
</Loot>
<Obstruction>
<Unit radius="2.7"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -36,9 +36,6 @@
<Loot>
<xp>50</xp>
</Loot>
<Obstruction>
<Unit radius="2.6"/>
</Obstruction>
<ResourceSupply>
<Amount>500</Amount>
<Type>food.meat</Type>

View File

@ -12,9 +12,6 @@
<SpecificName>Giraffe (Adult)</SpecificName>
<Icon>gaia/fauna_giraffe.png</Icon>
</Identity>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -9,9 +9,6 @@
<SpecificName>Giraffe (Juvenile)</SpecificName>
<Icon>gaia/fauna_giraffe.png</Icon>
</Identity>
<Obstruction>
<Unit radius="1.5"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -9,9 +9,6 @@
<SpecificName>Horse</SpecificName>
<Icon>gaia/fauna_horse.png</Icon>
</Identity>
<Obstruction>
<Unit radius="1.5"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -17,9 +17,6 @@
<Icon>gaia/fauna_fish.png</Icon>
</Identity>
<Minimap disable=""/>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
<Position>
<Altitude>-1</Altitude>
<Floating>true</Floating>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_gaia_flora_bush_berry">
<Obstruction>
<Unit radius="2.0"/>
<Static width="4.0" depth="4.0"/>
</Obstruction>
<VisualActor>
<Actor>props/flora/berry_bush.xml</Actor>

View File

@ -10,7 +10,7 @@
<Icon>gaia/flora_bush_berry.png</Icon>
</Identity>
<Obstruction>
<Unit radius="0.9"/>
<Static width="1.8" depth="1.8"/>
</Obstruction>
<ResourceSupply>
<Amount>400</Amount>

View File

@ -9,7 +9,7 @@
<History>The Cretan Date Palm is an palm tree generally found on the island of Crete, but in ancient times its range spanned the entire Aegean Sea. The Peloponnese had Cretan Date Palm forests along its shores.</History>
</Identity>
<Obstruction>
<Unit radius="2.25"/>
<Static width="5.5" depth="5.5"/>
</Obstruction>
<ResourceSupply>
<Amount>300</Amount>

View File

@ -10,7 +10,7 @@
<Icon>gaia/flora_bush_berry.png</Icon>
</Identity>
<Obstruction>
<Unit radius="0.9"/>
<Static width="1.8" depth="1.8"/>
</Obstruction>
<ResourceSupply>
<Amount>400</Amount>

View File

@ -7,9 +7,6 @@
<Identity>
<Civ>skirm</Civ>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
<Promotion disable=""/>
<SkirmishReplacer/>
<VisualActor>

View File

@ -4,7 +4,4 @@
<Civ>athen</Civ>
<SpecificName>Lithobólos</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>athen</Civ>
<SpecificName>Oxybelḗs</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>cart</Civ>
<SpecificName>Ballista</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>cart</Civ>
<SpecificName>Oxybelḗs</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>mace</Civ>
<SpecificName>Lithobólos</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>mace</Civ>
<SpecificName>Oxybelḗs</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>ptol</Civ>
<SpecificName>Lithobólos</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>ptol</Civ>
<SpecificName>Polybolos</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
</Entity>

View File

@ -28,7 +28,4 @@
<Civ>rome</Civ>
<SpecificName>Ballista</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>sele</Civ>
<SpecificName>Lithobólos</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
</Entity>

View File

@ -4,7 +4,4 @@
<Civ>spart</Civ>
<SpecificName>Oxybelḗs</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
</Entity>

View File

@ -8,6 +8,6 @@
<GenericName>Generic Flora</GenericName>
</Identity>
<Obstruction>
<Unit radius="1.5"/>
<Static width="3.0" depth="3.0"/>
</Obstruction>
</Entity>

View File

@ -9,7 +9,7 @@
<Classes datatype="tokens">ForestPlant</Classes>
</Identity>
<Obstruction>
<Unit radius="1.0"/>
<Static width="2.0" depth="2.0"/>
<BlockMovement>false</BlockMovement>
<BlockPathfinding>false</BlockPathfinding>
</Obstruction>

View File

@ -46,7 +46,7 @@
<Type>unit</Type>
</Minimap>
<Obstruction>
<Unit radius="0.8"/>
<Unit/>
<Active>true</Active>
<BlockMovement>true</BlockMovement>
<BlockPathfinding>false</BlockPathfinding>

View File

@ -48,9 +48,6 @@
<stone>0</stone>
<metal>0</metal>
</Loot>
<Obstruction>
<Unit radius="1.0"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -29,9 +29,6 @@
formations/wedge
</Formations>
</Identity>
<Obstruction>
<Unit radius="1.0"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -26,9 +26,6 @@
formations/skirmish
</Formations>
</Identity>
<Obstruction>
<Unit radius="1.0"/>
</Obstruction>
<Sound>
<SoundGroups>
<death>actor/fauna/death/death_horse.xml</death>

View File

@ -25,9 +25,6 @@
formations/skirmish
</Formations>
</Identity>
<Obstruction>
<Unit radius="1.0"/>
</Obstruction>
<Sound>
<SoundGroups>
<death>actor/fauna/death/death_horse.xml</death>

View File

@ -28,9 +28,6 @@
<Icon>gaia/fauna_elephant.png</Icon>
<History>War elephants were used by many Eastern and African cultures.</History>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -60,9 +60,6 @@
<stone>0</stone>
<metal>0</metal>
</Loot>
<Obstruction>
<Unit radius="1.0"/>
</Obstruction>
<Promotion>
<RequiredXp>100</RequiredXp>
</Promotion>

View File

@ -10,7 +10,6 @@
<Classes datatype="tokens">SeaCreature</Classes>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
<BlockMovement>false</BlockMovement>
<BlockPathfinding>false</BlockPathfinding>
</Obstruction>

View File

@ -17,9 +17,6 @@
<Tooltip>Kill, then collect food from this bountiful oceanic resource.</Tooltip>
<Icon>gaia/fauna_fish.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<Position>
<Floating>true</Floating>
</Position>

View File

@ -32,9 +32,6 @@
<GenericName>Ship</GenericName>
<VisibleClasses datatype="tokens">Ship</VisibleClasses>
</Identity>
<Obstruction>
<Unit radius="8.0"/>
</Obstruction>
<Position>
<Floating>true</Floating>
<TurnRate>3.0</TurnRate>

View File

@ -36,9 +36,6 @@
<Tooltip>Rapidly drain the health of enemy ships. Slowly loses health due to being on fire, so use the Fire Ship quickly.</Tooltip>
<RequiredTechnology>phase_town</RequiredTechnology>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<StatusBars>
<BarWidth>6.0</BarWidth>
<BarHeight>0.5</BarHeight>

View File

@ -33,9 +33,6 @@
<Tooltip>Fish the waters for Food. Garrison a support or infantry unit inside to boost fishing rate.</Tooltip>
<Classes datatype="tokens">FishingBoat</Classes>
</Identity>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<ResourceGatherer>
<MaxDistance>6.0</MaxDistance>
<BaseSpeed>1.0</BaseSpeed>

View File

@ -53,9 +53,6 @@
<Classes datatype="tokens">Ranged SiegeTower</Classes>
<Tooltip>Garrison up to 20 infantry inside to increase arrow count from 0 to 10.</Tooltip>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<Selectable>
<Overlay>
<Texture>

View File

@ -10,9 +10,6 @@
<History>Athens always relied upon the sea for trade, but when the commercial harbor at Piraeus was constructed in the 470s BC, maritime commerce increased exponentially. The growing population of Attica required grain imports from Egypt and the Athenian military colonies (Kleurukia) from the Bosporus and the formation of the Delian League headed by Athens helped clear the shipping lanes of pirates and hostile forces from Persia.</History>
<Icon>units/hele_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/athenians/merchant_new.xml</Actor>
</VisualActor>

View File

@ -13,9 +13,6 @@
<History>The Britons were one of the last European peoples to use two-horse chariots in combat. They had two iron-rimmed wheels and a flat riding platform that typically carried a driver and a warrior. Useless as shock weapons against tightly packed troops, they were useful for running down individual soldiers and as a stable mount to launch javelins from. The heads of defeated opponents often adorned the chassis to show the warrior's prowess.</History>
<Icon>units/celt_champion_cavalry_brit.png</Icon>
</Identity>
<Obstruction>
<Unit radius="1.3"/>
</Obstruction>
<VisualActor>
<Actor>units/celts/champion_unit_4.xml</Actor>
</VisualActor>

View File

@ -25,9 +25,6 @@
<History>Ammianus Marcellinus described how difficult it would be for a band of foreigners to deal with a Celt if he called in the help of his wife. For she was stronger than he was and could rain blows and kicks upon the assailants equal in force to the shots of a catapult. Boudicca, queen of the Iceni, was said to be 'very tall and terrifying in appearance; her voice was very harsh and a great mass of red hair fell over her shoulders. She wore a tunic of many colors over which a thick cloak was fastened by a brooch.</History>
<Icon>units/celt_hero_boudicca.png</Icon>
</Identity>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<VisualActor>
<Actor>units/celts/boudicca_chariot.xml</Actor>
</VisualActor>

View File

@ -13,9 +13,6 @@
<History>Celtic assaults on fortified positions were relegated largely to three methods. Creating a shell of shields and setting fire to gatehouses, sapping, at which they were noted as being most expert by Caesar, and rams, known only from votive inscriptions and some Celtic art.</History>
<Icon>units/celt_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/celts/siege_ram.xml</Actor>
</VisualActor>

View File

@ -21,9 +21,6 @@ Transport many soldiers across the sea.</Tooltip>
<History>The ships of Gaul were described by Julias Caesar as: flat bottoms to ride the shallows, exceptionally high bows and sterns, hulls were made entirely of oak, the foot wide cross-timbers were fastened with iron bolts as thick as a man's thumb, sails of raw hides or thin leather, adapted for sailing treacherous and stormy waters of the north atlantic. Caesar could not injure them by ramming because they were so solidly built, and their height made it difficult to reach them with missiles or board them with grappling irons.</History>
<Icon>units/celt_ship_trireme.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<UnitMotion>
<WalkSpeed>14</WalkSpeed>
</UnitMotion>

View File

@ -12,9 +12,6 @@
<Icon>units/cart_ship_merchant.png</Icon>
<RequiredTechnology>phase_village</RequiredTechnology>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<Trader>
<GainMultiplier>1.25</GainMultiplier>
</Trader>

View File

@ -13,9 +13,6 @@
<History>Celtic assaults on fortified positions were relegated largely to three methods. Creating a shell of shields and setting fire to gatehouses, sapping, at which they were noted as being most expert by Caesar, and rams, known only from votive inscriptions and some Celtic art.</History>
<Icon>units/celt_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/celts/siege_ram.xml</Actor>
</VisualActor>

View File

@ -21,9 +21,6 @@ Transport many soldiers across the sea.</Tooltip>
<History>The ships of Gaul were described by Julias Caesar as: flat bottoms to ride the shallows, exceptionally high bows and sterns, hulls were made entirely of oak, the foot wide cross-timbers were fastened with iron bolts as thick as a man's thumb, sails of raw hides or thin leather, adapted for sailing treacherous and stormy waters of the north atlantic. Caesar could not injure them by ramming because they were so solidly built, and their height made it difficult to reach them with missiles or board them with grappling irons.</History>
<Icon>units/celt_ship_trireme.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<UnitMotion>
<WalkSpeed>14</WalkSpeed>
</UnitMotion>

View File

@ -10,9 +10,6 @@
<History>It is not known if any of the Iberians culture tribes used rams; the unit is added to the civ roster for gameplay purposes.</History>
<Icon>units/iber_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="3"/>
</Obstruction>
<VisualActor>
<Actor>structures/iberians/siege_ram.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>The Iberians, especially along the western and northwestern coasts of the peninsula, had been trading by sea with peoples in North Africa, Western Europe along the coast of Gaul and the British Isles by boat well back into the 2nd millennium BC. As such, their ships were very seaworthy, crossing stretches of the Atlantic Ocean (while they are not known to have traded by sea in the Mediterranean). Though the Carthaginians came along around the beginning of the 1st millennium and co-opted much of that trade, along with the Greeks in the Mediterranean, with 'better ships', they still would have influenced the seafaring peoples who built the 'high sided sailing vessels' along the Atlantic Seaboard. So it is not such a stretch to specify a good strong sailing ship for Iberians that can be used as either a merchant trading vessel or a quasi-war fighting transport of units.</History>
<Icon>units/iber_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/iberians/merchant.xml</Actor>
</VisualActor>

View File

@ -21,9 +21,6 @@ Transport many soldiers across the sea.</Tooltip>
<History>.</History>
<Icon>units/celt_ship_trireme.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<UnitMotion>
<WalkSpeed>14</WalkSpeed>
</UnitMotion>

View File

@ -10,9 +10,6 @@
<History>Macedonian siege ram</History>
<Icon>units/mace_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/macedonians/siege_ram.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>Need History</History>
<Icon>units/hele_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/hellenes/merchant_new.xml</Actor>
</VisualActor>

View File

@ -21,9 +21,6 @@
<stone>0</stone>
<metal>20</metal>
</Loot>
<Obstruction>
<Unit radius="1.3"/>
</Obstruction>
<ResourceGatherer>
<MaxDistance>5.0</MaxDistance>
<Capacities>

View File

@ -15,9 +15,6 @@ Hero Aura: TBD.
Hero Special: "Edicts of Ashoka" - Edict Pillars of Ashoka can be built during Ashoka's lifetime.</Tooltip>
<History>TBD.</History>
</Identity>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<VisualActor>
<Actor>units/mauryans/hero_chariot.xml</Actor>
</VisualActor>

View File

@ -6,9 +6,6 @@
<History>Light Warship.</History>
<Icon>units/maur_ship_bireme.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<UnitMotion>
<WalkSpeed>14</WalkSpeed>
</UnitMotion>

View File

@ -20,9 +20,6 @@
<Tooltip>Classes: Mechanical Warship Medium Ranged Melee.</Tooltip>
<Icon>units/maur_ship_trireme.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<UnitMotion>
<WalkSpeed>14</WalkSpeed>
</UnitMotion>

View File

@ -39,9 +39,6 @@
<stone>10</stone>
<metal>10</metal>
</Loot>
<Obstruction>
<Unit radius="3.0"/>
</Obstruction>
<Position>
<Anchor>pitch</Anchor>
</Position>

View File

@ -23,9 +23,6 @@ Causes trample damage to enemy units.</Tooltip>
<stone>0</stone>
<metal>20</metal>
</Loot>
<Obstruction>
<Unit radius="1.3"/>
</Obstruction>
<Promotion>
<Entity>units/pers_cavalry_archer_a</Entity>
</Promotion>

View File

@ -34,9 +34,6 @@ Ranged attack 2x vs. spearmen. Ranged attack 1.5x vs. Swordsmen.</Tooltip>
<stone>0</stone>
<metal>100</metal>
</Loot>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<VisualActor>
<Actor>units/persians/hero_darius_chariot.xml</Actor>
</VisualActor>

View File

@ -33,9 +33,6 @@
<stone>0</stone>
<metal>100</metal>
</Loot>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<VisualActor>
<Actor>units/persians/hero_xerxes_chariot.xml</Actor>
</VisualActor>

View File

@ -17,9 +17,6 @@
<History>Even after the fall of the Neo-Assyrian Empire, the Assyrians themselves remained active in events. Under the Achaemenids they served in their own national regiments together with the Chaldeans. Naturally, they continued to employ the siege skills that made Assyria so famous in Persian service.</History>
<Icon>units/pers_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/persians/siege_ram.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>Need History</History>
<Icon>units/ptol_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/ptolemies/merchant_ship.xml</Actor>
</VisualActor>

View File

@ -31,9 +31,6 @@
<Civ>rome</Civ>
<SpecificName>Ballista</SpecificName>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
<Vision>
<Range>88</Range>
</Vision>

View File

@ -10,9 +10,6 @@
<History>There are several famous sieges during the time of the Republic which required the use of extensive siege weaponry – Syracuse (212 BC), Carthage (148 – 146 BC) and Tigranocerta (68 BC) – they were all carried out successfully.</History>
<Icon>units/rome_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<VisualActor>
<Actor>units/romans/siege_ram.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>The Corbita was the most famous class of Roman merchant ships, known as Oneraria. They had a cargo capacity of 60-300 tons on average, with variants known to carry as much as 400 tons. These vessels traveled all over the Mediterranean, and could be found literally on every trade route.</History>
<Icon>units/rome_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="8.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/romans/merchantman.xml</Actor>
</VisualActor>

View File

@ -22,9 +22,6 @@
<stone>0</stone>
<metal>20</metal>
</Loot>
<Obstruction>
<Unit radius="2.0"/>
</Obstruction>
<ResourceGatherer>
<MaxDistance>5.0</MaxDistance>
<Capacities>

View File

@ -10,9 +10,6 @@
<History>Need History</History>
<Icon>units/hele_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/hellenes/merchant_new.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>Spartans were not known for their siege craft, but they did know how to build rudimentary siege weapons like battering rams and use basic siege techniques. The siege of Plataea during the Peloponnesian War lasted 2 years.</History>
<Icon>units/spart_mechanical_siege_ram.png</Icon>
</Identity>
<Obstruction>
<Unit radius="4.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/spartans/siege_ram.xml</Actor>
</VisualActor>

View File

@ -10,9 +10,6 @@
<History>Need History</History>
<Icon>units/hele_ship_merchant.png</Icon>
</Identity>
<Obstruction>
<Unit radius="6.0"/>
</Obstruction>
<VisualActor>
<Actor>structures/hellenes/merchant_new.xml</Actor>
</VisualActor>

View File

@ -23,9 +23,6 @@
<SpecificName>Pyrobolos</SpecificName>
<Icon>units/hele_mechanical_siege_lithobolos.png</Icon>
</Identity>
<Obstruction>
<Unit radius="3.5"/>
</Obstruction>
<Vision>
<Range>60</Range>
</Vision>

View File

@ -23,7 +23,7 @@
#include "ps/CLogger.h"
#include "simulation2/MessageTypes.h"
#include "simulation2/components/ICmpObstructionManager.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpUnitMotion.h"
#include "simulation2/serialization/SerializeTemplates.h"
#define MAX(x,y) x>y ? x : y
@ -124,9 +124,7 @@ public:
"</attribute>"
"</element>"
"<element name='Unit'>"
"<attribute name='radius'>"
"<ref name='positiveDecimal'/>"
"</attribute>"
"<empty/>"
"</element>"
"<element name='Obstructions'>"
"<zeroOrMore>"
@ -208,7 +206,10 @@ public:
if (paramNode.GetChild("Unit").IsOk())
{
m_Type = UNIT;
m_Size0 = m_Size1 = paramNode.GetChild("Unit").GetChild("@radius").ToFixed();
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetEntityHandle());
if (cmpUnitMotion)
m_Clearance = cmpUnitMotion->GetUnitClearance();
}
else if (paramNode.GetChild("Static").IsOk())
{
@ -280,6 +281,8 @@ public:
serialize.NumberU8_Unbounded("flags", m_Flags);
if (m_Type == CLUSTER)
SerializeVector<SerializeTag>()(serialize, "cluster tags", m_ClusterTags);
if (m_Type == UNIT)
serialize.NumberFixed_Unbounded("clearance", m_Clearance);
}
virtual void Serialize(ISerializer& serialize)
@ -316,7 +319,7 @@ public:
{
cmpObstructionManager->MoveShape(m_Tag, data.x, data.z, data.a);
if(m_Type == CLUSTER)
if (m_Type == CLUSTER)
{
for (size_t i = 0; i < m_Shapes.size(); ++i)
{
@ -335,7 +338,7 @@ public:
data.x, data.z, data.a, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2);
else if (m_Type == UNIT)
m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(),
data.x, data.z, m_Size0, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
data.x, data.z, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
else
AddClusterShapes(data.x, data.x, data.a);
}
@ -392,7 +395,7 @@ public:
pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2);
else if (m_Type == UNIT)
m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(),
pos.X, pos.Y, m_Size0, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
pos.X, pos.Y, m_Clearance, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
else
AddClusterShapes(pos.X, pos.Y, cmpPosition->GetRotation().Y);
}
@ -487,7 +490,7 @@ public:
else
pos = cmpPosition->GetPosition2D();
if (m_Type == UNIT)
out = cmpObstructionManager->GetUnitShapeObstruction(pos.X, pos.Y, m_Size0);
out = cmpObstructionManager->GetUnitShapeObstruction(pos.X, pos.Y, m_Clearance);
else
out = cmpObstructionManager->GetStaticShapeObstruction(pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1);
return true;
@ -496,7 +499,7 @@ public:
virtual entity_pos_t GetUnitRadius()
{
if (m_Type == UNIT)
return m_Size0;
return m_Clearance;
else
return entity_pos_t::Zero();
}
@ -504,7 +507,7 @@ public:
virtual entity_pos_t GetSize()
{
if (m_Type == UNIT)
return m_Size0;
return m_Clearance;
else
return CFixedVector2D(m_Size0 / 2, m_Size1 / 2).Length();
}
@ -557,7 +560,7 @@ public:
ICmpObstructionManager::FLAG_BLOCK_FOUNDATION);
if (m_Type == UNIT)
return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass, onlyCenterPoint);
return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Clearance, passClass, onlyCenterPoint);
else
return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass, onlyCenterPoint);
}
@ -589,7 +592,7 @@ public:
ICmpObstructionManager::FLAG_BLOCK_FOUNDATION);
if (m_Type == UNIT)
return !cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Size0, NULL);
return !cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Clearance, NULL);
else
return !cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL );
}

View File

@ -47,13 +47,12 @@
#define TAG_TO_INDEX(tag) ((tag).n >> 1)
/**
* Internal representation of axis-aligned sometimes-square sometimes-circle shapes for moving units
* Internal representation of axis-aligned circular shapes for moving units
*/
struct UnitShape
{
entity_id_t entity;
entity_pos_t x, z;
entity_pos_t r; // radius of circle, or half width of square
entity_pos_t clearance;
ICmpObstructionManager::flags_t flags;
entity_id_t group; // control group (typically the owner entity, or a formation controller entity) (units ignore collisions with others in the same group)
@ -84,7 +83,6 @@ struct SerializeUnitShape
serialize.NumberU32_Unbounded("entity", value.entity);
serialize.NumberFixed_Unbounded("x", value.x);
serialize.NumberFixed_Unbounded("z", value.z);
serialize.NumberFixed_Unbounded("r", value.r);
serialize.NumberFixed_Unbounded("clearance", value.clearance);
serialize.NumberU8_Unbounded("flags", value.flags);
serialize.NumberU32_Unbounded("group", value.group);
@ -262,7 +260,7 @@ public:
for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it)
{
CFixedVector2D center(it->second.x, it->second.z);
CFixedVector2D halfSize(it->second.r, it->second.r);
CFixedVector2D halfSize(it->second.clearance, it->second.clearance);
m_UnitSubdivision.Add(it->first, center - halfSize, center + halfSize);
}
@ -274,13 +272,13 @@ public:
}
}
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t r, entity_pos_t clearance, flags_t flags, entity_id_t group)
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance, flags_t flags, entity_id_t group)
{
UnitShape shape = { ent, x, z, r, clearance, flags, group };
UnitShape shape = { ent, x, z, clearance, flags, group };
u32 id = m_UnitShapeNext++;
m_UnitShapes[id] = shape;
m_UnitSubdivision.Add(id, CFixedVector2D(x - r, z - r), CFixedVector2D(x + r, z + r));
m_UnitSubdivision.Add(id, CFixedVector2D(x - clearance, z - clearance), CFixedVector2D(x + clearance, z + clearance));
MakeDirtyUnit(flags, id, shape);
@ -307,11 +305,11 @@ public:
return STATIC_INDEX_TO_TAG(id);
}
virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t r)
virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance)
{
CFixedVector2D u(entity_pos_t::FromInt(1), entity_pos_t::Zero());
CFixedVector2D v(entity_pos_t::Zero(), entity_pos_t::FromInt(1));
ObstructionSquare o = { x, z, u, v, r, r };
ObstructionSquare o = { x, z, u, v, clearance, clearance };
return o;
}
@ -337,10 +335,10 @@ public:
MakeDirtyUnit(shape.flags, TAG_TO_INDEX(tag), shape); // dirty the old shape region
m_UnitSubdivision.Move(TAG_TO_INDEX(tag),
CFixedVector2D(shape.x - shape.r, shape.z - shape.r),
CFixedVector2D(shape.x + shape.r, shape.z + shape.r),
CFixedVector2D(x - shape.r, z - shape.r),
CFixedVector2D(x + shape.r, z + shape.r));
CFixedVector2D(shape.x - shape.clearance, shape.z - shape.clearance),
CFixedVector2D(shape.x + shape.clearance, shape.z + shape.clearance),
CFixedVector2D(x - shape.clearance, z - shape.clearance),
CFixedVector2D(x + shape.clearance, z + shape.clearance));
shape.x = x;
shape.z = z;
@ -422,8 +420,8 @@ public:
{
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)];
m_UnitSubdivision.Remove(TAG_TO_INDEX(tag),
CFixedVector2D(shape.x - shape.r, shape.z - shape.r),
CFixedVector2D(shape.x + shape.r, shape.z + shape.r));
CFixedVector2D(shape.x - shape.clearance, shape.z - shape.clearance),
CFixedVector2D(shape.x + shape.clearance, shape.z + shape.clearance));
MakeDirtyUnit(shape.flags, TAG_TO_INDEX(tag), shape);
@ -452,7 +450,7 @@ public:
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)];
CFixedVector2D u(entity_pos_t::FromInt(1), entity_pos_t::Zero());
CFixedVector2D v(entity_pos_t::Zero(), entity_pos_t::FromInt(1));
ObstructionSquare o = { shape.x, shape.z, u, v, shape.r, shape.r };
ObstructionSquare o = { shape.x, shape.z, u, v, shape.clearance, shape.clearance };
return o;
}
else
@ -618,18 +616,18 @@ private:
CFixedVector2D center(shape.x, shape.z);
std::vector<u32> staticsNear;
m_StaticSubdivision.GetNear(staticsNear, center, shape.r + m_MaxClearance*2);
m_StaticSubdivision.GetNear(staticsNear, center, shape.clearance + m_MaxClearance*2);
for (u32& staticId : staticsNear)
if (std::find(m_DirtyStaticShapes.begin(), m_DirtyStaticShapes.end(), staticId) == m_DirtyStaticShapes.end())
m_DirtyStaticShapes.push_back(staticId);
std::vector<u32> unitsNear;
m_UnitSubdivision.GetNear(staticsNear, center, shape.r + m_MaxClearance*2);
m_UnitSubdivision.GetNear(staticsNear, center, shape.clearance + m_MaxClearance*2);
for (u32& unitId : unitsNear)
if (std::find(m_DirtyUnitShapes.begin(), m_DirtyUnitShapes.end(), unitId) == m_DirtyUnitShapes.end())
m_DirtyUnitShapes.push_back(unitId);
MarkDirtinessGrid(shape.x, shape.z, shape.r + m_MaxClearance);
MarkDirtinessGrid(shape.x, shape.z, shape.clearance + m_MaxClearance);
}
}
@ -676,7 +674,7 @@ bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti
continue;
CFixedVector2D center(it->second.x, it->second.z);
CFixedVector2D halfSize(it->second.r + r, it->second.r + r);
CFixedVector2D halfSize(it->second.clearance + r, it->second.clearance + r);
if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize))
return true;
}
@ -737,7 +735,7 @@ bool CCmpObstructionManager::TestStaticShape(const IObstructionTestFilter& filte
CFixedVector2D center1(it->second.x, it->second.z);
if (Geometry::PointIsInSquare(center1 - center, u, v, CFixedVector2D(halfSize.X + it->second.r, halfSize.Y + it->second.r)))
if (Geometry::PointIsInSquare(center1 - center, u, v, CFixedVector2D(halfSize.X + it->second.clearance, halfSize.Y + it->second.clearance)))
{
if (out)
out->push_back(it->second.entity);
@ -769,7 +767,7 @@ bool CCmpObstructionManager::TestStaticShape(const IObstructionTestFilter& filte
}
bool CCmpObstructionManager::TestUnitShape(const IObstructionTestFilter& filter,
entity_pos_t x, entity_pos_t z, entity_pos_t r,
entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
std::vector<entity_id_t>* out)
{
PROFILE("TestUnitShape");
@ -777,7 +775,7 @@ bool CCmpObstructionManager::TestUnitShape(const IObstructionTestFilter& filter,
// TODO: should use the subdivision stuff here, if performance is non-negligible
// Check that the shape is within the world
if (!IsInWorld(x, z, r))
if (!IsInWorld(x, z, clearance))
{
if (out)
out->push_back(INVALID_ENTITY); // no entity ID, so just push an arbitrary marker
@ -792,9 +790,13 @@ bool CCmpObstructionManager::TestUnitShape(const IObstructionTestFilter& filter,
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
continue;
entity_pos_t r1 = it->second.r;
entity_pos_t c1 = it->second.clearance;
if (!(it->second.x + r1 < x - r || it->second.x - r1 > x + r || it->second.z + r1 < z - r || it->second.z - r1 > z + r))
if (!(
it->second.x + c1 < x - clearance ||
it->second.x - c1 > x + clearance ||
it->second.z + c1 < z - clearance ||
it->second.z - c1 > z + clearance))
{
if (out)
out->push_back(it->second.entity);
@ -809,13 +811,12 @@ bool CCmpObstructionManager::TestUnitShape(const IObstructionTestFilter& filter,
continue;
CFixedVector2D center1(it->second.x, it->second.z);
if (Geometry::PointIsInSquare(center1 - center, it->second.u, it->second.v, CFixedVector2D(it->second.hw + r, it->second.hh + r)))
if (Geometry::PointIsInSquare(center1 - center, it->second.u, it->second.v, CFixedVector2D(it->second.hw + clearance, it->second.hh + clearance)))
{
if (out)
out->push_back(it->second.entity);
else
return true;
}
}
@ -908,7 +909,7 @@ void CCmpObstructionManager::RasterizeHelper(Grid<u16>& grid, ICmpObstructionMan
if (!(pair.second.flags & requireMask))
continue;
entity_pos_t r = pair.second.r + clearance;
entity_pos_t r = pair.second.clearance + clearance;
u16 i0, j0, i1, j1;
Pathfinding::NearestNavcell(center.X - r, center.Y - r, i0, j0, grid.m_W, grid.m_H);
@ -935,15 +936,15 @@ void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY))
continue;
entity_pos_t r = it->second.r;
entity_pos_t c = it->second.clearance;
// Skip this object if it's completely outside the requested range
if (it->second.x + r < x0 || it->second.x - r > x1 || it->second.z + r < z0 || it->second.z - r > z1)
if (it->second.x + c < x0 || it->second.x - c > x1 || it->second.z + c < z0 || it->second.z - c > z1)
continue;
CFixedVector2D u(entity_pos_t::FromInt(1), entity_pos_t::Zero());
CFixedVector2D v(entity_pos_t::Zero(), entity_pos_t::FromInt(1));
squares.emplace_back(ObstructionSquare{ it->second.x, it->second.z, u, v, r, r });
squares.emplace_back(ObstructionSquare{ it->second.x, it->second.z, u, v, c, c });
}
std::vector<entity_id_t> staticShapes;
@ -1015,8 +1016,6 @@ void CCmpObstructionManager::GetUnitsOnObstruction(const ObstructionSquare& squa
out.push_back(shape.entity);
}
}
// TODO : Should we expand by r here?
}
void CCmpObstructionManager::RenderSubmit(SceneCollector& collector)
@ -1044,7 +1043,7 @@ void CCmpObstructionManager::RenderSubmit(SceneCollector& collector)
{
m_DebugOverlayLines.push_back(SOverlayLine());
m_DebugOverlayLines.back().m_Color = ((it->second.flags & FLAG_MOVING) ? movingColor : defaultColor);
SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.r.ToFloat()*2, it->second.r.ToFloat()*2, 0, m_DebugOverlayLines.back(), true);
SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.clearance.ToFloat()*2, it->second.clearance.ToFloat()*2, 0, m_DebugOverlayLines.back(), true);
}
for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it)

View File

@ -131,7 +131,7 @@ struct SerializeShortRequest
serialize.NumberU32_Unbounded("ticket", value.ticket);
serialize.NumberFixed_Unbounded("x0", value.x0);
serialize.NumberFixed_Unbounded("z0", value.z0);
serialize.NumberFixed_Unbounded("r", value.r);
serialize.NumberFixed_Unbounded("clearance", value.clearance);
serialize.NumberFixed_Unbounded("range", value.range);
SerializeGoal()(serialize, "goal", value.goal);
serialize.NumberU16_Unbounded("pass class", value.passClass);
@ -681,9 +681,9 @@ u32 CCmpPathfinder::ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const Pat
return req.ticket;
}
u32 CCmpPathfinder::ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify)
u32 CCmpPathfinder::ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify)
{
AsyncShortPathRequest req = { m_NextAsyncTicket++, x0, z0, r, range, goal, passClass, avoidMovingUnits, group, notify };
AsyncShortPathRequest req = { m_NextAsyncTicket++, x0, z0, clearance, range, goal, passClass, avoidMovingUnits, group, notify };
m_AsyncShortPathRequests.push_back(req);
return req.ticket;
}
@ -725,7 +725,7 @@ void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathReques
const AsyncShortPathRequest& req = shortRequests[i];
WaypointPath path;
ControlGroupMovementObstructionFilter filter(req.avoidMovingUnits, req.group);
ComputeShortPath(filter, req.x0, req.z0, req.r, req.range, req.goal, req.passClass, path);
ComputeShortPath(filter, req.x0, req.z0, req.clearance, req.range, req.goal, req.passClass, path);
CMessagePathResult msg(req.ticket, path);
GetSimContext().GetComponentManager().PostMessage(req.notify, msg);
}

View File

@ -64,7 +64,7 @@ struct AsyncShortPathRequest
u32 ticket;
entity_pos_t x0;
entity_pos_t z0;
entity_pos_t r;
entity_pos_t clearance;
entity_pos_t range;
PathGoal goal;
pass_class_t passClass;
@ -184,9 +184,9 @@ public:
virtual u32 ComputePathAsync(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass, entity_id_t notify);
virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret);
virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret);
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify);
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t controller, entity_id_t notify);
virtual void SetDebugPath(entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass)
{

View File

@ -557,7 +557,7 @@ struct SquareSort
};
void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
entity_pos_t x0, entity_pos_t z0, entity_pos_t r,
entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance,
entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& path)
{
PROFILE3("ComputeShortPath");
@ -634,15 +634,15 @@ void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
u16 i0, j0, i1, j1;
Pathfinding::NearestNavcell(rangeXMin, rangeZMin, i0, j0, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE);
Pathfinding::NearestNavcell(rangeXMax, rangeZMax, i1, j1, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE);
AddTerrainEdges(edges, vertexes, i0, j0, i1, j1, passClass, *m_Grid);
AddTerrainEdges(edges, vertexes, i0, j0, i1, j1, passClass, *m_TerrainOnlyGrid);
}
// Find all the obstruction squares that might affect us
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
std::vector<ICmpObstructionManager::ObstructionSquare> squares;
cmpObstructionManager->GetObstructionsInRange(filter, rangeXMin - r, rangeZMin - r, rangeXMax + r, rangeZMax + r, squares);
cmpObstructionManager->GetObstructionsInRange(filter, rangeXMin - clearance, rangeZMin - clearance, rangeXMax + clearance, rangeZMax + clearance, squares);
// Resize arrays to reduce reallocations
// Change array capacities to reduce reallocations
vertexes.reserve(vertexes.size() + squares.size()*4);
edgeSquares.reserve(edgeSquares.size() + squares.size()); // (assume most squares are AA)
@ -656,8 +656,8 @@ void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
// Expand the vertexes by the moving unit's collision radius, to find the
// closest we can get to it
CFixedVector2D hd0(squares[i].hw + r + EDGE_EXPAND_DELTA, squares[i].hh + r + EDGE_EXPAND_DELTA);
CFixedVector2D hd1(squares[i].hw + r + EDGE_EXPAND_DELTA, -(squares[i].hh + r + EDGE_EXPAND_DELTA));
CFixedVector2D hd0(squares[i].hw + clearance + EDGE_EXPAND_DELTA, squares[i].hh + clearance + EDGE_EXPAND_DELTA);
CFixedVector2D hd1(squares[i].hw + clearance + EDGE_EXPAND_DELTA, -(squares[i].hh + clearance + EDGE_EXPAND_DELTA));
// Check whether this is an axis-aligned square
bool aa = (u.X == fixed::FromInt(1) && u.Y == fixed::Zero() && v.X == fixed::Zero() && v.Y == fixed::FromInt(1));
@ -673,8 +673,8 @@ void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,
// Add the edges:
CFixedVector2D h0(squares[i].hw + r, squares[i].hh + r);
CFixedVector2D h1(squares[i].hw + r, -(squares[i].hh + r));
CFixedVector2D h0(squares[i].hw + clearance, squares[i].hh + clearance);
CFixedVector2D h1(squares[i].hw + clearance, -(squares[i].hh + clearance));
CFixedVector2D ev0(center.X - h0.Dot(u), center.Y + h0.Dot(v));
CFixedVector2D ev1(center.X - h1.Dot(u), center.Y + h1.Dot(v));

View File

@ -164,7 +164,7 @@ public:
// Dynamic state:
entity_pos_t m_Radius;
entity_pos_t m_Clearance;
bool m_Moving;
bool m_FacePointAfterMove;
@ -320,17 +320,16 @@ public:
else
m_RunSpeed = m_OriginalRunSpeed = m_WalkSpeed;
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
m_Radius = cmpObstruction->GetUnitRadius();
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
{
m_PassClassName = paramNode.GetChild("PassabilityClass").ToUTF8();
m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName);
m_Clearance = cmpPathfinder->GetClearance(m_PassClass);
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
cmpObstruction->SetUnitClearance(cmpPathfinder->GetClearance(m_PassClass));
cmpObstruction->SetUnitClearance(m_Clearance);
}
m_State = STATE_IDLE;
@ -352,8 +351,6 @@ public:
template<typename S>
void SerializeCommon(S& serialize)
{
serialize.NumberFixed_Unbounded("radius", m_Radius);
serialize.NumberU8("state", m_State, 0, STATE_MAX-1);
serialize.NumberU8("path state", m_PathState, 0, PATHSTATE_MAX-1);
@ -540,9 +537,9 @@ public:
m_ShortPath.m_Waypoints.clear();
}
virtual void SetUnitRadius(fixed radius)
virtual entity_pos_t GetUnitClearance()
{
m_Radius = radius;
return m_Clearance;
}
private:
@ -926,7 +923,7 @@ void CCmpUnitMotion::Move(fixed dt)
fixed offsetLength = offset.Length();
if (offsetLength <= maxdist)
{
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Radius, m_PassClass))
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Clearance, m_PassClass))
{
pos = target;
@ -956,7 +953,7 @@ void CCmpUnitMotion::Move(fixed dt)
offset.Normalize(maxdist);
target = pos + offset;
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Radius, m_PassClass))
if (cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, target.X, target.Y, m_Clearance, m_PassClass))
{
pos = target;
break;
@ -1076,7 +1073,7 @@ void CCmpUnitMotion::PlanNextStep(const CFixedVector2D& pos)
// The next step was obstructed the last time we checked; also check that
// the step is still obstructed (maybe the units in our way moved in the meantime)
if (!m_Planning.nextStepClean &&
!cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, nextPoint.x, nextPoint.z, m_Radius, m_PassClass))
!cmpPathfinder->CheckMovement(GetObstructionFilter(), pos.X, pos.Y, nextPoint.x, nextPoint.z, m_Clearance, m_PassClass))
{
// If the short path computation is over, use it, else just forget about it
if (!m_Planning.nextStepShortPath.m_Waypoints.empty())
@ -1093,12 +1090,12 @@ void CCmpUnitMotion::PlanNextStep(const CFixedVector2D& pos)
const Waypoint& followingPoint = m_LongPath.m_Waypoints.rbegin()[1]; // penultimate element
m_Planning.nextStepClean = cmpPathfinder->CheckMovement(
GetObstructionFilter(), nextPoint.x, nextPoint.z, followingPoint.x, followingPoint.z, m_Radius, m_PassClass);
GetObstructionFilter(), nextPoint.x, nextPoint.z, followingPoint.x, followingPoint.z, m_Clearance, m_PassClass);
if (!m_Planning.nextStepClean)
{
PathGoal goal = { PathGoal::POINT, followingPoint.x, followingPoint.z };
m_Planning.expectedPathTicket = cmpPathfinder->ComputeShortPathAsync(
nextPoint.x, nextPoint.z, m_Radius, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, false, m_TargetEntity, GetEntityId());
nextPoint.x, nextPoint.z, m_Clearance, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, false, m_TargetEntity, GetEntityId());
}
}
@ -1142,7 +1139,7 @@ bool CCmpUnitMotion::TryGoingStraightToGoalPoint(const CFixedVector2D& from)
return false;
// Check if there's any collisions on that route
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Radius, m_PassClass))
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
return false;
// That route is okay, so update our path
@ -1178,7 +1175,7 @@ bool CCmpUnitMotion::TryGoingStraightToTargetEntity(const CFixedVector2D& from)
CFixedVector2D goalPos = goal.NearestPointOnGoal(from);
// Check if there's any collisions on that route
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Radius, m_PassClass))
if (!cmpPathfinder->CheckMovement(GetObstructionFilter(), from.X, from.Y, goalPos.X, goalPos.Y, m_Clearance, m_PassClass))
return false;
// That route is okay, so update our path
@ -1378,7 +1375,7 @@ void CCmpUnitMotion::RequestShortPath(const CFixedVector2D &from, const PathGoal
if (!cmpPathfinder)
return;
m_ExpectedPathTicket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Radius, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, avoidMovingUnits, m_TargetEntity, GetEntityId());
m_ExpectedPathTicket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, SHORT_PATH_SEARCH_RANGE, goal, m_PassClass, avoidMovingUnits, m_TargetEntity, GetEntityId());
}
bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
@ -1587,7 +1584,7 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
goal.type = PathGoal::SQUARE;
goal.u = obstruction.u;
goal.v = obstruction.v;
entity_pos_t delta = std::max(goalDistance, m_Radius + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself
entity_pos_t delta = std::max(goalDistance, m_Clearance + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself
goal.hw = obstruction.hw + delta;
goal.hh = obstruction.hh + delta;
}
@ -1636,7 +1633,7 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
goal.type = PathGoal::SQUARE;
goal.u = obstruction.u;
goal.v = obstruction.v;
entity_pos_t delta = std::max(goalDistance, m_Radius + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself
entity_pos_t delta = std::max(goalDistance, m_Clearance + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself
goal.hw = obstruction.hw + delta;
goal.hh = obstruction.hh + delta;
}

View File

@ -112,15 +112,14 @@ public:
*
* @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
* @param x,z coordinates of center, in world space
* @param r radius of circle or half the unit's width/height
* @param clearance pathfinding clearance of the unit
* @param clearance pathfinding clearance of the unit (works as a radius)
* @param flags a set of EFlags values
* @param group control group (typically the owner entity, or a formation controller entity
* - units ignore collisions with others in the same group)
* @return a valid tag for manipulating the shape
* @see UnitShape
*/
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t r, entity_pos_t clearance,
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
flags_t flags, entity_id_t group) = 0;
/**
@ -195,13 +194,13 @@ public:
* @param filter filter to restrict the shapes that are being tested against
* @param x X coordinate of shape's center
* @param z Z coordinate of shape's center
* @param r radius of the shape (half the unit's width/height)
* @param clearance clearance of the shape's unit
* @param out if non-NULL, all colliding shapes' entities will be added to this list
*
* @return true if there is a collision
*/
virtual bool TestUnitShape(const IObstructionTestFilter& filter,
entity_pos_t x, entity_pos_t z, entity_pos_t r,
entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
std::vector<entity_id_t>* out) = 0;
/**
@ -261,7 +260,7 @@ public:
*/
virtual ObstructionSquare GetObstruction(tag_t tag) = 0;
virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t r) = 0;
virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance) = 0;
virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) = 0;

View File

@ -111,10 +111,10 @@ public:
/**
* Compute a precise path from the given point to the goal, and return the set of waypoints.
* The path is based on the full set of obstructions that pass the filter, such that
* a unit of radius 'r' will be able to follow the path with no collisions.
* a unit of clearance 'clearance' will be able to follow the path with no collisions.
* The path is restricted to a box of radius 'range' from the starting point.
*/
virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) = 0;
virtual void ComputeShortPath(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, WaypointPath& ret) = 0;
/**
* Asynchronous version of ComputeShortPath (using ControlGroupObstructionFilter).
@ -122,7 +122,7 @@ public:
* Returns a unique non-zero number, which will match the 'ticket' in the result,
* so callers can recognise each individual request they make.
*/
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t r, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify) = 0;
virtual u32 ComputeShortPathAsync(entity_pos_t x0, entity_pos_t z0, entity_pos_t clearance, entity_pos_t range, const PathGoal& goal, pass_class_t passClass, bool avoidMovingUnits, entity_id_t group, entity_id_t notify) = 0;
/**
* Check whether the given movement line is valid and doesn't hit any obstructions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -37,8 +37,8 @@ DEFINE_INTERFACE_METHOD_0("GetWalkSpeed", fixed, ICmpUnitMotion, GetWalkSpeed)
DEFINE_INTERFACE_METHOD_0("GetRunSpeed", fixed, ICmpUnitMotion, GetRunSpeed)
DEFINE_INTERFACE_METHOD_0("GetPassabilityClassName", std::string, ICmpUnitMotion, GetPassabilityClassName)
DEFINE_INTERFACE_METHOD_1("SetPassabilityClassName", void, ICmpUnitMotion, SetPassabilityClassName, std::string)
DEFINE_INTERFACE_METHOD_0("GetUnitClearance", entity_pos_t, ICmpUnitMotion, GetUnitClearance)
DEFINE_INTERFACE_METHOD_1("SetFacePointAfterMove", void, ICmpUnitMotion, SetFacePointAfterMove, bool)
DEFINE_INTERFACE_METHOD_1("SetUnitRadius", void, ICmpUnitMotion, SetUnitRadius, fixed)
DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpUnitMotion, SetDebugOverlay, bool)
END_INTERFACE_WRAPPER(UnitMotion)
@ -127,9 +127,9 @@ public:
m_Script.CallVoid("SetPassabilityClassName", passClassName);
}
virtual void SetUnitRadius(fixed radius)
virtual entity_pos_t GetUnitClearance()
{
m_Script.CallVoid("SetUnitRadius", radius);
return m_Script.Call<entity_pos_t>("GetUnitClearance");
}
virtual void SetDebugOverlay(bool enabled)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2012 Wildfire Games.
/* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -132,11 +132,9 @@ public:
virtual void SetPassabilityClassName(std::string passClassName) = 0;
/**
* Override the default obstruction radius, used for planning paths and checking for collisions.
* Bad things may happen if this entity has an active Obstruction component with a larger
* radius. (This is intended primarily for formation controllers.)
* Get the unit clearance (used by the Obstruction component)
*/
virtual void SetUnitRadius(fixed radius) = 0;
virtual entity_pos_t GetUnitClearance() = 0;
/**
* Toggle the rendering of debug info.

View File

@ -28,8 +28,8 @@ class TestCmpObstructionManager : public CxxTest::TestSuite
entity_id_t ent1, ent2, ent3; // entity IDs
entity_angle_t ent1a; // angles
entity_pos_t ent1x, ent1z, ent1w, ent1h, // positions/dimensions
ent2x, ent2z, ent2r, ent2c,
ent3x, ent3z, ent3r, ent3c;
ent2x, ent2z, ent2c,
ent3x, ent3z, ent3c;
entity_id_t ent1g1, ent1g2, ent2g, ent3g; // control groups
tag_t shape1, shape2, shape3;
@ -57,17 +57,15 @@ public:
ent1g2 = INVALID_ENTITY;
ent2 = 2;
ent2r = fixed::FromFloat(1);
ent2c = fixed::Zero();
ent2c = fixed::FromFloat(1);
ent2x = ent1x;
ent2z = ent1z;
ent2g = ent1g1;
ent3 = 3;
ent3r = fixed::FromFloat(3);
ent3c = fixed::Zero();
ent3c = fixed::FromFloat(3);
ent3x = ent2x;
ent3z = ent2z + ent2r + ent3r; // ensure it just touches the border of ent2
ent3z = ent2z + ent2c + ent3c; // ensure it just touches the border of ent2
ent3g = ent3;
testHelper = new ComponentTestHelper(g_ScriptRuntime);
@ -79,11 +77,11 @@ public:
ICmpObstructionManager::FLAG_BLOCK_MOVEMENT |
ICmpObstructionManager::FLAG_MOVING, ent1g1, ent1g2);
shape2 = cmp->AddUnitShape(ent2, ent2x, ent2z, ent2r, ent2c,
shape2 = cmp->AddUnitShape(ent2, ent2x, ent2z, ent2c,
ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION |
ICmpObstructionManager::FLAG_BLOCK_FOUNDATION, ent2g);
shape3 = cmp->AddUnitShape(ent3, ent3x, ent3z, ent3r, ent3c,
shape3 = cmp->AddUnitShape(ent3, ent3x, ent3z, ent3c,
ICmpObstructionManager::FLAG_BLOCK_MOVEMENT |
ICmpObstructionManager::FLAG_BLOCK_FOUNDATION, ent3g);
}
@ -121,13 +119,13 @@ public:
// Similarly, collision-test a simple shape nested inside both shape1 and shape2. Since the tested shape overlaps
// only with shapes 1 and 2, those are the only ones we should find in the result.
cmp->TestUnitShape(nullFilter, ent2x, ent2z, ent2r/2, &out);
cmp->TestUnitShape(nullFilter, ent2x, ent2z, ent2c/2, &out);
TS_ASSERT_EQUALS(2U, out.size());
TS_ASSERT_VECTOR_CONTAINS(out, ent1);
TS_ASSERT_VECTOR_CONTAINS(out, ent2);
out.clear();
cmp->TestStaticShape(nullFilter, ent2x, ent2z, fixed::Zero(), ent2r, ent2r, &out);
cmp->TestStaticShape(nullFilter, ent2x, ent2z, fixed::Zero(), ent2c, ent2c, &out);
TS_ASSERT_EQUALS(2U, out.size());
TS_ASSERT_VECTOR_CONTAINS(out, ent1);
TS_ASSERT_VECTOR_CONTAINS(out, ent2);
@ -202,12 +200,12 @@ public:
SkipTagObstructionFilter ignoreShape2(shape2);
cmp->TestUnitShape(ignoreShape2, ent2x, ent2z, ent2r/2, &out);
cmp->TestUnitShape(ignoreShape2, ent2x, ent2z, ent2c/2, &out);
TS_ASSERT_EQUALS(1U, out.size());
TS_ASSERT_EQUALS(ent1, out[0]);
out.clear();
cmp->TestStaticShape(ignoreShape2, ent2x, ent2z, fixed::Zero(), ent2r, ent2r, &out);
cmp->TestStaticShape(ignoreShape2, ent2x, ent2z, fixed::Zero(), ent2c, ent2c, &out);
TS_ASSERT_EQUALS(1U, out.size());
TS_ASSERT_EQUALS(ent1, out[0]);
out.clear();
@ -422,7 +420,7 @@ public:
entity_angle_t ent4a = fixed::FromDouble(M_PI); // rotated 180 degrees, should not affect collision test
entity_pos_t ent4w = fixed::FromInt(2),
ent4h = fixed::FromInt(1),
ent4x = ent3x + ent3r + ent4w/2, // make ent4 adjacent to ent3
ent4x = ent3x + ent3c + ent4w/2, // make ent4 adjacent to ent3
ent4z = ent3z;
cmp->TestStaticShape(nullFilter, ent4x, ent4z, ent4a, ent4w, ent4h, &out);
@ -462,15 +460,15 @@ public:
TS_ASSERT_EQUALS(obSquare1.u, CFixedVector2D(fixed::FromInt(1), fixed::FromInt(0)));
TS_ASSERT_EQUALS(obSquare1.v, CFixedVector2D(fixed::FromInt(0), fixed::FromInt(1)));
TS_ASSERT_EQUALS(obSquare2.hh, ent2r);
TS_ASSERT_EQUALS(obSquare2.hw, ent2r);
TS_ASSERT_EQUALS(obSquare2.hh, ent2c);
TS_ASSERT_EQUALS(obSquare2.hw, ent2c);
TS_ASSERT_EQUALS(obSquare2.x, ent2x);
TS_ASSERT_EQUALS(obSquare2.z, ent2z);
TS_ASSERT_EQUALS(obSquare2.u, CFixedVector2D(fixed::FromInt(1), fixed::FromInt(0)));
TS_ASSERT_EQUALS(obSquare2.v, CFixedVector2D(fixed::FromInt(0), fixed::FromInt(1)));
TS_ASSERT_EQUALS(obSquare3.hh, ent3r);
TS_ASSERT_EQUALS(obSquare3.hw, ent3r);
TS_ASSERT_EQUALS(obSquare3.hh, ent3c);
TS_ASSERT_EQUALS(obSquare3.hw, ent3c);
TS_ASSERT_EQUALS(obSquare3.x, ent3x);
TS_ASSERT_EQUALS(obSquare3.z, ent3z);
TS_ASSERT_EQUALS(obSquare3.u, CFixedVector2D(fixed::FromInt(1), fixed::FromInt(0)));

View File

@ -130,7 +130,7 @@ public:
fixed x = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX);
fixed z = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX);
// printf("# %f %f\n", x.ToFloat(), z.ToFloat());
cmpObstructionMan->AddUnitShape(INVALID_ENTITY, x, z, fixed::FromInt(2), fixed::Zero(), 0, INVALID_ENTITY);
cmpObstructionMan->AddUnitShape(INVALID_ENTITY, x, z, fixed::FromInt(2), 0, INVALID_ENTITY);
}
NullObstructionFilter filter;