simulated function float getXY(Canvas C, vector location, out int screenX, out int screenY) {
local vector X, Y, Z, CamLoc, TargetDir, Dir, XY;
local rotator CamRot;
local Actor Camera;
local float TanFOVx, TanFOVy;
local float ret;
C.ViewPort.Actor.PlayerCalcView(Camera, CamLoc, CamRot);
TanFOVx = Tan(C.ViewPort.Actor.FOVAngle / 114.591559); // 360/Pi = 114.5915590...
TanFOVy = (C.ClipY / C.ClipX) * TanFOVx;
GetAxes(CamRot, X, Y, Z);
TargetDir = Location - CamLoc;
ret = X dot TargetDir;
if (ret > 0) {
Dir = X * (X dot TargetDir);
XY = TargetDir - Dir;
screenX = C.ClipX * 0.5 * (1.0 + (XY dot Y) / (VSize(Dir) * TanFOVx));
screenY = C.ClipY * 0.5 * (1.0 - (XY dot Z) / (VSize(Dir) * TanFOVy));
}
return ret;
}
if return value (which is projection of vector from camera to desired point to line of view) less or equal zero, then point behind camera and coordinates can not set.
simulated function DrawTextClipped(Canvas C, int X, int Y, string text, Color outline) {
local Color old;
old = C.DrawColor;
C.DrawColor = outline;
C.SetPos(X - 1, Y - 1);
C.DrawTextClipped(text, False);
C.SetPos(X + 1, Y + 1);
C.DrawTextClipped(text, False);
C.SetPos(X - 1, Y + 1);
C.DrawTextClipped(text, False);
C.SetPos(X + 1, Y - 1);
C.DrawTextClipped(text, False);
C.DrawColor = old;
C.SetPos(X, Y);
C.DrawTextClipped(text, False);
}
Slow! Don't use often. Better use another approach.
simulated function DrawLine(Canvas Canvas, int x1, int y1, int x2, int y2) {
const PenTex = Texture'UWindow.WhiteTexture';
local int i, j, n, dx, dy;
if (x1 == 0 && y1 == 0) return;
if (x2 == 0 && y2 == 0) return;
dx = x2 - x1;
dy = y2 - y1;
if (Abs(dx) > Abs(dy)) {
if (dx == 0) return;
if (dx > 0) j = 1; else j = -1;
n = Min(Canvas.ClipX, Max(0, x2));
i = Min(Canvas.ClipX, Max(0, x1));
if (i != n)
do {
canvas.CurX = i;
canvas.CurY = y1 + dy*(i - x1)/dx;
canvas.DrawTile(PenTex, 1, 1, 0, 0, PenTex.USize, PenTex.VSize);
i += j;
} until (i == n);
} else {
if (dy == 0) return;
if (dy > 0) j = 1; else j = -1;
n = Min(Canvas.ClipY, Max(0, y2));
i = Min(Canvas.ClipY, Max(0, y1));
if (i != n)
do {
canvas.CurX = x1 + dx*(i - y1)/dy;
canvas.CurY = i;
canvas.DrawTile(PenTex, 1, 1, 0, 0, PenTex.USize, PenTex.VSize);
i += j;
} until (i == n);
}
}
simulated function string getVal(Actor actor, string prop) {
local string ret;
Root.Console.ViewPort.Actor.MyHUD.Role = actor.Role; // hack for avoid Enum set issues, here always ROLE_Authority before that
actor.Role = actor.ENetRole.ROLE_Authority;
ret = actor.GetPropertyText(prop);
actor.Role = Root.Console.ViewPort.Actor.MyHUD.Role;
Root.Console.ViewPort.Actor.MyHUD.Role = actor.ENetRole.ROLE_Authority;
return ret;
}
Taken from http://www.unreal.ut-files.com/3DEditing/Tutorials/unrealwiki-offline/quicksort.html
And optimized for usage with CoopTranslocator but can be easly modified for your needs:
// http://www.unreal.ut-files.com/3DEditing/Tutorials/unrealwiki-offline/quicksort.html
static Function SortPlayers(CoopTranslocator trans, Int Low, Int High) { //Sortage
// low is the lower index, high is the upper index
// of the region of array a that is to be sorted
local Int i,j;
local String x;
Local Pawn tmp;
i = Low;
j = High;
x = trans.player[(Low+High)/2].PlayerReplicationInfo.PlayerName;
do { // partition
while (trans.player[i].PlayerReplicationInfo.PlayerName < x) i += 1;
while (trans.player[j].PlayerReplicationInfo.PlayerName > x) j -= 1;
if (i <= j) {
tmp = trans.player[j];
trans.player[j] = trans.player[i];
trans.player[i] = tmp;
i += 1;
j -= 1;
}
} until (i > j);
// recursion
if (low < j) SortPlayers(trans, low, j);
if (i < high) SortPlayers(trans, i, high);
}
Replace first occurrence of substring with another substring. Useful for make placeholders in messages.
static function string Replace(coerce string source, coerce string search, coerce string replace) {
var int pos;
pos = InStr(source, search);
if (pos >= 0) {
source = Left(source, pos) $ replace $ Mid(source, pos + Len(search));
}
return source;
}
simulated function DrawLine3D( Canvas C, vector P1, vector P2, float R, float G, float B ) {
local int x1, y1, x2, y2;
local float a1, a2;
a1 = getXY(C, P1, x1, y1);
a2 = getXY(C, P2, x2, y2);
if (a1 <= 0 && a2 <= 0) return;
if (a1 <= 0) {
P1 -= P2;
P1 *= a2/(a2 - a1);
P1 -= Normal(P1);
P1 += P2;
getXY(C, P1, x1, y1);
} else if (a2 <= 0) {
P2 -= P1;
P2 *= a1/(a1 - a2);
P2 -= Normal(P2);
P2 += P1;
getXY(C, P2, x2, y2);
}
if (R >= 0)
SetColor(C, R, G, B);
DrawLine(C, x1, y1, x2, y2);
}
Nice! I recently noticed that the way the Redeemer's altfire calculates screen co-ords to draw the red crosshair by players is a bit off (see here), and I wondered if it was deliberate - but your equivalent (
getXY
) is absolutely spot-on 👍