[Resolved] RMXP Blizz ABS Enemy Seeing Through Walls

Started by CriticalHit, April 24, 2020, 10:28:33 pm

Previous topic - Next topic

CriticalHit

April 24, 2020, 10:28:33 pm Last Edit: April 30, 2020, 01:54:41 pm by CriticalHit
Hi,

I am developing a game using RPG Maker XP with Blizz ABS that relies on stealth. I've noticed that enemies see through walls sometimes even though I set up the wall terrain tag on the tile they are seeing through. They only seem to see through walls at certain points which is very odd and I can't account for it.
I made a test project with a clean copy of RMXP and Blizz ABS and experience the same odd seeing through walls issue.I put this project in a Github repository to demonstrate my issue:
https://github.com/antlaw0/Test-Project
The enemy detects the player on the spots on the ground where I put grass.
How can I make the enemy not see through walls?

Thank you

KK20

April 25, 2020, 02:06:14 am #1 Last Edit: April 25, 2020, 02:09:34 am by KK20
Good job finding this bug. There is definitely something wrong with the wall algorithm:
    #--------------------------------------------------------------------------
    # wall?
    #  char - the character
    #  x    - x-coordinate
    #  y    - y-coordinate
    #  Checks if between the char and the target is a "wall". Walls prevent
    #  perception.
    #--------------------------------------------------------------------------
    def wall?(char, x, y)
      # abort instantly if not using this option
      return false if Config::WALL_TAGS.size == 0
      # get pixel movement rate
      pix = $BlizzABS.pixel
      # get coordinate difference
      dx, dy = (x-char.x)/pix, (y-char.y)/pix
      # if x difference is not 0 and x difference is greater
      if dx != 0 && dx.abs > dy.abs
        # return any wall tile between
        return (0..dx.abs).any? {|i| Config::WALL_TAGS.include?($game_map.
            terrain_tag(char.x/pix+dx.sgn*i, char.y/pix+(i.to_f*dy/dx).round))}
      # if y difference is not 0 and y difference is greater
      elsif dy != 0 && dy.abs > dx.abs
        # return any wall tile between
        return (0..dy.abs).any? {|i| Config::WALL_TAGS.include?($game_map.
            terrain_tag(char.x/pix+(i.to_f*dx/dy).round, char.y/pix+dy.sgn*i))}
      end
      # no wall between
      return false
    end
For the bottom right corner in your demo, the (dx, dy) is (3, 3). Because dx == dy, the two if-statements are ignored, and the method returns false.

For the bottom left area, we're running through this part of the method:
        # return any wall tile between
        return (0..dx.abs).any? {|i| Config::WALL_TAGS.include?($game_map.
            terrain_tag(char.x/pix+dx.sgn*i, char.y/pix+(i.to_f*dy/dx).round))}
The problem is that, as the loop iterates, it is checking the tile to the left and UP, starting from the enemy's position.
Your event is at (9, 7). When i = 1, it checks if tile (8, 6) is a wall, which it isn't. It should be checking (8, 8 ) instead.

Not currently in a position to fix it, but letting you know why it's behaving that way.

Other Projects
RPG Maker XP Ace  Upgrade RMXP to RMVXA performance!
XPA Tilemap  Tilemap rewrite with many features, including custom resolution!

Nintendo Switch Friend Code: 8310-1917-5318
Discord: KK20 Tyler#8901

Join the CP Discord Server!

winkio

replacing the method with this one should fix it, but I haven't tested it
    #--------------------------------------------------------------------------
    # wall?
    #  char - the character
    #  x    - x-coordinate
    #  y    - y-coordinate
    #  Checks if between the char and the target is a "wall". Walls prevent
    #  perception.
    #--------------------------------------------------------------------------
    def wall?(char, x, y)
      # abort instantly if not using this option
      return false if Config::WALL_TAGS.size == 0
      # get pixel movement rate
      pix = $BlizzABS.pixel
      # get coordinate difference
      dx, dy = (x-char.x)/pix, (y-char.y)/pix
      # if x difference is not 0 and x difference is greater
      if dx != 0 && dx.abs >= dy.abs
        # return any wall tile between
        return (0..dx.abs).any? {|i| Config::WALL_TAGS.include?($game_map.
            terrain_tag(char.x/pix+dx.sgn*i, char.y/pix+(i.to_f*dy/dx.abs).round))}
      # if y difference is not 0 and y difference is greater
      elsif dy != 0 && dy.abs > dx.abs
        # return any wall tile between
        return (0..dy.abs).any? {|i| Config::WALL_TAGS.include?($game_map.
            terrain_tag(char.x/pix+(i.to_f*dx/dy.abs).round, char.y/pix+dy.sgn*i))}
      end
      # no wall between
      return false
    end

I made the first if block use >= instead of >, and then for the slopes used the absolute value of the denominator so that the signs would match correctly.

CriticalHit

Thanks for the response. I replaced the method with the code you posted and it works fine so far- enemies are not detecting the player on the sections of grass any more.
My plan is to implement this new method into my game and test it more thoroughly over the next couple of days before marking this issue as resolved.