forked from 0ad/0ad
Implements entity terrain anchoring as a visual effect, based on patch by sanderd17, fixes #1988.
Sets cavalry and quadrupedal animals to 'pitch' anchoring. Cleans up mine templates. This was SVN commit r13565.
This commit is contained in:
parent
9a0ab14cf3
commit
f302faf8e4
@ -18,6 +18,9 @@
|
||||
<SpecificName>Bear</SpecificName>
|
||||
<Icon>gaia/fauna_bear.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/lion_select.xml</select>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Boar</SpecificName>
|
||||
<Icon>gaia/fauna_boar.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>150</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -12,6 +12,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="1.5"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/camel.xml</select>
|
||||
|
@ -5,6 +5,9 @@
|
||||
<SpecificName>Deer</SpecificName>
|
||||
<Icon>gaia/fauna_deer.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<UnitMotion>
|
||||
<WalkSpeed>2.0</WalkSpeed>
|
||||
<Run>
|
||||
|
@ -14,6 +14,9 @@
|
||||
<SpecificName>Elephant</SpecificName>
|
||||
<Icon>gaia/fauna_elephant.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/elephant_select.xml</select>
|
||||
|
@ -53,6 +53,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="3.5"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>800</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="1.5"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>100</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -53,6 +53,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="2.7"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>650</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -5,6 +5,9 @@
|
||||
<SpecificName>Gazelle</SpecificName>
|
||||
<Icon>gaia/fauna_gazelle.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<UnitMotion>
|
||||
<Run>
|
||||
<Range>600.0</Range>
|
||||
|
@ -16,6 +16,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="2.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>350</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -12,6 +12,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="1.5"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>150</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -11,6 +11,9 @@
|
||||
<SpecificName>Goat</SpecificName>
|
||||
<Icon>gaia/fauna_goat.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>120</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -12,6 +12,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="1.5"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>200</Amount>
|
||||
</ResourceSupply>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Lion</SpecificName>
|
||||
<Icon>gaia/fauna_lion.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/lion_select.xml</select>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Lion</SpecificName>
|
||||
<Icon>gaia/fauna_lion.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/lion_select.xml</select>
|
||||
|
@ -9,6 +9,9 @@
|
||||
<SpecificName>Muskox</SpecificName>
|
||||
<Icon>gaia/fauna_muskox.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>200</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -5,6 +5,9 @@
|
||||
<SpecificName>Pig</SpecificName>
|
||||
<Icon>gaia/fauna_pig.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<StatusBars>
|
||||
<HeightOffset>5.0</HeightOffset>
|
||||
</StatusBars>
|
||||
|
@ -9,6 +9,9 @@
|
||||
<SpecificName>Rabbit</SpecificName>
|
||||
<Icon>gaia/fauna_rabbit.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>50</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -12,6 +12,9 @@
|
||||
<Classes datatype="tokens">Domestic</Classes>
|
||||
<Icon>gaia/fauna_sheep.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/sheep.xml</select>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Tiger</SpecificName>
|
||||
<Icon>gaia/fauna_tiger.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Sound>
|
||||
<SoundGroups>
|
||||
<select>actor/fauna/animal/lion_select.xml</select>
|
||||
|
@ -23,6 +23,9 @@
|
||||
<SpecificName>Walrus</SpecificName>
|
||||
<Icon>gaia/fauna_walrus.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>300</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -10,6 +10,9 @@
|
||||
<History>The wildebeest (plural wildebeest, wildebeests or wildebai), also called the gnu, is an antelope of the genus Connochaetes. It is a hooved (ungulate) mammal. Wildebeest are well known for their annual migration to new pastures in which vast numbers of wildebeest can be seen crossing rivers, such as the Mara River and dying in large numbers as they attempt to reach the other side. Many of them are eaten by crocodiles while others simply drown. Herds of wildebeest possesses what is known as "swarm intelligence", whereby the animals systematically explore and overcome obstacles as one when, for instance, crossing a river or defending against predator attacks.</History>
|
||||
<Icon>gaia/fauna_wildebeest.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>150</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Wolf</SpecificName>
|
||||
<Icon>gaia/fauna_wolf.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>fauna/wolf.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -18,6 +18,9 @@
|
||||
<SpecificName>Snow Wolf</SpecificName>
|
||||
<Icon>gaia/fauna_wolf_snow.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>fauna/wolf_snow.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -9,6 +9,9 @@
|
||||
<SpecificName>Zebra</SpecificName>
|
||||
<Icon>gaia/fauna_zebra.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>150</Amount>
|
||||
<Type>food.meat</Type>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_alpine.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_desert_small.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_granite_greek.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_mediterranean.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_granite_temperate.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_mineral">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/metalmine_tropic.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_rock">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_alpine_a.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -7,9 +7,6 @@
|
||||
<Identity>
|
||||
<Icon>gaia/geology_stone_2.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_desert_small.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_rock">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_granite_greek.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_rock">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_mediterranean.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -7,9 +7,6 @@
|
||||
<Identity>
|
||||
<Icon>gaia/geology_stone_2.png</Icon>
|
||||
</Identity>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_savanna_small.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_rock">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_granite.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -1,8 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Entity parent="template_gaia_geo_rock">
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<VisualActor>
|
||||
<Actor>geology/stonemine_tropic.xml</Actor>
|
||||
</VisualActor>
|
||||
|
@ -10,6 +10,9 @@
|
||||
<Obstruction>
|
||||
<Static width="7.0" depth="7.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<EditorOnly disable=""/>
|
||||
<Overlay>
|
||||
|
@ -7,9 +7,6 @@
|
||||
<Obstruction>
|
||||
<Static width="13.0" depth="13.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>5000</Amount>
|
||||
<MaxGatherers>24</MaxGatherers>
|
||||
|
@ -7,9 +7,6 @@
|
||||
<Obstruction>
|
||||
<Static width="13.0" depth="13.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch-roll</Anchor>
|
||||
</Position>
|
||||
<ResourceSupply>
|
||||
<Amount>5000</Amount>
|
||||
<MaxGatherers>24</MaxGatherers>
|
||||
|
@ -42,6 +42,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="1.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<Overlay>
|
||||
<Texture>
|
||||
|
@ -31,6 +31,9 @@
|
||||
<Obstruction>
|
||||
<Unit radius="4.0"/>
|
||||
</Obstruction>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<Selectable>
|
||||
<Overlay>
|
||||
<Texture>
|
||||
|
@ -38,6 +38,9 @@
|
||||
<stone>10</stone>
|
||||
<metal>10</metal>
|
||||
</Loot>
|
||||
<Position>
|
||||
<Anchor>pitch</Anchor>
|
||||
</Position>
|
||||
<ResourceDropsite>
|
||||
<Types>food wood stone metal</Types>
|
||||
</ResourceDropsite>
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "maths/MathUtil.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "maths/Vector2D.h"
|
||||
#include "ps/CLogger.h"
|
||||
|
||||
/**
|
||||
@ -58,6 +59,7 @@ public:
|
||||
UPRIGHT = 0,
|
||||
PITCH = 1,
|
||||
PITCH_ROLL = 2,
|
||||
ROLL=3,
|
||||
} m_AnchorType;
|
||||
|
||||
bool m_Floating;
|
||||
@ -73,7 +75,12 @@ public:
|
||||
bool m_RelativeToGround; // whether m_YOffset is relative to terrain/water plane, or an absolute height
|
||||
|
||||
entity_angle_t m_RotX, m_RotY, m_RotZ;
|
||||
float m_InterpolatedRotY; // not serialized
|
||||
|
||||
// not serialized:
|
||||
float m_InterpolatedRotX, m_InterpolatedRotY, m_InterpolatedRotZ;
|
||||
float m_LastInterpolatedRotX, m_LastInterpolatedRotZ; // not serialized
|
||||
|
||||
bool m_NeedInitialXZRotation;
|
||||
|
||||
static std::string GetSchema()
|
||||
{
|
||||
@ -87,9 +94,10 @@ public:
|
||||
"</a:example>"
|
||||
"<element name='Anchor' a:help='Automatic rotation to follow the slope of terrain'>"
|
||||
"<choice>"
|
||||
"<value a:help='Always stand straight up'>upright</value>"
|
||||
"<value a:help='Rotate backwards and forwards to follow the terrain'>pitch</value>"
|
||||
"<value a:help='Rotate in all direction to follow the terrain'>pitch-roll</value>"
|
||||
"<value a:help='Always stand straight up (e.g. humans)'>upright</value>"
|
||||
"<value a:help='Rotate backwards and forwards to follow the terrain (e.g. animals)'>pitch</value>"
|
||||
"<value a:help='Rotate sideways to follow the terrain'>roll</value>"
|
||||
"<value a:help='Rotate in all directions to follow the terrain (e.g. carts)'>pitch-roll</value>"
|
||||
"</choice>"
|
||||
"</element>"
|
||||
"<element name='Altitude' a:help='Height above terrain in metres'>"
|
||||
@ -110,6 +118,8 @@ public:
|
||||
m_AnchorType = PITCH;
|
||||
else if (anchor == L"pitch-roll")
|
||||
m_AnchorType = PITCH_ROLL;
|
||||
else if (anchor == L"roll")
|
||||
m_AnchorType = ROLL;
|
||||
else
|
||||
m_AnchorType = UPRIGHT;
|
||||
|
||||
@ -122,7 +132,10 @@ public:
|
||||
m_RotYSpeed = paramNode.GetChild("TurnRate").ToFixed().ToFloat();
|
||||
|
||||
m_RotX = m_RotY = m_RotZ = entity_angle_t::FromInt(0);
|
||||
m_InterpolatedRotY = 0;
|
||||
m_InterpolatedRotX = m_InterpolatedRotY = m_InterpolatedRotZ = 0.f;
|
||||
m_LastInterpolatedRotX = m_LastInterpolatedRotZ = 0.f;
|
||||
|
||||
m_NeedInitialXZRotation = false;
|
||||
}
|
||||
|
||||
virtual void Deinit()
|
||||
@ -138,8 +151,6 @@ public:
|
||||
serialize.NumberFixed_Unbounded("z", m_Z);
|
||||
serialize.NumberFixed_Unbounded("last x", m_LastX);
|
||||
serialize.NumberFixed_Unbounded("last z", m_LastZ);
|
||||
// TODO: for efficiency, we probably shouldn't actually store the last position - it doesn't
|
||||
// matter if we don't have smooth interpolation after reloading a game
|
||||
}
|
||||
serialize.NumberFixed_Unbounded("rot x", m_RotX);
|
||||
serialize.NumberFixed_Unbounded("rot y", m_RotY);
|
||||
@ -152,9 +163,22 @@ public:
|
||||
const char* anchor = "???";
|
||||
switch (m_AnchorType)
|
||||
{
|
||||
case UPRIGHT: anchor = "upright"; break;
|
||||
case PITCH: anchor = "pitch"; break;
|
||||
case PITCH_ROLL: anchor = "pitch-roll"; break;
|
||||
case PITCH:
|
||||
anchor = "pitch";
|
||||
break;
|
||||
|
||||
case PITCH_ROLL:
|
||||
anchor = "pitch-roll";
|
||||
break;
|
||||
|
||||
case ROLL:
|
||||
anchor = "roll";
|
||||
break;
|
||||
|
||||
case UPRIGHT: // upright is the default
|
||||
default:
|
||||
anchor = "upright";
|
||||
break;
|
||||
}
|
||||
serialize.StringASCII("anchor", anchor, 0, 16);
|
||||
serialize.Bool("floating", m_Floating);
|
||||
@ -181,6 +205,9 @@ public:
|
||||
// TODO: should there be range checks on all these values?
|
||||
|
||||
m_InterpolatedRotY = m_RotY.ToFloat();
|
||||
|
||||
if (m_InWorld)
|
||||
UpdateXZRotation();
|
||||
}
|
||||
|
||||
virtual bool IsInWorld()
|
||||
@ -216,6 +243,11 @@ public:
|
||||
m_LastZ = m_PrevZ = m_Z = z;
|
||||
m_InWorld = true;
|
||||
|
||||
UpdateXZRotation();
|
||||
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
|
||||
AdvertisePositionChanges();
|
||||
}
|
||||
|
||||
@ -329,6 +361,14 @@ public:
|
||||
m_RotY = y;
|
||||
m_InterpolatedRotY = m_RotY.ToFloat();
|
||||
|
||||
if (m_InWorld)
|
||||
{
|
||||
UpdateXZRotation();
|
||||
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
}
|
||||
|
||||
AdvertisePositionChanges();
|
||||
}
|
||||
|
||||
@ -337,6 +377,14 @@ public:
|
||||
m_RotX = x;
|
||||
m_RotZ = z;
|
||||
|
||||
if (m_InWorld)
|
||||
{
|
||||
UpdateXZRotation();
|
||||
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
}
|
||||
|
||||
AdvertisePositionChanges();
|
||||
}
|
||||
|
||||
@ -400,11 +448,13 @@ public:
|
||||
|
||||
float y = baseY + m_YOffset.ToFloat();
|
||||
|
||||
// TODO: do something with m_AnchorType
|
||||
|
||||
CMatrix3D m;
|
||||
m.SetXRotation(m_RotX.ToFloat());
|
||||
m.RotateZ(m_RotZ.ToFloat());
|
||||
CMatrix3D m;
|
||||
|
||||
// linear interpolation is good enough (for RotX/Z).
|
||||
// As you always stay close to zero angle.
|
||||
m.SetXRotation(Interpolate(m_LastInterpolatedRotX, m_InterpolatedRotX, frameOffset));
|
||||
m.RotateZ(Interpolate(m_LastInterpolatedRotZ, m_InterpolatedRotZ, frameOffset));
|
||||
|
||||
m.RotateY(rotY + (float)M_PI);
|
||||
m.Translate(CVector3D(x, y, z));
|
||||
|
||||
@ -420,32 +470,60 @@ public:
|
||||
const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
|
||||
|
||||
float rotY = m_RotY.ToFloat();
|
||||
float delta = rotY - m_InterpolatedRotY;
|
||||
// Wrap delta to -M_PI..M_PI
|
||||
delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI
|
||||
if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI
|
||||
delta -= (float)M_PI; // range -M_PI..M_PI
|
||||
// Clamp to max rate
|
||||
float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime);
|
||||
// Calculate new orientation, in a peculiar way in order to make sure the
|
||||
// result gets close to m_orientation (rather than being n*2*M_PI out)
|
||||
m_InterpolatedRotY = rotY + deltaClamped - delta;
|
||||
|
||||
if (rotY != m_InterpolatedRotY)
|
||||
{
|
||||
float delta = rotY - m_InterpolatedRotY;
|
||||
// Wrap delta to -M_PI..M_PI
|
||||
delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI
|
||||
if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI
|
||||
delta -= (float)M_PI; // range -M_PI..M_PI
|
||||
// Clamp to max rate
|
||||
float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime);
|
||||
// Calculate new orientation, in a peculiar way in order to make sure the
|
||||
// result gets close to m_orientation (rather than being n*2*M_PI out)
|
||||
m_InterpolatedRotY = rotY + deltaClamped - delta;
|
||||
|
||||
// update the visual XZ rotation
|
||||
if (m_InWorld)
|
||||
{
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
|
||||
UpdateXZRotation();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_InWorld && m_NeedInitialXZRotation)
|
||||
{
|
||||
// the terrain probably wasn't loaded last time we tried, so update the XZ rotation without interpolation
|
||||
UpdateXZRotation();
|
||||
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MT_TurnStart:
|
||||
{
|
||||
m_LastInterpolatedRotX = m_InterpolatedRotX;
|
||||
m_LastInterpolatedRotZ = m_InterpolatedRotZ;
|
||||
|
||||
if (m_InWorld && (m_LastX != m_X || m_LastZ != m_Z))
|
||||
UpdateXZRotation();
|
||||
|
||||
// Store the positions from the turn before
|
||||
m_PrevX = m_LastX;
|
||||
m_PrevZ = m_LastZ;
|
||||
|
||||
|
||||
m_LastX = m_X;
|
||||
m_LastZ = m_Z;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
void AdvertisePositionChanges()
|
||||
@ -461,6 +539,56 @@ private:
|
||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateXZRotation()
|
||||
{
|
||||
if (!m_InWorld)
|
||||
{
|
||||
LOGERROR(L"CCmpPosition::UpdateXZRotation called on entity when IsInWorld is false");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_RotZ.IsZero() || !m_RotX.IsZero())
|
||||
{
|
||||
// set the visual rotations to the ones fixed by the interface
|
||||
m_InterpolatedRotX = m_RotX.ToFloat();
|
||||
m_InterpolatedRotZ = m_RotZ.ToFloat();
|
||||
return;
|
||||
}
|
||||
|
||||
// change nothing if anchor is upright
|
||||
if (m_AnchorType == UPRIGHT)
|
||||
return;
|
||||
|
||||
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
|
||||
if (!cmpTerrain || !cmpTerrain->IsLoaded())
|
||||
{
|
||||
// try again when terrain is loaded
|
||||
m_NeedInitialXZRotation = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO average normal (average all the tiles?) for big units or for buildings
|
||||
CVector3D normal = cmpTerrain->CalcNormal(m_X, m_Z);
|
||||
|
||||
// rotate the normal so the positive x direction is in the direction of the unit
|
||||
CVector2D projected = CVector2D(normal.X, normal.Z);
|
||||
projected.Rotate(m_InterpolatedRotY);
|
||||
|
||||
normal.X = projected.X;
|
||||
normal.Z = projected.Y;
|
||||
|
||||
// project and calculate the angles
|
||||
if (m_AnchorType == PITCH || m_AnchorType == PITCH_ROLL)
|
||||
m_InterpolatedRotX = -atan2(normal.Z, normal.Y);
|
||||
|
||||
if (m_AnchorType == ROLL || m_AnchorType == PITCH_ROLL)
|
||||
m_InterpolatedRotZ = atan2(normal.X, normal.Y);
|
||||
|
||||
m_NeedInitialXZRotation = false;
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_TYPE(Position)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -44,8 +44,12 @@ class CMatrix3D;
|
||||
* - Terrain conformance mode, one of:
|
||||
* - Upright (upwards axis is always the world Y axis, e.g. for humans)
|
||||
* - Pitch (rotates backwards and forwards to match the terrain, e.g. for horses)
|
||||
* - PitchRoll (rotates in all directions to match the terrain, e.g. for carts)
|
||||
* - Pitch-Roll (rotates in all directions to match the terrain, e.g. for carts)
|
||||
* - Roll (rotates sideways to match the terrain)
|
||||
* NOTE: terrain conformance is currently only a local, visual effect; it doesn't change
|
||||
* the network synchronized rotation or the data returned by GetRotation
|
||||
* - Rotation around relative X (pitch), Z (roll) axes (rare; used for special effects)
|
||||
* NOTE: if XZ rotation is non-zero, it will override the terrain conformance mode
|
||||
*
|
||||
* Entities can also be 'outside the world' (e.g. hidden inside a building), in which
|
||||
* case they have no position. Callers <b>must</b> check the entity is in the world, before
|
||||
@ -137,6 +141,7 @@ public:
|
||||
* Rotate immediately to the given angles around the X (pitch) and Z (roll) axes.
|
||||
* @param x radians around the X axis. (TODO: in which direction?)
|
||||
* @param z radians around the Z axis.
|
||||
* @note if either x or z is non-zero, it will override terrain conformance mode
|
||||
*/
|
||||
virtual void SetXZRotation(entity_angle_t x, entity_angle_t z) = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user