SRL Archive - Research & Development Lounge

Sneak Peak: QuickWebWalk


Sir R. M8gic1an

2010-05-31 12:39:56


program QuickWebWalkSystem;
{
II | I
- - - - -
III | IV
}

const
MM_RADIUS = 5;

type
TTile = TPoint;

WDir = record
xL : boolean;
yL : boolean;
xH : boolean;
yH : boolean;
end;

WPoint = record //Walkable Point
WTile: TTile;
WP : TPoint; //To avoid precious ms loss in loops
Walkable: Boolean;
WalkD : WDir;
end;

var
WebWPoints: array of WPoint;
WebTPoints: TPointArray;

function Tile(x, y: integer): TTile;
begin
Result.x := x;
Result.y := y;
end;

function TileToPoint(T: TTile): TPoint;
begin
Result.x := T.x;
Result.y := T.y;
end;

function PointToTile(TP: TPoint): TTile;
begin
Result.x := TP.x;
Result.y := TP.y;
end;

procedure WriteTP(T: TPoint);
begin
writeln('TP: ('+IntToStr(T.x)+', '+IntToStr(T.y)+')');
end;

procedure LoadWPA;
begin
SetLength(WebWPoints, 3);
SetLength(WebTPoints, 3);

with WebWPoints[0] do
begin

WTile := Tile(0, 0);
WP := TileToPoint(WTile);
Walkable := true;

{This point connects W, N, E}
WalkD.xL := true;
WalkD.yL := true;
WalkD.xH := true;
WalkD.yH := false;
end;

with WebWPoints[1] do
begin

WTile := Tile(30, 25);
WP := TileToPoint(WTile);
Walkable := true;

{Bank only approachable from South-> North}
WalkD.xL := false;
WalkD.yL := true;
WalkD.xH := false;
WalkD.yH := false;
end;

with WebWPoints[2] do
begin

WTile := Tile(35, 27);
WP := TileToPoint(WTile);
Walkable := true;

{This point connects all}
WalkD.xL := true;
WalkD.yL := true;
WalkD.xH := true;
WalkD.yH := true;
end;
end;

function GetWebTPA: TPointArray;
var
i, t: integer;
begin
SetLength(Result, Length(WebWPoints));

t := High(WebWPoints);
for i := 0 to t do
Result[i] := WebWPoints[i].WP;

end;

function DirsToWDir(RxL, RyL, RxH, RyH: boolean): WDir;
begin
with Result do
begin
xL := RxL;
yL := RyL;
xH := RxH;
yH := RyH;
end;
end;

function TileToWP(T: TTile; Walk: boolean; WD: WDir): WPoint;
begin
with Result do
begin
WTile := T;
WP := TileToPoint(T);
Walkable := Walk;
WalkD := WD;
end;
end;

function GetWPoint(T: TTile): WPoint; //This will scan to find the closest walkable point
var
i, Pi, Dis, tDis, tot: integer;
begin
writeln('GetWPoint');
//Could be made faster if WebWPoints has a logic behind it
tot := High(WebTPoints);
Dis := 99999;
Pi := 0;

for i:= 0 to tot do
begin

tDis := Distance(T.x, T.y, WebTPoints[i].x, WebTPoints[i].y );
if tDis < Dis then
if WebWPoints[i].Walkable then
begin
Dis := tDis;
Pi := i;

if Dis = 0 then
break;

end;

end;

Result := WebWPoints[Pi];
writeln(Result.Walkable);
end;


function GetMiddlePoint(StartP, EndP: TPoint; angle: extended): TPoint;
begin
//So the angle can always be calculated in the same way
if StartP.x > EndP.x then
begin

if StartP.y > EndP.y then
begin
// Q II
angle := 90.0;
Result := Point(StartP.x, EndP.y);
end else begin
// Q III
angle := 180.0;
Result := Point(EndP.x, StartP.y);
end;

end else begin

if StartP.y > EndP.y then
begin
// Q IV
angle := 270.0;
Result := Point(EndP.x, StartP.y);
end else begin
// Q I
angle := 0.0;
Result := Point(StartP.x, EndP.y);
end;

end;
end;

function Approachable(SP: TPoint; EP: WPoint): boolean;
var
TP: TPoint;
begin
TP := EP.WP;

if abs(TP.x - SP.x) > abs(TP.y - SP.y) then
//sort by x
if TP.x > SP.x then
Result := EP.WalkD.xH
else
Result := EP.WalkD.xL
else
//sort by y
if TP.y > SP.y then
Result := EP.WalkD.yH
else
Result := EP.WalkD.yL;
end;

//Using the WebWalkArray, Returns TPoint of next Walkable Point
//Parts pretty much ripped off of Nielsie's RadialWalkEx
function TPA_RadialWalkEx(var NextP: TPoint; StartP, EndP: TPoint): boolean;
var
i, h, SD, ED, radius: Integer;
angle: extended;
tpa: TPointArray;
MPoint, TP: TPoint;
WP: WPoint;
begin

tpa := WebTPoints;

WP := GetWPoint(PointToTile(EndP));
TP := WP.WP;
writeTP(TP);

radius := Max(
Distance(StartP.x, StartP.y, EndP.x, EndP.y) + 10,
Distance(StartP.x, StartP.y, TP.x, TP.y) + 5
);

writeln('r');
writeln(radius);

MPoint := GetMiddlePoint(StartP, TP, angle);

writeln('no trig');
writeln(angle);

angle := angle + Cos( distance(StartP.x, StartP.y, MPoint.x, MPoint.y) /
distance(StartP.x, StartP.y, TP.x, TP.y)
);


writeln('angle');
writeln(angle);


SD := Round(angle - 22.0);
ED := Round(angle + 22.0);

while not Result do
begin
writeln('i: ' + IntToStr(i));
SD := SD - 5 * i;
ED := ED + 5 * i;
Radius := Radius + 5 * i;

SD := Trunc(FixD(SD + 0.0));
ED := Trunc(FixD(ED + 0.0));

try
tpa := GetWebTPA;
FilterPointsPie(tpa, SD, ED, MM_RADIUS, Radius, StartP.x, StartP.y);
SortCircleWise(tpa, StartP.x, StartP.y, SD, true, true);
Result := (Length(tpa) > 0);

except writeln('except'); end;

if Result then
begin
writeln('TPA length');
writeln(Length(TPA));
end else begin
inc(i);
continue;
writeln('continued');
end;


try
for h := 0 to High(tpa) do
begin
writeTP(TPA[h]);
WP := GetWPoint(PointToTile(tpa[h]));

if not WP.Walkable or
not Approachable(StartP, WP)
then
Result := false
else begin
NextP := TPA[h];
Result := true;
break;
end;

end;

except
writeln('Out of TPA range?');
Result := false;
end;



inc(i);
end;

end;

var
TP: TPoint;
begin
ClearDebug;
LoadWPA;
WebTPoints := GetWebTPA;
TPA_RadialWalkEx(TP, Point(0, 0), Point(20, 20));
writeln('Coords'); writeln(TP.x); writeln(TP.y);
end.



Well, this has some useless stuff in there for now, and is not exactly very reader friendly.

But here is a picture of what it will do:
The only real improvement of this compared to previous WebWalkSystems made here at SRL is the Non_Walkable point. It is not yet properly scripted. Here's how it will work:

Find straightest path between StartPoint and EndPoint;
Find Any NonWalkable Points in that path.
Find Alternative walk around NonWalkable point
Generate TTileArray with propper walk.

ATM it does not go around NonWalkable Points. It just avoids them. So it would've failed in the above picture.

Now, my question is this:

Should it follow the orange path, or the light blue path?

Orange path would probably mean walking through woods and so on.
Light blue path would mean longer walks, but walking through 'mapped' places.

~RM

Gu3st...

2010-05-31 12:46:47

Even though I don't use reflection, I would have preferred the orange path

EDIT: Timer made a similar system some time ago. He made Splines between the walkable points

Drakan

2010-05-31 12:49:04

I like using the orange path. Humans just go straight through (when they know the map well.) VERY nice RM! Keep it up.

marpis

2010-05-31 12:50:30

Make it choose a spline with random 1 or 2 curve points :) If the distance between the 2 last points is big enough, it'd be the best way to randomize walking path

Sir R. M8gic1an

2010-05-31 12:56:01

Another big plus of this is that points can only be approached from certain directions.

Eg, You'll be able to walk to the north wall of lumby castle from inside, But seen from the outside it is a non-walkable point.

~RM

JPHamlett

2010-05-31 20:07:06

Dang it lol I'm working on one as well lol

well gl to you my friend

weequ

2010-06-09 13:51:15

So if we make a database of all runescape tiles we could make a world walker? (no matter what starting location in runescape)

I think this is exatly what I have been thinking of doing to make my own game(whitch doesnt exist yet) get past unwalkabale objects… Sorry for my bad english.

Torrent of Flame

2010-06-09 15:01:23

Orange. Most people know shortcuts to get to where they want to go.

Coh3n

2010-06-09 18:12:46

Orange, and I was thinking of the EXACT same system a while back. Guess great minds think alike. ;)

Sir R. M8gic1an

2010-06-09 22:35:20

@mies
You wouldn't need a list of all tiles ;) Just tiles that affect direction. (Stop you from walking in any direction)

I guess that a non-walkable tile can always be added to the orange path if it for some reason fails.

About the splines, sure, but the 'main' points it walks through first need to be sorted out.

~RM

Hobbit

2010-06-09 23:43:57

I think the orange path would be better for another reason than just shorter walk… What legit player follows mapped points such as the road all the time and doesn't cut through forests? I why go around the forest for no apparent reason when you can go through it?

nickrules

2010-06-10 00:36:54

I would vote orange. I take the shortest route, unless its too dangerous, or just plain obnoxious, like a forest >_>

ape

2010-06-12 21:10:59

You could create a map of specific tiles that act as waypoints. You could store the tiles in an xml file with each point having specifics about neighbor tiles. Such as point A can be accessed from point B but not from point F. etc. Then you could just use an a* algorithm to find a path from a start point to any point on the map. It would be much simpler than having every world tile in a database. You could also add values to each waypoint, such as giving a shortcut point a lower value making it more prone to generating a path that utilizes a shortcut.

http://en.wikipedia.org/wiki/A-star

Boreas

2010-06-13 00:06:42

From: ape
You could create a map of specific tiles that act as waypoints. You could store the tiles in an xml file with each point having specifics about neighbor tiles. Such as point A can be accessed from point B but not from point F. etc. Then you could just use an a* algorithm to find a path from a start point to any point on the map. It would be much simpler than having every world tile in a database. You could also add values to each waypoint, such as giving a shortcut point a lower value making it more prone to generating a path that utilizes a shortcut.

http://en.wikipedia.org/wiki/A-star

+1 except with waypoints being tile boxes