# Add experimental fighter planes.

This was SVN commit r9605.
This commit is contained in:
Ykkrosh 2011-06-09 19:44:40 +00:00
parent 1357000401
commit 2c58b07223
19 changed files with 386 additions and 32 deletions

View File

@ -10,6 +10,7 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
<UnitAI/>
</Entity>

View File

@ -10,6 +10,7 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
<UnitAI/>
<Footprint>

BIN
binaries/data/mods/public/maps/scenarios/Flight_demo.pmp (Stored with Git LFS) Normal file

Binary file not shown.

BIN
binaries/data/mods/public/maps/scenarios/Flight_demo.xml (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1829,9 +1829,7 @@ UnitAI.prototype.FaceTowardsTarget = function(target)
{
var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
if (cmpUnitMotion)
{
cmpPosition.TurnTo(angle);
}
cmpUnitMotion.FaceTowardsPoint(pos.x, pos.z);
}
}

View File

@ -0,0 +1,196 @@
// (A serious implementation of this might want to use C++ instead of JS
// for performance; this is just for fun.)
function UnitMotionFlying() {}
UnitMotionFlying.prototype.Schema =
"<element name='MaxSpeed'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='AccelRate'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='TurnRate'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='OvershootTime'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='FlyingHeight'>" +
"<data type='decimal'/>" +
"</element>" +
"<element name='ClimbRate'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>";
UnitMotionFlying.prototype.Init = function()
{
this.hasTarget = false;
this.reachedTarget = false;
this.targetX = 0;
this.targetZ = 0;
this.targetMinRange = 0;
this.targetMaxRange = 0;
this.speed = 0;
};
UnitMotionFlying.prototype.OnUpdate = function(msg)
{
var turnLength = msg.turnLength;
if (!this.hasTarget)
return;
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
var pos = cmpPosition.GetPosition();
var angle = cmpPosition.GetRotation().y;
var canTurn = true;
// If we haven't reached max speed yet then we're still on the ground;
// otherwise we're taking off or flying
if (this.speed < this.template.MaxSpeed)
{
// Accelerate forwards
this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength*this.template.AccelRate);
canTurn = false;
// Clamp to ground if below it, or descend if above
var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
if (pos.y < ground)
pos.y = ground;
else if (pos.y > ground)
pos.y = Math.max(ground, pos.y - turnLength*this.template.ClimbRate);
cmpPosition.SetHeightFixed(pos.y);
}
else
{
// Climb/sink to max height above ground
var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
var targetHeight = ground + (+this.template.FlyingHeight);
if (pos.y < targetHeight)
pos.y = Math.min(targetHeight, pos.y + turnLength*this.template.ClimbRate);
else if (pos.y > targetHeight)
pos.y = Math.max(targetHeight, pos.y - turnLength*this.template.ClimbRate);
cmpPosition.SetHeightFixed(pos.y);
}
// If we're in range of the target then tell people that we've reached it
// (TODO: quantisation breaks this)
var distFromTarget = Math.sqrt(Math.pow(this.targetX - pos.x, 2) + Math.pow(this.targetZ - pos.z, 2));
if (!this.reachedTarget && this.targetMinRange <= distFromTarget && distFromTarget <= this.targetMaxRange)
{
this.reachedTarget = true;
Engine.PostMessage(this.entity, MT_MotionChanged, { "starting": false, "error": false });
}
// If we're facing away from the target, and are still fairly close to it,
// then carry on going straight so we overshoot in a straight line
var isBehindTarget = ((this.targetX - pos.x)*Math.sin(angle) + (this.targetZ - pos.z)*Math.cos(angle) < 0);
if (isBehindTarget && distFromTarget < this.template.MaxSpeed*this.template.OvershootTime)
{
// Overshoot the target: carry on straight
canTurn = false;
}
if (canTurn)
{
// Turn towards the target
var targetAngle = Math.atan2(this.targetX - pos.x, this.targetZ - pos.z);
var delta = targetAngle - angle;
// Wrap delta to -pi..pi
delta = (delta + Math.PI) % (2*Math.PI); // range -2pi..2pi
if (delta < 0) delta += 2*Math.PI; // range 0..2pi
delta -= Math.PI; // range -pi..pi
// Clamp to max rate
var deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate*turnLength), this.template.TurnRate*turnLength);
// Calculate new orientation, in a peculiar way in order to make sure the
// result gets close to targetAngle (rather than being n*2*pi out)
angle = targetAngle + deltaClamped - delta;
}
pos.x += this.speed * turnLength * Math.sin(angle);
pos.z += this.speed * turnLength * Math.cos(angle);
cmpPosition.TurnTo(angle);
cmpPosition.MoveTo(pos.x, pos.z);
};
UnitMotionFlying.prototype.MoveToPointRange = function(x, z, minRange, maxRange)
{
this.hasTarget = true;
this.reachedTarget = false;
this.targetX = x;
this.targetZ = z;
this.targetMinRange = minRange;
this.targetMaxRange = maxRange;
return true;
};
UnitMotionFlying.prototype.MoveToTargetRange = function(target, minRange, maxRange)
{
var cmpTargetPosition = Engine.QueryInterface(target, IID_Position);
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld())
return false;
var targetPos = cmpTargetPosition.GetPosition2D();
this.hasTarget = true;
this.reachedTarget = false;
this.targetX = targetPos.x;
this.targetZ = targetPos.y;
this.targetMinRange = minRange;
this.targetMaxRange = maxRange;
return true;
};
UnitMotionFlying.prototype.IsInTargetRange = function(target, minRange, maxRange)
{
var cmpTargetPosition = Engine.QueryInterface(target, IID_Position);
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld())
return false;
var targetPos = cmpTargetPosition.GetPosition2D();
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
var pos = cmpPosition.GetPosition2D();
var distFromTarget = Math.sqrt(Math.pow(targetPos.x - pos.x, 2) + Math.pow(targetPos.y - pos.y, 2));
if (minRange <= distFromTarget && distFromTarget <= maxRange)
return true;
return false;
};
UnitMotionFlying.prototype.GetWalkSpeed = function()
{
return +this.template.MaxSpeed;
};
UnitMotionFlying.prototype.GetRunSpeed = function()
{
return this.GetWalkSpeed();
};
UnitMotionFlying.prototype.FaceTowardsPoint = function(x, z)
{
// Ignore this - angle is controlled by the target-seeking code instead
};
UnitMotionFlying.prototype.SetDebugOverlay = function(enabled)
{
};
Engine.RegisterComponentType(IID_UnitMotion, "UnitMotionFlying", UnitMotionFlying);

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit">
<Identity>
<Civ>hele</Civ>
<SpecificName>Aeroplane</SpecificName>
<History>This may be anachronistic.</History>
</Identity>
<VisualActor>
<Actor>units/hellenes/siege_rock.xml</Actor> <!-- only using this because its flaming projectiles look nice -->
</VisualActor>
<Obstruction disable=""/>
<UnitMotion disable=""/>
<Position>
<TurnRate>1.57</TurnRate>
</Position>
<UnitMotionFlying>
<MaxSpeed>24.0</MaxSpeed>
<AccelRate>8.0</AccelRate>
<TurnRate>1.57</TurnRate>
<OvershootTime>2.0</OvershootTime>
<FlyingHeight>16.0</FlyingHeight>
<ClimbRate>3.0</ClimbRate>
</UnitMotionFlying>
<Attack>
<Ranged>
<Hack>0.0</Hack>
<Pierce>100.0</Pierce>
<Crush>25.0</Crush>
<MaxRange>48</MaxRange>
<MinRange>24</MinRange>
<ProjectileSpeed>50.0</ProjectileSpeed>
<PrepareTime>0</PrepareTime>
<RepeatTime>1000</RepeatTime>
</Ranged>
</Attack>
</Entity>

View File

@ -4,6 +4,7 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
<VisualActor>
<Actor>(should be overridden)</Actor>

View File

@ -4,6 +4,7 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
<Formation/>
<UnitAI>

View File

@ -6,6 +6,7 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
<Selectable/>
</Entity>

View File

@ -6,5 +6,6 @@
<Altitude>0</Altitude>
<Anchor>upright</Anchor>
<Floating>false</Floating>
<TurnRate>6.0</TurnRate>
</Position>
</Entity>

View File

@ -127,6 +127,7 @@ COMPONENT(Terrain)
INTERFACE(UnitMotion)
COMPONENT(UnitMotion) // must be after Obstruction
COMPONENT(UnitMotionScripted)
INTERFACE(Vision)
COMPONENT(Vision)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -68,6 +68,7 @@ public:
bool m_InWorld;
entity_pos_t m_X, m_Z, m_LastX, m_LastZ; // these values contain undefined junk if !InWorld
entity_pos_t m_YOffset;
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
@ -80,6 +81,7 @@ public:
"<Anchor>upright</Anchor>"
"<Altitude>0.0</Altitude>"
"<Floating>false</Floating>"
"<TurnRate>6.0</TurnRate>"
"</a:example>"
"<element name='Anchor' a:help='Automatic rotation to follow the slope of terrain'>"
"<choice>"
@ -93,6 +95,9 @@ public:
"</element>"
"<element name='Floating' a:help='Whether the entity floats on water'>"
"<data type='boolean'/>"
"</element>"
"<element name='TurnRate' a:help='Maximum graphical rotation speed around Y axis, in radians per second'>"
"<ref name='positiveDecimal'/>"
"</element>";
}
@ -109,9 +114,10 @@ public:
m_InWorld = false;
m_YOffset = paramNode.GetChild("Altitude").ToFixed();
m_RelativeToGround = true;
m_Floating = paramNode.GetChild("Floating").ToBool();
m_RotYSpeed = 6.f; // TODO: should get from template
m_RotYSpeed = paramNode.GetChild("TurnRate").ToFixed().ToFloat();
m_RotX = m_RotY = m_RotZ = entity_angle_t::FromInt(0);
m_InterpolatedRotY = 0;
@ -137,6 +143,7 @@ public:
serialize.NumberFixed_Unbounded("rot y", m_RotY);
serialize.NumberFixed_Unbounded("rot z", m_RotZ);
serialize.NumberFixed_Unbounded("altitude", m_YOffset);
serialize.Bool("relative", m_RelativeToGround);
if (serialize.IsDebug())
{
@ -168,6 +175,7 @@ public:
deserialize.NumberFixed_Unbounded("rot y", m_RotY);
deserialize.NumberFixed_Unbounded("rot z", m_RotZ);
deserialize.NumberFixed_Unbounded("altitude", m_YOffset);
deserialize.Bool("relative", m_RelativeToGround);
// TODO: should there be range checks on all these values?
m_InterpolatedRotY = m_RotY.ToFloat();
@ -212,6 +220,7 @@ public:
virtual void SetHeightOffset(entity_pos_t dy)
{
m_YOffset = dy;
m_RelativeToGround = true;
AdvertisePositionChanges();
}
@ -221,6 +230,12 @@ public:
return m_YOffset;
}
virtual void SetHeightFixed(entity_pos_t y)
{
m_YOffset = y;
m_RelativeToGround = false;
}
virtual bool IsFloating()
{
return m_Floating;
@ -235,15 +250,18 @@ public:
}
entity_pos_t baseY;
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
baseY = cmpTerrain->GetGroundLevel(m_X, m_Z);
if (m_Floating)
if (m_RelativeToGround)
{
CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY);
if (!cmpWaterMan.null())
baseY = std::max(baseY, cmpWaterMan->GetWaterLevel(m_X, m_Z));
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
baseY = cmpTerrain->GetGroundLevel(m_X, m_Z);
if (m_Floating)
{
CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY);
if (!cmpWaterMan.null())
baseY = std::max(baseY, cmpWaterMan->GetWaterLevel(m_X, m_Z));
}
}
return CFixedVector3D(m_X, baseY + m_YOffset, m_Z);
@ -327,15 +345,18 @@ public:
GetInterpolatedPosition2D(frameOffset, x, z, rotY);
float baseY = 0;
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
baseY = cmpTerrain->GetExactGroundLevel(x, z);
if (m_Floating || forceFloating)
if (m_RelativeToGround)
{
CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY);
if (!cmpWaterMan.null())
baseY = std::max(baseY, cmpWaterMan->GetExactWaterLevel(x, z));
CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
baseY = cmpTerrain->GetExactGroundLevel(x, z);
if (m_Floating || forceFloating)
{
CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY);
if (!cmpWaterMan.null())
baseY = std::max(baseY, cmpWaterMan->GetExactWaterLevel(x, z));
}
}
float y = baseY + m_YOffset.ToFloat();

View File

@ -413,6 +413,8 @@ public:
virtual bool IsInTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange);
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z);
virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z);
virtual void StopMoving()
{
m_ExpectedPathTicket = 0;
@ -522,7 +524,7 @@ private:
/**
* Rotate to face towards the target point, given the current pos
*/
void FaceTowardsPoint(CFixedVector2D pos, entity_pos_t x, entity_pos_t z);
void FaceTowardsPointFromPos(CFixedVector2D pos, entity_pos_t x, entity_pos_t z);
/**
* Returns an appropriate obstruction filter for use with path requests.
@ -901,7 +903,7 @@ void CCmpUnitMotion::Move(fixed dt)
StopMoving();
FaceTowardsPoint(pos, m_FinalGoal.x, m_FinalGoal.z);
FaceTowardsPointFromPos(pos, m_FinalGoal.x, m_FinalGoal.z);
// TODO: if the goal was a square building, we ought to point towards the
// nearest point on the square, not towards its center
}
@ -1033,7 +1035,17 @@ bool CCmpUnitMotion::PathIsShort(const ICmpPathfinder::Path& path, CFixedVector2
return true;
}
void CCmpUnitMotion::FaceTowardsPoint(CFixedVector2D pos, entity_pos_t x, entity_pos_t z)
void CCmpUnitMotion::FaceTowardsPoint(entity_pos_t x, entity_pos_t z)
{
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
if (cmpPosition.null() || !cmpPosition->IsInWorld())
return;
CFixedVector2D pos = cmpPosition->GetPosition2D();
FaceTowardsPointFromPos(pos, x, z);
}
void CCmpUnitMotion::FaceTowardsPointFromPos(CFixedVector2D pos, entity_pos_t x, entity_pos_t z)
{
CFixedVector2D target(x, z);
CFixedVector2D offset = target - pos;
@ -1223,7 +1235,7 @@ bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos
else
{
// We're already in range - no need to move anywhere
FaceTowardsPoint(pos, x, z);
FaceTowardsPointFromPos(pos, x, z);
return false;
}
@ -1334,7 +1346,7 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
else if (maxRange < entity_pos_t::Zero() || distance < maxRange)
{
// We're already in range - no need to move anywhere
FaceTowardsPoint(pos, goal.x, goal.z);
FaceTowardsPointFromPos(pos, goal.x, goal.z);
return false;
}
else
@ -1356,7 +1368,7 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
if (circleDistance < maxRange)
{
// We're already in range - no need to move anywhere
FaceTowardsPoint(pos, goal.x, goal.z);
FaceTowardsPointFromPos(pos, goal.x, goal.z);
return false;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -28,6 +28,7 @@ DEFINE_INTERFACE_METHOD_2("MoveTo", void, ICmpPosition, MoveTo, entity_pos_t, en
DEFINE_INTERFACE_METHOD_2("JumpTo", void, ICmpPosition, JumpTo, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_1("SetHeightOffset", void, ICmpPosition, SetHeightOffset, entity_pos_t)
DEFINE_INTERFACE_METHOD_0("GetHeightOffset", entity_pos_t, ICmpPosition, GetHeightOffset)
DEFINE_INTERFACE_METHOD_1("SetHeightFixed", void, ICmpPosition, SetHeightFixed, entity_pos_t)
DEFINE_INTERFACE_METHOD_0("IsFloating", bool, ICmpPosition, IsFloating)
DEFINE_INTERFACE_METHOD_0("GetPosition", CFixedVector3D, ICmpPosition, GetPosition)
DEFINE_INTERFACE_METHOD_0("GetPosition2D", CFixedVector2D, ICmpPosition, GetPosition2D)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -84,6 +84,12 @@ public:
*/
virtual entity_pos_t GetHeightOffset() = 0;
/**
* Set the vertical position as a fixed, absolute value.
* Will stay at this height until the next call to SetHeightFixed or SetHeightOffset.
*/
virtual void SetHeightFixed(entity_pos_t y) = 0;
/**
* Returns whether the entity floats on water.
*/

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -20,12 +20,14 @@
#include "ICmpUnitMotion.h"
#include "simulation2/system/InterfaceScripted.h"
#include "simulation2/scripting/ScriptComponent.h"
BEGIN_INTERFACE_WRAPPER(UnitMotion)
DEFINE_INTERFACE_METHOD_4("MoveToPointRange", bool, ICmpUnitMotion, MoveToPointRange, entity_pos_t, entity_pos_t, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_3("IsInTargetRange", bool, ICmpUnitMotion, IsInTargetRange, entity_id_t, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_3("MoveToTargetRange", bool, ICmpUnitMotion, MoveToTargetRange, entity_id_t, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_3("MoveToFormationOffset", void, ICmpUnitMotion, MoveToFormationOffset, entity_id_t, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_2("FaceTowardsPoint", void, ICmpUnitMotion, FaceTowardsPoint, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_0("StopMoving", void, ICmpUnitMotion, StopMoving)
DEFINE_INTERFACE_METHOD_1("SetSpeed", void, ICmpUnitMotion, SetSpeed, fixed)
DEFINE_INTERFACE_METHOD_0("GetWalkSpeed", fixed, ICmpUnitMotion, GetWalkSpeed)
@ -33,3 +35,67 @@ DEFINE_INTERFACE_METHOD_0("GetRunSpeed", fixed, ICmpUnitMotion, GetRunSpeed)
DEFINE_INTERFACE_METHOD_1("SetUnitRadius", void, ICmpUnitMotion, SetUnitRadius, fixed)
DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpUnitMotion, SetDebugOverlay, bool)
END_INTERFACE_WRAPPER(UnitMotion)
class CCmpUnitMotionScripted : public ICmpUnitMotion
{
public:
DEFAULT_SCRIPT_WRAPPER(UnitMotionScripted)
virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
{
return m_Script.Call<bool>("MoveToPointRange", x, z, minRange, maxRange);
}
virtual bool IsInTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
{
return m_Script.Call<bool>("IsInTargetRange", target, minRange, maxRange);
}
virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange)
{
return m_Script.Call<bool>("MoveToTargetRange", target, minRange, maxRange);
}
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z)
{
m_Script.CallVoid("MoveToFormationOffset", target, x, z);
}
virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z)
{
m_Script.CallVoid("FaceTowardsPoint", x, z);
}
virtual void StopMoving()
{
m_Script.CallVoid("StopMoving");
}
virtual void SetSpeed(fixed speed)
{
m_Script.CallVoid("SetSpeed", speed);
}
virtual fixed GetWalkSpeed()
{
return m_Script.Call<fixed>("GetWalkSpeed");
}
virtual fixed GetRunSpeed()
{
return m_Script.Call<fixed>("GetRunSpeed");
}
virtual void SetUnitRadius(fixed radius)
{
m_Script.CallVoid("SetUnitRadius", radius);
}
virtual void SetDebugOverlay(bool enabled)
{
m_Script.CallVoid("SetDebugOverlay", enabled);
}
};
REGISTER_COMPONENT_SCRIPT_WRAPPER(UnitMotionScripted)

View File

@ -67,6 +67,11 @@ public:
*/
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z) = 0;
/**
* Turn to look towards the given point.
*/
virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z) = 0;
/**
* Stop moving immediately.
*/

View File

@ -83,7 +83,7 @@ public:
const CParamNode* preview = tempMan->LoadTemplate(ent2, "preview|unit", -1);
TS_ASSERT(preview != NULL);
TS_ASSERT_WSTR_EQUALS(preview->ToXML(),
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating></Position>"
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating><TurnRate>6.0</TurnRate></Position>"
L"<Vision><AlwaysVisible>true</AlwaysVisible><Range>0</Range><RetainInFog>false</RetainInFog></Vision>"
L"<VisualActor><Actor>example</Actor><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder></VisualActor>");
@ -97,7 +97,7 @@ public:
L"<DisableBlockMovement>false</DisableBlockMovement><DisableBlockPathfinding>false</DisableBlockPathfinding>"
L"<Unit radius=\"4\"></Unit>"
L"</Obstruction>"
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating></Position>"
L"<Position><Altitude>0</Altitude><Anchor>upright</Anchor><Floating>false</Floating><TurnRate>6.0</TurnRate></Position>"
L"<Vision><AlwaysVisible>true</AlwaysVisible><Range>0</Range><RetainInFog>false</RetainInFog></Vision>"
L"<VisualActor><Actor>example</Actor><SilhouetteDisplay>false</SilhouetteDisplay><SilhouetteOccluder>false</SilhouetteOccluder></VisualActor>");