gpt4 book ai didi

c# - xbox 性能陷阱

转载 作者:太空宇宙 更新时间:2023-11-03 16:44:57 34 4
gpt4 key购买 nike

背景:我有一款游戏,主要是在(低规范)笔记本电脑上进行测试。它运行良好。在 xbox 上进行测试时,有一种方法在调用时似乎会严重影响性能/fps。在 PC 上,您不会注意到任何减速/跳帧。

我在 xbox 上分析过,我平均每秒获得 1-2 次 GC,游戏运行时需要 20-40 毫秒。

当我的慢速方法运行时,我注意到 GC 率或持续时间没有变化。

接下来,我尝试在 PC 上进行分析,以确定该方法中花费最多时间的内容。原来它在做 List<T>.Contains() ,所以我创建了自己的类,它有一个 List<T>和一个 HashSet<T>在内部,所以我可以使用 HashSet<T>内部 Contains() .

我现在已经到了这样的地步,在不更改算法的情况下,我真的想不出还能调整什么,而且我认为该算法已经很简单了。

我知道我无法在 xbox 上获取方法时间/百分比,所以我对接下来要尝试的事情有点不知所措。

我包含了下面的代码,用于在基于图 block 的系统中模拟流水。它每个水格运行一次,试图将它向下移动可能穿过其他水格(一般来说)。

问题:我想知道我在这里是否做错了什么(即严重影响 xbox 性能)。正在调用Func慢吗?我可以用我的 Point 在任何地方打拳击吗?对象?等

对大量代码表示歉意! tiles 本身来自对象池以最小化 GC。 InternalThink()方法是导致所有问题的原因。

public abstract class TileFlowing : TileMovable
{
private FastList<Point> TeleportSwapLocations = new FastList<Point>();

private FastList<Point> PossibleMoveLocations = new FastList<Point>();

private FastQueue<Point> PositionsToCheck = new FastQueue<Point>();

private FastList<Point> PositionsChecked = new FastList<Point>();

private static Comparison<Point> _PossibleMoveComparer;

public bool Static = false;

protected abstract Func<Point, int> PossibleMoveLocationOrdering { get; }

protected abstract Func<Point, Point, bool, bool> MoveSidewaysFunc { get; }

protected abstract int MaxUnitsWithin { get; }

protected abstract int Weight { get; }

public int UnitsWithin;

public int AvailableToFlowThrough = 0;

protected virtual bool RecurseTilesUp { get { return true; } }
protected virtual bool RecurseTilesDown { get { return true; } }
protected virtual bool RecurseTilesLeft { get { return true; } }
protected virtual bool RecurseTilesRight { get { return true; } }

public TileFlowing()
: base()
{

}

public override void LoadContent(Components.TileGridManagement.GameGrid Owner)
{
base.LoadContent(Owner);

_PossibleMoveComparer = (Point P1, Point P2) =>
{
int Result = PossibleMoveLocationOrdering(P1) -
PossibleMoveLocationOrdering(P2);
if (Result == 0)
Result = (IsSameType(P1) ? (_Owner[P1] as TileFlowing).UnitsWithin : 0) -
(IsSameType(P2) ? (_Owner[P2] as TileFlowing).UnitsWithin : 0);

return Result;
};
}

public override void ResetProperties()
{
base.ResetProperties();

Static = false;
UnitsWithin = MaxUnitsWithin;
AvailableToFlowThrough = 0;
}

public override void CopyProperties(Tile SourceTile)
{
base.CopyProperties(SourceTile);

Static = (SourceTile as TileFlowing).Static;
UnitsWithin = (SourceTile as TileFlowing).UnitsWithin;
AvailableToFlowThrough = (SourceTile as TileFlowing).AvailableToFlowThrough;
}

public override void Think()
{
base.Think();

InternalThink(false, false);
}

public override void FactoryThink()
{
base.FactoryThink();

InternalThink(true, false);
}

public void FlowThink(bool CalledFromFactoryThink)
{
InternalThink(CalledFromFactoryThink, true);
}

private bool IsSameType(Point Position)
{
return IsSameType(Position.X, Position.Y);
}

private bool IsSameType(int X, int Y)
{
return _Owner[X, Y] != null && _Owner[X, Y].GetType() == GetType();
}

private bool IsDifferentFlowingTile(Point Position)
{
return IsDifferentFlowingTile(Position.X, Position.Y);
}

private bool IsDifferentFlowingTile(int X, int Y)
{
return !IsSameType(X, Y) && _Owner[X, Y] is TileFlowing;
}

protected void CheckPosition(Point PositionToCheck, Point TilePosition, bool CalledFromFactoryThink, bool CalledFromFlowThink,
ref FastList<Point> PossibleMoveLocations, ref FastList<Point> TeleportSwapLocations, ref FastQueue<Point> PositionsToCheck,
Func<Point, Point, bool, bool> ClearCheckFunc)
{
if (IsSameType(PositionToCheck))
{
if (!PositionsToCheck.Contains(PositionToCheck))
PositionsToCheck.Enqueue(PositionToCheck);
}
else if (_Owner[PositionToCheck] is TileFlowing && (ClearCheckFunc == null || ClearCheckFunc(PositionToCheck, TilePosition, CalledFromFactoryThink)))
{
// If we weigh more than the other tile, or we're called from the factory think (are under pressure)
if ((_Owner[PositionToCheck] as TileFlowing).Weight < Weight || CalledFromFactoryThink)
{
if (!(_Owner[PositionToCheck] as TileFlowing).Static || !CalledFromFlowThink)
PossibleMoveLocations.Add(PositionToCheck);
}
}
else if (_Owner.IsClear(PositionToCheck) && (ClearCheckFunc == null || ClearCheckFunc(PositionToCheck, TilePosition, CalledFromFactoryThink)))
{
PossibleMoveLocations.Add(PositionToCheck);
}
}

private int PossibleMoveLocationsComparer(Point P1, Point P2)
{
return (PossibleMoveLocationOrdering(P1) - PossibleMoveLocationOrdering(P2)) * 1000 +
((IsSameType(P1) ? (_Owner[P1] as TileFlowing).UnitsWithin : 0) - (IsSameType(P2) ? (_Owner[P2] as TileFlowing).UnitsWithin : 0)) * 100;
}

protected void InternalThink(bool CalledFromFactoryThink, bool CalledFromFlowThink)
{
AvailableToFlowThrough = 0;

TeleportSwapLocations.Clear();

PossibleMoveLocations.Clear();

PositionsToCheck.Clear();

PositionsChecked.Clear();

PositionsToCheck.Enqueue(Position);

while (PositionsToCheck.Count != 0)
{
Point PositionToCheck = PositionsToCheck.Dequeue();

if (!PositionsChecked.Contains(PositionToCheck) &&
((_Owner[PositionToCheck] as TileFlowing).AvailableToFlowThrough < MaxUnitsWithin || CalledFromFactoryThink))
{
if (((_Owner[PositionToCheck] as TileFlowing).Static && !CalledFromFactoryThink))
continue;

if (PositionToCheck != Position)
{
(_Owner[PositionToCheck] as TileFlowing).AvailableToFlowThrough++;
}

PositionsChecked.Add(PositionToCheck);

if ((_Owner[PositionToCheck] as TileFlowing).UnitsWithin < MaxUnitsWithin && PositionToCheck != Position)
{
PossibleMoveLocations.Add(PositionToCheck);

if (CalledFromFactoryThink && (_Owner[PositionToCheck] as TileFlowing).UnitsWithin + UnitsWithin <= MaxUnitsWithin)
continue;
}

// Check below
Point PosBelow = new Point(PositionToCheck.X + TileDirection.Down.X, PositionToCheck.Y + TileDirection.Down.Y);

CheckPosition(PosBelow, Position, CalledFromFactoryThink, CalledFromFlowThink, ref PossibleMoveLocations, ref TeleportSwapLocations, ref PositionsToCheck, null);

// Check one horizontal direction
Point RandHDir = Randomiser.GetHDirection();

Point RandHPos = new Point(RandHDir.X + PositionToCheck.X, RandHDir.Y + PositionToCheck.Y);

CheckPosition(RandHPos, Position, CalledFromFactoryThink, CalledFromFlowThink, ref PossibleMoveLocations, ref TeleportSwapLocations, ref PositionsToCheck, MoveSidewaysFunc);

// Check the other horizontal direction
Point OtherHDir = new Point(-RandHDir.X, RandHDir.Y);

Point OtherHPos = new Point(OtherHDir.X + PositionToCheck.X, OtherHDir.Y + PositionToCheck.Y);

CheckPosition(OtherHPos, Position, CalledFromFactoryThink, CalledFromFlowThink, ref PossibleMoveLocations, ref TeleportSwapLocations, ref PositionsToCheck, MoveSidewaysFunc);

// Check above if appropriate
Point AbovePos = new Point(PositionToCheck.X + TileDirection.Up.X, PositionToCheck.Y + TileDirection.Up.Y);

if (TileDirection.Below(AbovePos, Position) || CalledFromFactoryThink)
{
CheckPosition(AbovePos, Position, CalledFromFactoryThink, CalledFromFlowThink, ref PossibleMoveLocations, ref TeleportSwapLocations, ref PositionsToCheck, null);
}
}
}

PossibleMoveLocations.Sort(_PossibleMoveComparer);

bool Moved = false;

if (PossibleMoveLocations.Count != 0)
{
if (CalledFromFactoryThink)
{
while (UnitsWithin != 0 && PossibleMoveLocations.Count != 0)
{
int OldUnitsWithin = UnitsWithin;

Moved = IterateTeleport(CalledFromFactoryThink, ref PossibleMoveLocations, (P) => !IsDifferentFlowingTile(P), Moved);

if (UnitsWithin == OldUnitsWithin)
{
Moved = IterateTeleport(CalledFromFactoryThink, ref PossibleMoveLocations, (P) => IsDifferentFlowingTile(P), Moved);
}

PossibleMoveLocations.RemoveAll(P => IsSameType(P) && (_Owner[P] as TileFlowing).UnitsWithin == MaxUnitsWithin);
}
}
else
{
Moved = Moved || Teleport(PossibleMoveLocations[0]);
}

// If we did move and not because we were forced to then mark all mercury tiles above and left or right as not static.
if (!CalledFromFactoryThink)
{
_Owner.RecurseTiles(Position,
(P) => RecurseTilesUp && IsSameType(P.X + TileDirection.Up.X, P.Y + TileDirection.Up.Y),
(P) => RecurseTilesDown && IsSameType(P.X + TileDirection.Down.X, P.Y + TileDirection.Down.Y),
(P) => RecurseTilesLeft && IsSameType(P.X + TileDirection.Left.X, P.Y + TileDirection.Left.Y),
(P) => RecurseTilesRight && IsSameType(P.X + TileDirection.Right.X, P.Y + TileDirection.Right.Y),
(P) =>
{
if (IsSameType(P))
(_Owner[P] as TileFlowing).Static = false;
});
}
}
else
{
// Mark this tile as static if we didn't move, no water moved through this tile and we have all the units we can take.
Static = (AvailableToFlowThrough == 0) && (UnitsWithin == MaxUnitsWithin); // TODO: 9 Fix flowing tiles becoming static and getting stuck
}

if (!Moved)
{
// If we haven't moved
if (TeleportSwapLocations.Count != 0)
{
Moved = TeleportSwap(TeleportSwapLocations[0]);
}

if(!Moved)
{
// If we didn't move, undo checked tiles
foreach (var CheckedPosition in PositionsChecked)
{
(_Owner[CheckedPosition] as TileFlowing).AvailableToFlowThrough--;
}
}
}
}

private bool IterateTeleport(bool CalledFromFactoryThink, ref FastList<Point> SortedPossibleMoveLocations, Func<Point, bool> PossibleMoveLocationsFilter, bool Moved)
{
foreach (var PossibleMoveLocation in SortedPossibleMoveLocations)
{
if (PossibleMoveLocationsFilter(PossibleMoveLocation))
{
if (IsDifferentFlowingTile(PossibleMoveLocation))
{
bool OldStatic = Static;

Static = true;
(_Owner[PossibleMoveLocation] as TileFlowing).FlowThink(CalledFromFactoryThink);
Static = OldStatic;
}

bool TeleportResult = Teleport(PossibleMoveLocation);
Moved = Moved || TeleportResult;

if (TeleportResult)
break;
}
}
return Moved;
}

protected bool TeleportSwap(Point NewPosition)
{
TileFlowing OurNewTile = (TileFlowing)Tile.GetNewTileFromStore(this);
OurNewTile.CopyProperties(this);
OurNewTile.Position = NewPosition;

TileFlowing ReplacedTile = (TileFlowing)Tile.GetNewTileFromStore(_Owner[NewPosition]);
ReplacedTile.CopyProperties(_Owner[NewPosition]);
ReplacedTile.Position = Position;

_Owner.ClearTile(NewPosition);
_Owner.AddTileToGrid(OurNewTile);

_Owner.ClearTile(Position);
_Owner.AddTileToGrid(ReplacedTile);

UnitsWithin = 0;

return true;
}

protected bool Teleport(Point NewPosition)
{
if (IsDifferentFlowingTile(NewPosition))
{
return TeleportSwap(NewPosition);
}
else
{

TileFlowing NewTile;

bool RemovedAllUnits = false;

int NewPositionUnits = IsSameType(NewPosition) ? (_Owner[NewPosition] as TileFlowing).UnitsWithin : 0;

int UnitsToRemove = Math.Min(UnitsWithin,
Math.Max(1,
Math.Min(Math.Abs(UnitsWithin - NewPositionUnits) / 2,
MaxUnitsWithin - NewPositionUnits)));

UnitsWithin -= UnitsToRemove;

if (IsSameType(NewPosition))
{
(_Owner[NewPosition] as TileFlowing).UnitsWithin += UnitsToRemove;
}
else
{
NewTile = (TileFlowing)Tile.GetNewTileFromStore(this);

NewTile.Position = NewPosition;
NewTile.UnitsWithin = UnitsToRemove;

_Owner.AddTileToGrid(NewTile);
}

if (UnitsWithin == 0)
{
_Owner.ClearTile(Position);
RemovedAllUnits = true;
}

return RemovedAllUnits;
}
}
}

最佳答案

我认为您可以使用秒表 进行一些基本的分析。您可以考虑在 think 方法上设置毫秒或迭代“限制”- 这样它就不会花费超过 5 毫秒/200 次迭代或任何有效的方法。

关于c# - xbox 性能陷阱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6340381/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com