Help simplifying an unwieldy graphics function as for dungeon crawler

Started by newwaveburritos, Thu 06/10/2022 20:37:38

Previous topic - Next topic

newwaveburritos

I'm trying to write some script that renders a first person dungeon crawler screen and while I think this would work I don't really believe it's the simplest way to do it but also I can't think of a better way to do it rather than just brute force.

Code: ags
function renderVisionCone()
{
  if (playerChar.faceDir==eFaceUp){
    
    clearScreen();
    MazeType tile0 = GetCell(playerChar.x-2, playerChar.y-3);
    if (tile0==eMazeWall){
      DynamicSprite.Create(620, 400);
      DrawingSurface *dungeonWalls = Room.GetDrawingSurfaceForBackground();
      dungeonWalls.DrawImage(0, 0, BACK_LEFT);    
      dungeonWalls.Release();
    }
  
    MazeType tile1 = GetCell(playerChar.x-1, playerChar.y-3);
    if (tile1==eMazeWall){
      DynamicSprite.Create(620, 400);
      DrawingSurface *dungeonWalls = Room.GetDrawingSurfaceForBackground();
      dungeonWalls.DrawImage(0, 0, BACK_MIDDLE_LEFT);    
      dungeonWalls.Release();
    }
  
    MazeType tile2 = GetCell(playerChar.x, playerChar.y-3);
    if (tile2==eMazeWall){
      DynamicSprite.Create(620, 400);
      DrawingSurface *dungeonWalls = Room.GetDrawingSurfaceForBackground();
      dungeonWalls.DrawImage(0, 0, BACK_MIDDLE);    
      dungeonWalls.Release();
    }
    
    //MazeType tile3...
    //this times ten plus one more for each cardinal direction == bad times.
    
  }
  
}

EDIT: I realize now I have my coordinates incorrect but I don't think that really affects the concept too much.
EDIT EDIT: I fixed the coordinates.  I was think there were only 10 tiles I needed to render but there are actually 13.

newwaveburritos

Okay, this is already a lot better but I think if I arrange the sprites in the order that I need to populate them then I can iterate through them or something like that.

Code: ags
function renderVisionCone()  //draws the walls
{
 clearScreen();
 DynamicSprite.Create(620, 400);
 DrawingSurface *dungeonWalls = Room.GetDrawingSurfaceForBackground();
 
      
  if (playerChar.faceDir==eFaceUp){
    
    
    MazeType tile0 = GetCell(playerChar.x-2, playerChar.y-2);
    if (tile0==eMazeWall){
      dungeonWalls.DrawImage(0, 0, 18);    
    }
  
    MazeType tile1 = GetCell(playerChar.x-1, playerChar.y-2);
    if (tile1==eMazeWall){
      dungeonWalls.DrawImage(0, 0, 12);    
    }
  
    MazeType tile2 = GetCell(playerChar.x, playerChar.y-2);
    if (tile2==eMazeWall){
      dungeonWalls.DrawImage(0, 0, 4);    

    }
    
    //MazeType tile3...
    //this times ten plus one more for each cardinal direction == bad times.
    
  }
  
}

eri0o

Made one first person dungeon crawler open source in gh here, is the specific maze renderer: https://github.com/ericoporto/galleys/blob/main/DungeonCraw/MazeRenderer.asc

The algorithm/original code is not mine, the game/assets were posted on Open Game Art and I picked up from there. Perhaps it could be useful as inspiration.


newwaveburritos

Quote from: eri0o on Thu 06/10/2022 21:48:14Made one first person dungeon crawler open source in gh here, is the specific maze renderer: https://github.com/ericoporto/galleys/blob/main/DungeonCraw/MazeRenderer.asc

The algorithm/original code is not mine, the game/assets were posted on Open Game Art and I picked up from there. Perhaps it could be useful as inspiration.



Lol, I had no idea such a thing existed.  I've already gotten the pathfinding figured out.  But it was a really good exercise in coding since I felt out of my depth the whole time.  This will surely be useful in my endeavors, though, so thanks! EDIT: @eri0o Oh, and there was a comment in there that really saved my bacon.  Draw order is important and I wouldn't have realized that for a long time!!

newwaveburritos

Dang, I tried to post the whole monster function and it's so long that it gets caught in the spam filter.  :-\

Khris

You can put it on pastebin and post the link.

When I did this last, I used an array of coordinate offsets: [-2, -2], [-1, -2], etc. (in AGScript you can use an array of points for this).
Next I would rotate a copy according to the direction; a 90° rotation means swapping x and y and either x's or y's sign.
A 180° rotation is easier: swap both x's and y's sign.

Then I'd iterate over the rotated offset array and add it to the player position to get the grid coordinate.

newwaveburritos

Here's the link.

@Khris Some of that should look a little familiar as I was using a lot of what you explained last time you posted about this.

Khris

Here's the offset rotation method:

Code: ags
int wallSprites[15];

function game_start() {
  /* wall sprites, 3 rows and 5 columns (eFaceUp)
      14 10  9  3 13
       0  8  2  7  0
       0  6  X  5  0
  */
  wallSprites[0] = 14; wallSprites[1] = 10; wallSprites[2] = 9; wallSprites[3] = 3; wallSprites[4] = 13; 
  wallSprites[6] = 8; wallSprites[7] = 2; wallSprites[8] = 7; wallSprites[11] = 6; wallSprites[13] = 5;
}

int[] rOffset(int x, int y, Direction dir) {
  int r[] = new int[2];
  if (dir == eDirUp) { r[0] = x; r[1] = y; }  
  if (dir == eDirDown) { r[0] = -x; r[1] = -y; }  
  if (dir == eDirLeft) { r[0] = y; r[1] = -x; }  
  if (dir == eDirRight) { r[0] = -y; r[1] = x; }  
  return r;
}

function renderVisionCone() //draws the walls
{
  clearScreen();
  DrawingSurface * dungeonWalls = Room.GetDrawingSurfaceForBackground();

  // iterate over cone
  for (int y = -2; y <= 0; y++) {
    for (int x = -2; x <= 0; x++) {
      // rotate offset to find correct cell
      int ro[];
      MazeType mt;
      int sprite;
      ro = rOffset(x, y, playerChar.faceDir);
      mt = GetCell(playerChar.x + ro[0], playerChar.y + ro[1]);
      if (mt == eMazeWall) {
        sprite = wallSprites[(y + 2) * 5 + (x + 2)];
        if (sprite > 0) dungeonWalls.DrawImage(0, 0, sprite);
      }
      if (x < 0) {
        ro = rOffset(-x, y, playerChar.faceDir);
        mt = GetCell(playerChar.x + ro[0], playerChar.y + ro[1]);
        if (mt == eMazeWall) {
          sprite = wallSprites[(y + 2) * 5 + (-x + 2)];
          if (sprite > 0) dungeonWalls.DrawImage(0, 0, sprite);
        }
      }
    }
  }
}

(Probably a bunch of typos in there)

edit: fixed renderVisionCone()

newwaveburritos

Actually, it worked with very little editing.  One problem is that I think the iterating has to be done out of order or you end up with part of a wall in front. The other part where there's a wall where there shouldn't be I can't really explain.

Video
Full code

Thanks for the help, though!

EDIT: I think I see how to fix the first bit by assigning the sprites to the wallSprites array in a different order.
EDIT EDIT: Sprites 3 and 9 were transposed in the assignment which solves the second part.  Fooling with the order they are assigned is giving very curious results, though.  I should also note that the fact that you figured out which sprite is which based on that meandering function is pretty astonishing.

Khris

My code is supposed to draw from far to near but let me check my code and get back to you.

newwaveburritos

Quote from: Khris on Fri 07/10/2022 17:50:52My code is supposed to draw from far to near but let me check my code and get back to you.

It does do that but this comment from Eri0o's code helped me with the order:

/**
The visibility cone is shaped like this:
 
.........
..VVVVV..
..VVVVV..
...V@V...
.........
Drawing is done in this order (a=10, b=11, c=12)
.........
..02431..
..57986..
...acb...
.........
*/

Khris

You're right, I forgot to draw the outer walls first. Fixed the cone code.


SMF spam blocked by CleanTalk