Add terrain orientation support for Mobile.

This commit is contained in:
Paul Chote
2021-08-21 10:23:57 +01:00
committed by reaperrr
parent c88d1bbefa
commit 68710e48a6
7 changed files with 113 additions and 30 deletions

View File

@@ -900,6 +900,14 @@ namespace OpenRA
return new WDist(offset.Z);
}
public WRot TerrainOrientation(CPos cell)
{
if (!Ramp.Contains(cell))
return WRot.None;
return Grid.Ramps[Ramp[cell]].Orientation;
}
public WVec Offset(CVec delta, int dz)
{
if (Grid.Type == MapGridType.Rectangular)

View File

@@ -27,9 +27,11 @@ namespace OpenRA
public readonly int CenterHeightOffset;
public readonly WVec[] Corners;
public readonly WVec[][] Polygons;
public readonly WRot Orientation;
public CellRamp(MapGridType type, RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low, RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low, RampSplit split = RampSplit.Flat)
public CellRamp(MapGridType type, WRot orientation, RampCornerHeight tl = RampCornerHeight.Low, RampCornerHeight tr = RampCornerHeight.Low, RampCornerHeight br = RampCornerHeight.Low, RampCornerHeight bl = RampCornerHeight.Low, RampSplit split = RampSplit.Flat)
{
Orientation = orientation;
if (type == MapGridType.RectangularIsometric)
{
Corners = new[]
@@ -138,41 +140,52 @@ namespace OpenRA
throw new InvalidDataException("Subcell default index must be a valid index into the offset triples and must be greater than 0 for mods with subcells");
}
// Rotation axes and amounts for the different slope types
var southEast = new WVec(724, 724, 0);
var southWest = new WVec(-724, 724, 0);
var south = new WVec(0, 1024, 0);
var east = new WVec(1024, 0, 0);
var forward = new WAngle(64);
var backward = -forward;
var halfForward = new WAngle(48);
var halfBackward = -halfForward;
// Slope types are hardcoded following the convention from the TS and RA2 map format
Ramps = new[]
{
// Flat
new CellRamp(Type),
new CellRamp(Type, WRot.None),
// Two adjacent corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half),
new CellRamp(Type, br: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half),
new CellRamp(Type, new WRot(southEast, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half),
new CellRamp(Type, new WRot(southWest, backward), br: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, new WRot(southEast, forward), tl: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, new WRot(southWest, forward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half),
// One corner raised by half a cell
new CellRamp(Type, br: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tr: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, new WRot(south, halfBackward), br: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, new WRot(east, halfForward), bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, new WRot(east, halfBackward), tr: RampCornerHeight.Half, split: RampSplit.Y),
// Three corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, new WRot(south, halfBackward), tr: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, new WRot(east, halfForward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, new WRot(south, halfForward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, new WRot(east, halfBackward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
// Full tile sloped (mid corners raised by half cell, far corner by full cell)
new CellRamp(Type, tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full),
new CellRamp(Type, tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half),
new CellRamp(Type, new WRot(south, backward), tr: RampCornerHeight.Half, br: RampCornerHeight.Full, bl: RampCornerHeight.Half),
new CellRamp(Type, new WRot(east, forward), tl: RampCornerHeight.Half, br: RampCornerHeight.Half, bl: RampCornerHeight.Full),
new CellRamp(Type, new WRot(south, forward), tl: RampCornerHeight.Full, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half),
new CellRamp(Type, new WRot(east, backward), tl: RampCornerHeight.Half, tr: RampCornerHeight.Full, br: RampCornerHeight.Half),
// Two opposite corners raised by half a cell
new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.Y),
new CellRamp(Type, WRot.None, tr: RampCornerHeight.Half, bl: RampCornerHeight.Half, split: RampSplit.X),
new CellRamp(Type, WRot.None, tl: RampCornerHeight.Half, br: RampCornerHeight.Half, split: RampSplit.X),
};
TilesByDistance = CreateTilesByDistance();

View File

@@ -221,7 +221,12 @@ namespace OpenRA.Mods.Common.Activities
var to = Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) +
(map.Grid.OffsetOfSubCell(mobile.FromSubCell) + map.Grid.OffsetOfSubCell(mobile.ToSubCell)) / 2;
QueueChild(new MoveFirstHalf(this, from, to, mobile.Facing, mobile.Facing, carryoverProgress));
WRot? toTerrainOrientation = null;
var margin = mobile.Info.TerrainOrientationAdjustmentMargin.Length;
if (margin >= 0)
toTerrainOrientation = WRot.SLerp(map.TerrainOrientation(mobile.FromCell), map.TerrainOrientation(mobile.ToCell), 1, 2);
QueueChild(new MoveFirstHalf(this, from, to, mobile.Facing, mobile.Facing, null, toTerrainOrientation, margin, carryoverProgress));
carryoverProgress = 0;
return false;
}
@@ -389,6 +394,7 @@ namespace OpenRA.Mods.Common.Activities
protected readonly Move Move;
protected readonly WPos From, To;
protected readonly WAngle FromFacing, ToFacing;
protected readonly WRot? FromTerrainOrientation, ToTerrainOrientation;
protected readonly bool EnableArc;
protected readonly WPos ArcCenter;
protected readonly int ArcFromLength;
@@ -396,17 +402,22 @@ namespace OpenRA.Mods.Common.Activities
protected readonly int ArcToLength;
protected readonly WAngle ArcToAngle;
protected readonly int Distance;
readonly int terrainOrientationMargin;
protected int progress;
public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress)
public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing,
WRot? fromTerrainOrientation, WRot? toTerrainOrientation, int terrainOrientationMargin, int carryoverProgress)
{
Move = move;
From = from;
To = to;
FromFacing = fromFacing;
ToFacing = toFacing;
FromTerrainOrientation = fromTerrainOrientation;
ToTerrainOrientation = toTerrainOrientation;
progress = carryoverProgress;
Distance = (to - from).Length;
this.terrainOrientationMargin = Math.Min(terrainOrientationMargin, Distance / 2);
IsInterruptible = false; // See comments in Move.Cancel()
@@ -471,6 +482,21 @@ namespace OpenRA.Mods.Common.Activities
pos -= new WVec(WDist.Zero, WDist.Zero, self.World.Map.DistanceAboveTerrain(pos));
mobile.SetCenterPosition(self, pos);
// Smoothly interpolate over terrain orientation changes
if (FromTerrainOrientation.HasValue && progress < terrainOrientationMargin)
{
var currentCellOrientation = self.World.Map.TerrainOrientation(mobile.FromCell);
var orientation = WRot.SLerp(FromTerrainOrientation.Value, currentCellOrientation, progress, terrainOrientationMargin);
mobile.SetTerrainRampOrientation(self, orientation);
}
else if (ToTerrainOrientation.HasValue && Distance - progress < terrainOrientationMargin)
{
var currentCellOrientation = self.World.Map.TerrainOrientation(mobile.FromCell);
var orientation = WRot.SLerp(ToTerrainOrientation.Value, currentCellOrientation, Distance - progress, terrainOrientationMargin);
mobile.SetTerrainRampOrientation(self, orientation);
}
mobile.Facing = WAngle.Lerp(FromFacing, ToFacing, progress, Distance);
return false;
}
@@ -485,8 +511,9 @@ namespace OpenRA.Mods.Common.Activities
class MoveFirstHalf : MovePart
{
public MoveFirstHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress)
: base(move, from, to, fromFacing, toFacing, carryoverProgress) { }
public MoveFirstHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing,
WRot? fromTerrainOrientation, WRot? toTerrainOrientation, int terrainOrientationMargin, int carryoverProgress)
: base(move, from, to, fromFacing, toFacing, fromTerrainOrientation, toTerrainOrientation, terrainOrientationMargin, carryoverProgress) { }
static bool IsTurn(Mobile mobile, CPos nextCell, Map map)
{
@@ -513,12 +540,20 @@ namespace OpenRA.Mods.Common.Activities
if (!mobile.IsTraitPaused && !mobile.IsTraitDisabled && IsTurn(mobile, nextCell.Value.Cell, map))
{
var nextSubcellOffset = map.Grid.OffsetOfSubCell(nextCell.Value.SubCell);
WRot? nextToTerrainOrientation = null;
var margin = mobile.Info.TerrainOrientationAdjustmentMargin.Length;
if (margin >= 0)
nextToTerrainOrientation = WRot.SLerp(map.TerrainOrientation(mobile.ToCell), map.TerrainOrientation(nextCell.Value.Cell), 1, 2);
var ret = new MoveFirstHalf(
Move,
Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + (fromSubcellOffset + toSubcellOffset) / 2,
Util.BetweenCells(self.World, mobile.ToCell, nextCell.Value.Cell) + (toSubcellOffset + nextSubcellOffset) / 2,
mobile.Facing,
map.FacingBetween(mobile.ToCell, nextCell.Value.Cell, mobile.Facing),
ToTerrainOrientation,
nextToTerrainOrientation,
margin,
progress - Distance);
mobile.FinishedMoving(self);
@@ -538,6 +573,9 @@ namespace OpenRA.Mods.Common.Activities
toPos + toSubcellOffset,
mobile.Facing,
mobile.Facing,
ToTerrainOrientation,
null,
mobile.Info.TerrainOrientationAdjustmentMargin.Length,
progress - Distance);
mobile.EnteringCell(self);
@@ -548,8 +586,9 @@ namespace OpenRA.Mods.Common.Activities
class MoveSecondHalf : MovePart
{
public MoveSecondHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress)
: base(move, from, to, fromFacing, toFacing, carryoverProgress) { }
public MoveSecondHalf(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing,
WRot? fromTerrainOrientation, WRot? toTerrainOrientation, int terrainOrientationMargin, int carryoverProgress)
: base(move, from, to, fromFacing, toFacing, fromTerrainOrientation, toTerrainOrientation, terrainOrientationMargin, carryoverProgress) { }
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
{

View File

@@ -133,8 +133,12 @@ namespace OpenRA.Mods.Common.Graphics
this.model = model;
var draw = model.models.Where(v => v.IsVisible);
var map = wr.World.Map;
var groundOrientation = map.TerrainOrientation(map.CellContaining(model.pos));
var groundNormal = OpenRA.Graphics.Util.MatrixVectorMultiply(OpenRA.Graphics.Util.MakeFloatMatrix(groundOrientation.AsMatrix()), GroundNormal);
renderProxy = Game.Renderer.WorldModelRenderer.RenderAsync(
wr, draw, model.camera, model.scale, GroundNormal, model.lightSource,
wr, draw, model.camera, model.scale, groundNormal, model.lightSource,
model.lightAmbientColor, model.lightDiffuseColor,
model.palette, model.normalsPalette, model.shadowPalette);
}

View File

@@ -74,6 +74,10 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Boolean expression defining the condition under which this actor cannot be nudged by other actors.")]
public readonly BooleanExpression ImmovableCondition = null;
[Desc("The distance from the edge of a cell over which the actor will adjust its tilt when moving between cells with different ramp types.",
"-1 means that the actor does not tilt on slopes.")]
public readonly WDist TerrainOrientationAdjustmentMargin = new WDist(-1);
IEnumerable<ActorInit> IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type)
{
yield return new FacingInit(PreviewFacing);
@@ -183,6 +187,7 @@ namespace OpenRA.Mods.Common.Traits
}
#endregion
WRot terrainRampOrientation = WRot.None;
WAngle oldFacing;
WRot orientation;
WPos oldPos;
@@ -211,7 +216,7 @@ namespace OpenRA.Mods.Common.Traits
set => orientation = orientation.WithYaw(value);
}
public WRot Orientation => orientation;
public WRot Orientation => orientation.Rotate(terrainRampOrientation);
public WAngle TurnSpeed => Info.TurnSpeed;
@@ -485,6 +490,9 @@ namespace OpenRA.Mods.Common.Traits
CenterPosition = pos;
self.World.UpdateMaps(self, this);
var map = self.World.Map;
SetTerrainRampOrientation(self, map.TerrainOrientation(map.CellContaining(pos)));
// The first time SetCenterPosition is called is in the constructor before creation, so we need a null check here as well
if (notifyCenterPositionChanged == null)
return;
@@ -493,6 +501,12 @@ namespace OpenRA.Mods.Common.Traits
n.CenterPositionChanged(self, fromCell.Layer, toCell.Layer);
}
public void SetTerrainRampOrientation(Actor self, WRot orientation)
{
if (Info.TerrainOrientationAdjustmentMargin.Length >= 0)
terrainRampOrientation = orientation;
}
public bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any)
{
return ToCell != location && fromCell == location

View File

@@ -780,6 +780,7 @@
Locomotor: wheeled
TurnSpeed: 20
Voice: Move
TerrainOrientationAdjustmentMargin: 256
Selectable:
Bounds: 1206, 1448
Voiced:

View File

@@ -67,6 +67,7 @@ HVR:
Mobile:
Speed: 99
Locomotor: hover
TerrainOrientationAdjustmentMargin: -1
Selectable:
Bounds: 1206, 1448, 0, -603
Health:
@@ -123,6 +124,7 @@ SMECH:
TurnSpeed: 20
Speed: 99
AlwaysTurnInPlace: true
TerrainOrientationAdjustmentMargin: -1
Health:
HP: 17500
Armor:
@@ -176,6 +178,7 @@ MMCH:
TurnSpeed: 20
Speed: 56
AlwaysTurnInPlace: true
TerrainOrientationAdjustmentMargin: -1
Health:
HP: 40000
Armor:
@@ -341,6 +344,7 @@ JUGG:
AlwaysTurnInPlace: true
ImmovableCondition: !undeployed
RequireForceMoveCondition: !undeployed
TerrainOrientationAdjustmentMargin: -1
RevealsShroud:
RequiresCondition: !inside-tunnel
Range: 9c0