Editor actor move
This commit is contained in:
committed by
Gustas
parent
ac610c54eb
commit
7b82d85b27
@@ -43,6 +43,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
readonly IResourceLayer resourceLayer;
|
||||
readonly EditorCursorLayer cursorLayer;
|
||||
|
||||
public CellRegion CurrentDragBounds => selectionBounds ?? Selection.Area;
|
||||
|
||||
@@ -53,6 +54,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
int2? selectionStartLocation;
|
||||
CPos? selectionStartCell;
|
||||
int2 worldPixel;
|
||||
bool draggingActor;
|
||||
MoveActorAction moveAction;
|
||||
|
||||
public EditorDefaultBrush(EditorViewportControllerWidget editorWidget, WorldRenderer wr)
|
||||
{
|
||||
@@ -63,6 +66,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
|
||||
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
|
||||
resourceLayer = world.WorldActor.TraitOrDefault<IResourceLayer>();
|
||||
cursorLayer = world.WorldActor.Trait<EditorCursorLayer>();
|
||||
}
|
||||
|
||||
long CalculateActorSelectionPriority(EditorActorPreview actor)
|
||||
@@ -126,16 +130,44 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
else
|
||||
editorWidget.SetTooltip(null);
|
||||
|
||||
// Actor drag.
|
||||
if (mi.Button == MouseButton.Left)
|
||||
{
|
||||
if (mi.Event == MouseInputEvent.Down && underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || underCursor == Selection.Actor))
|
||||
{
|
||||
editorWidget.SetTooltip(null);
|
||||
var cellViewPx = worldRenderer.Viewport.WorldToViewPx(worldRenderer.ScreenPosition(world.Map.CenterOfCell(cell)));
|
||||
var pixelOffset = cellViewPx - mi.Location;
|
||||
var cellOffset = underCursor.Location - cell;
|
||||
moveAction = new MoveActorAction(underCursor, cursorLayer, worldRenderer, pixelOffset, cellOffset);
|
||||
draggingActor = true;
|
||||
return false;
|
||||
}
|
||||
else if (mi.Event == MouseInputEvent.Up && draggingActor)
|
||||
{
|
||||
editorWidget.SetTooltip(null);
|
||||
draggingActor = false;
|
||||
editorActionManager.Add(moveAction);
|
||||
moveAction = null;
|
||||
return false;
|
||||
}
|
||||
else if (mi.Event == MouseInputEvent.Move && draggingActor)
|
||||
{
|
||||
editorWidget.SetTooltip(null);
|
||||
moveAction.Move(mi.Location);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Selection box drag.
|
||||
if (selectionStartLocation != null &&
|
||||
if (mi.Event == MouseInputEvent.Move &&
|
||||
selectionStartLocation != null &&
|
||||
(selectionBounds != null || (mi.Location - selectionStartLocation.Value).LengthSquared > MinMouseMoveBeforeDrag))
|
||||
{
|
||||
selectionStartCell ??= worldRenderer.Viewport.ViewToWorld(selectionStartLocation.Value);
|
||||
|
||||
var topLeft = new CPos(Math.Min(selectionStartCell.Value.X, cell.X), Math.Min(selectionStartCell.Value.Y, cell.Y));
|
||||
var bottomRight = new CPos(Math.Max(selectionStartCell.Value.X, cell.X), Math.Max(selectionStartCell.Value.Y, cell.Y));
|
||||
var width = bottomRight.X - topLeft.X;
|
||||
var height = bottomRight.Y - topLeft.Y;
|
||||
var gridType = worldRenderer.World.Map.Grid.Type;
|
||||
|
||||
// We've dragged enough to capture more than one cell, make a selection box.
|
||||
@@ -211,7 +243,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
editorWidget.SetTooltip(null);
|
||||
|
||||
// Delete actor.
|
||||
if (underCursor != null && underCursor != Selection.Actor)
|
||||
if (underCursor != null && underCursor != Selection.Actor && !draggingActor)
|
||||
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));
|
||||
|
||||
// Or delete resource if found under cursor.
|
||||
@@ -368,6 +400,59 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MoveActorAction : IEditorAction
|
||||
{
|
||||
[TranslationReference("id", "x1", "y1", "x2", "y2")]
|
||||
const string MovedActor = "notification-moved-actor";
|
||||
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly EditorActorPreview actor;
|
||||
readonly EditorCursorLayer layer;
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly int2 pixelOffset;
|
||||
readonly CVec cellOffset;
|
||||
readonly CPos from;
|
||||
|
||||
CPos to;
|
||||
|
||||
public MoveActorAction(
|
||||
EditorActorPreview actor,
|
||||
EditorCursorLayer layer,
|
||||
WorldRenderer worldRenderer,
|
||||
int2 pixelOffset,
|
||||
CVec cellOffset)
|
||||
{
|
||||
this.actor = actor;
|
||||
this.layer = layer;
|
||||
this.worldRenderer = worldRenderer;
|
||||
this.pixelOffset = pixelOffset;
|
||||
this.cellOffset = cellOffset;
|
||||
|
||||
from = actor.Location;
|
||||
}
|
||||
|
||||
public void Execute() { }
|
||||
|
||||
public void Do()
|
||||
{
|
||||
layer.MoveActor(actor, to);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
layer.MoveActor(actor, from);
|
||||
}
|
||||
|
||||
public void Move(int2 pixelTo)
|
||||
{
|
||||
to = worldRenderer.Viewport.ViewToWorld(pixelTo + pixelOffset) + cellOffset;
|
||||
layer.MoveActor(actor, to);
|
||||
|
||||
Text = TranslationProvider.GetString(MovedActor, Translation.Arguments("id", actor.ID, "x1", from.X, "y1", from.Y, "x2", to.X, "y2", to.Y));
|
||||
}
|
||||
}
|
||||
|
||||
sealed class RemoveResourceAction : IEditorAction
|
||||
{
|
||||
[TranslationReference("type")]
|
||||
|
||||
@@ -25,10 +25,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
public readonly string DescriptiveName;
|
||||
public readonly ActorInfo Info;
|
||||
public readonly WPos CenterPosition;
|
||||
public readonly IReadOnlyDictionary<CPos, SubCell> Footprint;
|
||||
public readonly Rectangle Bounds;
|
||||
public readonly SelectionBoxAnnotationRenderable SelectionBox;
|
||||
|
||||
public string Tooltip =>
|
||||
(tooltip == null ? " < " + Info.Name + " >" : TranslationProvider.GetString(tooltip.Name)) + "\n" + Owner.Name + " (" + Owner.Faction + ")"
|
||||
@@ -38,17 +34,22 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public string ID { get; set; }
|
||||
public PlayerReference Owner { get; set; }
|
||||
public SubCell SubCell { get; }
|
||||
public WPos CenterPosition { get; set; }
|
||||
public IReadOnlyDictionary<CPos, SubCell> Footprint { get; private set; }
|
||||
public Rectangle Bounds { get; private set; }
|
||||
public bool Selected { get; set; }
|
||||
public Color RadarColor { get; private set; }
|
||||
readonly RadarColorFromTerrainInfo terrainRadarColorInfo;
|
||||
public CPos Location { get; private set; }
|
||||
|
||||
readonly RadarColorFromTerrainInfo terrainRadarColorInfo;
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly TooltipInfoBase tooltip;
|
||||
IActorPreview[] previews;
|
||||
readonly ActorReference reference;
|
||||
readonly Action<CPos> onCellEntryChanged;
|
||||
readonly Dictionary<INotifyEditorPlacementInfo, object> editorData = new();
|
||||
readonly Action<CPos> onCellEntryChanged;
|
||||
|
||||
SelectionBoxAnnotationRenderable selectionBox;
|
||||
IActorPreview[] previews;
|
||||
|
||||
public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner)
|
||||
{
|
||||
@@ -67,41 +68,58 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (!world.Map.Rules.Actors.TryGetValue(reference.Type.ToLowerInvariant(), out Info))
|
||||
throw new InvalidDataException($"Actor {id} of unknown type {reference.Type.ToLowerInvariant()}");
|
||||
|
||||
CenterPosition = PreviewPosition(world, reference);
|
||||
|
||||
var location = reference.Get<LocationInit>().Value;
|
||||
var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
|
||||
var subCellInit = reference.GetOrDefault<SubCellInit>();
|
||||
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;
|
||||
|
||||
var occupiedCells = ios?.OccupiedCells(Info, location, subCell);
|
||||
if (occupiedCells == null || occupiedCells.Count == 0)
|
||||
Footprint = new Dictionary<CPos, SubCell>() { { location, SubCell.FullCell } };
|
||||
else
|
||||
Footprint = occupiedCells;
|
||||
UpdateFromCellChange();
|
||||
GenerateFootprint();
|
||||
|
||||
tooltip = Info.TraitInfos<EditorOnlyTooltipInfo>().FirstOrDefault(info => info.EnabledByDefault) as TooltipInfoBase
|
||||
?? Info.TraitInfos<TooltipInfo>().FirstOrDefault(info => info.EnabledByDefault);
|
||||
|
||||
DescriptiveName = tooltip != null ? tooltip.Name : Info.Name;
|
||||
|
||||
GeneratePreviews();
|
||||
|
||||
terrainRadarColorInfo = Info.TraitInfoOrDefault<RadarColorFromTerrainInfo>();
|
||||
UpdateRadarColor();
|
||||
|
||||
// Bounds are fixed from the initial render.
|
||||
// If this is a problem, then we may need to fetch the area from somewhere else
|
||||
// TODO: updating all actors on the map is not very efficient.
|
||||
onCellEntryChanged = _ => UpdateFromCellChange();
|
||||
}
|
||||
|
||||
void UpdateFromCellChange()
|
||||
{
|
||||
CenterPosition = PreviewPosition(worldRenderer.World, reference);
|
||||
GeneratePreviews();
|
||||
GenerateBounds();
|
||||
}
|
||||
|
||||
void GenerateBounds()
|
||||
{
|
||||
var r = previews.SelectMany(p => p.ScreenBounds(worldRenderer, CenterPosition));
|
||||
|
||||
Bounds = r.Union();
|
||||
|
||||
SelectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192),
|
||||
selectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192),
|
||||
new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height), Color.White);
|
||||
}
|
||||
|
||||
// TODO: updating all actors on the map is not very efficient.
|
||||
onCellEntryChanged = _ => GeneratePreviews();
|
||||
void GenerateFootprint()
|
||||
{
|
||||
Location = reference.Get<LocationInit>().Value;
|
||||
var ios = Info.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
var subCellInit = reference.GetOrDefault<SubCellInit>();
|
||||
var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any;
|
||||
|
||||
var occupiedCells = ios?.OccupiedCells(Info, Location, subCell);
|
||||
if (occupiedCells == null || occupiedCells.Count == 0)
|
||||
Footprint = new Dictionary<CPos, SubCell>() { { Location, SubCell.FullCell } };
|
||||
else
|
||||
Footprint = occupiedCells;
|
||||
}
|
||||
|
||||
void GeneratePreviews()
|
||||
{
|
||||
var init = new ActorPreviewInitializer(reference, worldRenderer);
|
||||
previews = Info.TraitInfos<IRenderActorPreviewInfo>()
|
||||
.SelectMany(rpi => rpi.RenderPreview(init))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
@@ -131,7 +149,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
public IEnumerable<IRenderable> RenderAnnotations()
|
||||
{
|
||||
if (Selected)
|
||||
yield return SelectionBox;
|
||||
yield return selectionBox;
|
||||
}
|
||||
|
||||
public void UpdateFromMove()
|
||||
{
|
||||
CenterPosition = PreviewPosition(worldRenderer.World, reference);
|
||||
GenerateFootprint();
|
||||
GenerateBounds();
|
||||
}
|
||||
|
||||
public void AddedToEditor()
|
||||
@@ -258,14 +283,6 @@ namespace OpenRA.Mods.Common.Traits
|
||||
throw new InvalidDataException($"Actor {ID} must define Location or CenterPosition");
|
||||
}
|
||||
|
||||
void GeneratePreviews()
|
||||
{
|
||||
var init = new ActorPreviewInitializer(reference, worldRenderer);
|
||||
previews = Info.TraitInfos<IRenderActorPreviewInfo>()
|
||||
.SelectMany(rpi => rpi.RenderPreview(init))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
void UpdateRadarColor()
|
||||
{
|
||||
RadarColor = terrainRadarColorInfo == null ? Owner.Color : terrainRadarColorInfo.GetColorFromTerrain(worldRenderer.World);
|
||||
|
||||
@@ -189,6 +189,22 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return ++CurrentToken;
|
||||
}
|
||||
|
||||
public void MoveActor(EditorActorPreview preview, CPos location)
|
||||
{
|
||||
editorLayer.Remove(preview);
|
||||
preview.ReplaceInit(new LocationInit(location));
|
||||
var ios = preview.Info.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
if (ios != null && ios.SharesCell)
|
||||
{
|
||||
var actorSubCell = editorLayer.FreeSubCellAt(location);
|
||||
if (actorSubCell != SubCell.Invalid)
|
||||
preview.ReplaceInit(new SubCellInit(actorSubCell));
|
||||
}
|
||||
|
||||
preview.UpdateFromMove();
|
||||
editorLayer.Add(preview);
|
||||
}
|
||||
|
||||
public int SetTerrainTemplate(WorldRenderer wr, TerrainTemplateInfo template)
|
||||
{
|
||||
terrainOrResourceCell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos));
|
||||
|
||||
@@ -810,6 +810,7 @@ notification-selected-actor = Selected actor { $id }
|
||||
notification-cleared-selection = Cleared selection
|
||||
notification-removed-actor = Removed { $name } ({ $id })
|
||||
notification-removed-resource = Removed { $type }
|
||||
notification-moved-actor = Moved { $id } from { $x1 },{ $y1 } to { $x2 },{ $y2 }
|
||||
|
||||
## EditorResourceBrush
|
||||
notification-added-resource =
|
||||
|
||||
Reference in New Issue
Block a user