Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Atelier on Sat 22/10/2011 15:13:32

Title: Mapping a Network of Locations [SOLVED]
Post by: Atelier on Sat 22/10/2011 15:13:32
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? :/
Title: Re: Mapping a Network of Locations
Post by: pcj on Sat 22/10/2011 16:06:45
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.
Title: Re: Mapping a Network of Locations
Post by: Calin Leafshade on Sat 22/10/2011 16:33:27
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.

Title: Re: Mapping a Network of Locations
Post by: Khris on Sat 22/10/2011 17:13:01
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.
Title: Re: Mapping a Network of Locations
Post by: Calin Leafshade on Sat 22/10/2011 17:14:59
AGS has a limit on the call stack though and i dont think its very large.
Title: Re: Mapping a Network of Locations
Post by: Atelier on Sat 22/10/2011 22:59:53
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
Title: Re: Mapping a Network of Locations
Post by: Atelier on Mon 24/10/2011 15:55:51
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)
Title: Re: Mapping a Network of Locations [SOLVED]
Post by: Khris on Mon 24/10/2011 16:47:17
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.)