Easier actor selection in game by actor bounds center
This commit is contained in:
@@ -37,23 +37,26 @@ namespace OpenRA.Orders
|
||||
public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button)
|
||||
: this(new Actor[] { subject }, order, cursor, button) { }
|
||||
|
||||
public override IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
public override IEnumerable<Order> Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
if (mi.Button != ExpectedButton)
|
||||
world.CancelInputMode();
|
||||
return OrderInner(world, xy, mi);
|
||||
return OrderInner(world, cell, mi);
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<Order> OrderInner(World world, CPos xy, MouseInput mi)
|
||||
protected virtual IEnumerable<Order> OrderInner(World world, CPos cell, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == ExpectedButton && world.Map.Contains(xy))
|
||||
if (mi.Button == ExpectedButton && world.Map.Contains(cell))
|
||||
{
|
||||
world.CancelInputMode();
|
||||
foreach (var subject in Subjects)
|
||||
yield return new Order(OrderName, subject, false) { TargetLocation = xy };
|
||||
yield return new Order(OrderName, subject, false) { TargetLocation = cell };
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? Cursor : "generic-blocked"; }
|
||||
public override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
return world.Map.Contains(cell) ? Cursor : "generic-blocked";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace OpenRA
|
||||
{
|
||||
public interface IOrderGenerator
|
||||
{
|
||||
IEnumerable<Order> Order(World world, CPos xy, MouseInput mi);
|
||||
IEnumerable<Order> Order(World world, CPos cell, int2 worldPixel, MouseInput mi);
|
||||
void Tick(World world);
|
||||
IEnumerable<IRenderable> Render(WorldRenderer wr, World world);
|
||||
IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world);
|
||||
string GetCursor(World world, CPos xy, MouseInput mi);
|
||||
string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,31 +17,31 @@ namespace OpenRA.Orders
|
||||
{
|
||||
public class UnitOrderGenerator : IOrderGenerator
|
||||
{
|
||||
static Target TargetForInput(World world, CPos xy, MouseInput mi)
|
||||
static Target TargetForInput(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
var actor = world.ScreenMap.ActorsAt(mi)
|
||||
.Where(a => !world.FogObscures(a) && a.Info.HasTraitInfo<ITargetableInfo>())
|
||||
.WithHighestSelectionPriority();
|
||||
.WithHighestSelectionPriority(worldPixel);
|
||||
|
||||
if (actor != null)
|
||||
return Target.FromActor(actor);
|
||||
|
||||
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, mi)
|
||||
.Where(a => a.Info.HasTraitInfo<ITargetableInfo>() && a.Visible && a.HasRenderables)
|
||||
.WithHighestSelectionPriority();
|
||||
.WithHighestSelectionPriority(worldPixel);
|
||||
|
||||
if (frozen != null)
|
||||
return Target.FromFrozenActor(frozen);
|
||||
|
||||
return Target.FromCell(world, xy);
|
||||
return Target.FromCell(world, cell);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Order> Order(World world, CPos xy, MouseInput mi)
|
||||
public virtual IEnumerable<Order> Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
var target = TargetForInput(world, xy, mi);
|
||||
var actorsAt = world.ActorMap.GetActorsAt(xy).ToList();
|
||||
var target = TargetForInput(world, cell, worldPixel, mi);
|
||||
var actorsAt = world.ActorMap.GetActorsAt(cell).ToList();
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, target, actorsAt, xy, mi))
|
||||
.Select(a => OrderForUnit(a, target, actorsAt, cell, mi))
|
||||
.Where(o => o != null)
|
||||
.ToList();
|
||||
|
||||
@@ -62,18 +62,18 @@ namespace OpenRA.Orders
|
||||
public virtual IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
|
||||
public virtual IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world) { yield break; }
|
||||
|
||||
public virtual string GetCursor(World world, CPos xy, MouseInput mi)
|
||||
public virtual string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
|
||||
{
|
||||
var useSelect = false;
|
||||
var target = TargetForInput(world, xy, mi);
|
||||
var actorsAt = world.ActorMap.GetActorsAt(xy).ToList();
|
||||
var target = TargetForInput(world, cell, worldPixel, mi);
|
||||
var actorsAt = world.ActorMap.GetActorsAt(cell).ToList();
|
||||
|
||||
if (target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo<SelectableInfo>() &&
|
||||
(mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
|
||||
useSelect = true;
|
||||
|
||||
var ordersWithCursor = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, target, actorsAt, xy, mi))
|
||||
.Select(a => OrderForUnit(a, target, actorsAt, cell, mi))
|
||||
.Where(o => o != null && o.Cursor != null);
|
||||
|
||||
var cursorOrder = ordersWithCursor.MaxByOrDefault(o => o.Order.OrderPriority);
|
||||
@@ -84,14 +84,14 @@ namespace OpenRA.Orders
|
||||
// Used for classic mouse orders, determines whether or not action at xy is move or select
|
||||
public static bool InputOverridesSelection(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
var actor = world.ScreenMap.ActorsAt(xy).WithHighestSelectionPriority();
|
||||
var actor = world.ScreenMap.ActorsAt(xy).WithHighestSelectionPriority(xy);
|
||||
if (actor == null)
|
||||
return true;
|
||||
|
||||
var target = Target.FromActor(actor);
|
||||
var cell = world.Map.CellContaining(target.CenterPosition);
|
||||
var actorsAt = world.ActorMap.GetActorsAt(cell).ToList();
|
||||
var underCursor = world.Selection.Actors.WithHighestSelectionPriority();
|
||||
var underCursor = world.Selection.Actors.WithHighestSelectionPriority(xy);
|
||||
|
||||
var o = OrderForUnit(underCursor, target, actorsAt, cell, mi);
|
||||
if (o != null && o.Order.OverrideSelection)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
@@ -43,14 +44,22 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public static Actor WithHighestSelectionPriority(this IEnumerable<Actor> actors)
|
||||
public static Actor WithHighestSelectionPriority(this IEnumerable<Actor> actors, int2 selectionPixel)
|
||||
{
|
||||
return actors.MaxByOrDefault(a => a.Info.SelectionPriority());
|
||||
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.Bounds, selectionPixel));
|
||||
}
|
||||
|
||||
public static FrozenActor WithHighestSelectionPriority(this IEnumerable<FrozenActor> actors)
|
||||
public static FrozenActor WithHighestSelectionPriority(this IEnumerable<FrozenActor> actors, int2 selectionPixel)
|
||||
{
|
||||
return actors.MaxByOrDefault(a => a.Info.SelectionPriority());
|
||||
return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Info, a.Bounds, selectionPixel));
|
||||
}
|
||||
|
||||
static long CalculateActorSelectionPriority(ActorInfo info, Rectangle bounds, int2 selectionPixel)
|
||||
{
|
||||
var centerPixel = new int2(bounds.X, bounds.Y);
|
||||
var pixelDistance = (centerPixel - selectionPixel).Length;
|
||||
|
||||
return ((long)-pixelDistance << 32) + info.SelectionPriority();
|
||||
}
|
||||
|
||||
static readonly Actor[] NoActors = { };
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace OpenRA.Widgets
|
||||
if (multiClick)
|
||||
{
|
||||
var unit = World.ScreenMap.ActorsAt(xy)
|
||||
.WithHighestSelectionPriority();
|
||||
.WithHighestSelectionPriority(xy);
|
||||
|
||||
if (unit != null && unit.Owner == (World.RenderPlayer ?? World.LocalPlayer))
|
||||
{
|
||||
@@ -193,7 +193,8 @@ namespace OpenRA.Widgets
|
||||
return;
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
var orders = world.OrderGenerator.Order(world, cell, mi).ToArray();
|
||||
var worldPixel = worldRenderer.Viewport.ViewToWorldPx(mi.Location);
|
||||
var orders = world.OrderGenerator.Order(world, cell, worldPixel, mi).ToArray();
|
||||
world.PlayVoiceForOrders(orders);
|
||||
|
||||
var flashed = false;
|
||||
@@ -231,6 +232,7 @@ namespace OpenRA.Widgets
|
||||
return null;
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(screenPos);
|
||||
var worldPixel = worldRenderer.Viewport.ViewToWorldPx(screenPos);
|
||||
|
||||
var mi = new MouseInput
|
||||
{
|
||||
@@ -239,7 +241,7 @@ namespace OpenRA.Widgets
|
||||
Modifiers = Game.GetModifierKeys()
|
||||
};
|
||||
|
||||
return World.OrderGenerator.GetCursor(World, cell, mi);
|
||||
return World.OrderGenerator.GetCursor(World, cell, worldPixel, mi);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user