I need help again ;)
Each location in my game can have four exits... north east south and west.
loc[1].nor = 2;
loc[2].sou = 1;
loc[3].eas = 4;
loc[4].wes = 3;
In this fashion they are all interlinked.
Now, say I want to generate a physical map of the location network. I need some kind of formula to position components on a drawing surface. The result would look something like this:
(http://i.imgur.com/ZTM9u.png)
As an aside, the generated map doesn't need long line connectors, only short ones like between the green star and tavern. Here's what I've come up with so far, but it's not ideal:
//Map Components
//Squares
//'you are here' square - 12x12, slot 10
//plain square - 12x12, slot 7
//tavern square...
//stable square...
//Connectors
//1 vertical line - 4x6, slot 8
//1 horizontal line - 6x4, slot 9
DynamicSprite *sprite;
DrawingSurface *surface;
function GenerateMap()
{
sprite = DynamicSprite.CreateFromExistingSprite(Map.Graphic); //Map.Graphic is 162x112, and invisible
surface = sprite.GetDrawingSurface(); surface.Clear();
int x = (Map.Width/2)-6, //find the centre point and -6, because 1 square is 12x12 so it must span the centre
y = (Map.Height/2)-6;
surface.DrawImage(x, y, 10); //mob[0] is the player. draw their location.
if (loc[mob[0].loc].nor != 0) { //ie, there is an exit to the north
surface.DrawImage(x, y-18, 7); //draw a plain square
surface.DrawImage(x+4, y-6, 9); //draw a line connecting the two
}
if (loc[mob[0].loc].eas != 0) {
surface.DrawImage(x+18, y, 7);
surface.DrawImage(x+12, y+4, 8);
}
if (loc[mob[0].loc].sou != 0) {
surface.DrawImage(x, y+18, 7);
surface.DrawImage(x+4, y+12, 9);
}
if (loc[mob[0].loc].wes != 0) {
surface.DrawImage(x-18, y, 7);
surface.DrawImage(x-6, y+4, 8);
}
surface.Release();
Map.NormalGraphic = sprite.Graphic;
}
As I say, it's pretty useless because it only draws the direct satellite locations of the current location. What I need to do is get the satellite locations of the satellite locations of the satellite locations... etc. In this way I create a map of the network, with the current location in the centre.
I would need some kind of concatanating sequence:
if (loc[mob[0].loc].nor != 0) //draw
if (loc[loc[mob[0].loc].nor].nor != 0) //draw
if (loc[loc[loc[mob[0].loc].nor].nor].nor != 0) //draw
But this would be ridiculous, especially as there are 100s of locations. Any ideas for alternatives? :/
Sounds like you need a loop rather than appending more iterations of the array. Continue through the loop until there are no more exits.
Also, pretty sure this isn't a beginner question.
This is essentially a version of A* pathfinding.
You basically add nodes to a list and iterate through the list, removing checked nodes until you are left with nodes that have no exits.
You *will* need long connectors because your locations are not stored on a grid (if they are, then that would make life much easier because you can just use a 2D array) If you dont use long connectors then you will get clashes between adjacent compass points like this:
X - - A - - X
| |
B - - *
The node at the star is both south of A and east of B which causes a conflict.
I'd use recursion. In other words, drawing one location includes drawing all adjacent locations except the one that called it.
pseudovoid draw(int location, int skip_location)
if (location isnt_drawn) {
draw location;
mark location as drawn;
loop through adjacent_locations {
if (adjacent_location != skip_location) draw(adjacent_location, location);
}
}
}
This should draw all locations connected to the current one.
AGS has a limit on the call stack though and i dont think its very large.
Quote from: Calin Leafshade on Sat 22/10/2011 16:33:27
The node at the star is both south of A and east of B which causes a conflict.
I have multiple instances of that. Many locations are connected to two or more locations. Does this mean the solution is easier or harder?
Quote from: pcj on Sat 22/10/2011 16:06:45Also, pretty sure this isn't a beginner question.
I forget I'm not a beginner anymore :P
I managed to do it in the end, by assigning locations an x and y coordinate. I'll post the code for anyone who finds it useful.
DynamicSprite *sprite;
DrawingSurface *surface;
function GenerateMap()
{
sprite = DynamicSprite.CreateFromExistingSprite(Map.Graphic);
surface = sprite.GetDrawingSurface(); surface.Clear();
int x = (Map.Width/2)-6,
y = (Map.Height/2)-6,
i = 1, square;
while (i < Max_Locs) {
if (loc[i].name != null) { //ie, room has been defined
int xdraw, ydraw;
if (loc[i].x < loc[mob[o].loc].x) xdraw = x-(loc[mob[0].loc].x-loc[i].x)*19;
else if (loc[mob[0].loc].x < loc[i].x) xdraw = x+(loc[i].x-loc[mob[0].loc].x)*19;
else if (loc[mob[0].loc].x == loc[i].x) xdraw = x;
if (loc[i].y < loc[mob[0].loc].y) ydraw = y+(loc[mob[0].loc].y-loc[i].y)*19;
else if (loc[mob[o].loc].y < loc[i].y) ydraw = y-(loc[i].y-loc[mob[0].loc].y)*19;
else if (loc[mob[0].loc].y == loc[i].y) ydraw = y;
if (loc[i].type == eLocTavern) square == 11;
else if (loc[i].type == eLocTravel) square == 12;
// ...
else square = 7;
surface.DrawImage(xdraw, ydraw, square);
if (loc[i].nor) surface.DrawImage(xdraw+4, ydraw-6, 9);
if (loc[i].eas) surface.DrawImage(xdraw+13, ydraw+4, 8);
if (loc[i].sou) surface.DrawImage(xdraw+4, ydraw+13, 9);
if (loc[i].wes) surface.DrawImage(xdraw-6, ydraw+4, 8);
}
i++;
}
surface.DrawPixel(x+6, y+6);
surface.Release();
// Save the image to a file
//sprite.Resize(500, 500);
//sprite.SaveToFile("mapoverview.bmp");
Map.NormalGraphic = sprite.Graphic;
}
Here's just a small test map it generated. Lots of potential!
(http://i.imgur.com/aLEnE.png)
A small suggestion regarding this part:
if (loc[i].type == eLocTavern) square == 11;
else if (loc[i].type == eLocTravel) square == 12;
// ...
else square = 7;
enums are handled as ints, you can even redefine the values. By default, the first enum member is 1, the second is 2 etc.
So you should be able to do:
square = loc[i].type + 10;
(Assuming that the sprites are ordered in the same way as the enum members.)