Skip to content

How do i check for tiles around a specific tile?

An answer to this question on Stack Overflow.

Question

I'm making a game.

The game's world is represented by a tilemap. The tiles correspond to values in a 2D array.

I would like to use a special "corner" wall sprite if any three wall tiles make an L shape. That is,

V
##      #    >##
#      ##     #
        ^

The tiles indicated with arrows should be corner tiles.

I have the code to search for the wall but I don't know how to identify which tiles are the corner tiles.

My code is:

import pygame, sys
import Sprites
import random
from pygame.locals import *
pygame.init()
fpsClock = pygame.time.Clock()
cloudx = -200
cloudy = 0
infoObject = pygame.display.Info()
DIRT = 0
GRASS = 1
WATER = 2
COAL = 3
CLOUD = 4
WALL = 5
CWALL = 6
controls = {
    DIRT : 49,
    GRASS: 50,
    WATER: 51,
    COAL : 52,
    WALL : 53
}
infoObject = pygame.display.Info()
w = infoObject.current_w
h = infoObject.current_h
TILESIZE  = 40
MAPWIDTH  = 15
MAPHEIGHT = 15
WHITE = (255,255,255)
BLACK = (0,0,0)
resources = [DIRT, GRASS, WATER, COAL]
textures =  {
            DIRT  : pygame.image.load('Sprites/Dirt.png'),
            GRASS : pygame.image.load('Sprites/tile130.png'),
            WATER : pygame.image.load('Sprites/Water.png'),
            COAL  : pygame.image.load('Sprites/Coal.png'),
            CLOUD : pygame.image.load('Sprites/Cloud.png'),
            WALL  : pygame.image.load('Sprites/Swall.png'),
            CWALL : pygame.image.load('Sprites/Swall.png')
          }
playerPos = [0,0]
inventory = {
            DIRT   :  0,
            GRASS  :  0,
            WATER  :  0,
            COAL   :  0,
            WALL   :  10,
            }
tilemap = [[DIRT for w in range(MAPWIDTH)] for h in range(MAPHEIGHT)]
DISPLAYSURF = pygame.display.set_mode((MAPWIDTH*TILESIZE,MAPHEIGHT*TILESIZE + 50))
pygame.display.set_caption('M I N E C R A F T -- 2D')
pygame.display.set_icon(pygame.image.load('Sprites/player.png'))
PLAYER = pygame.image.load('Sprites/Player.png').convert_alpha()
for rw in range(MAPHEIGHT):
    for cl in range(MAPWIDTH):
        randomNumber = random.randint(0,15)
        if randomNumber == 0:
            tile = COAL
        elif randomNumber == 1 or randomNumber == 2:
            tile = WATER
        elif randomNumber >= 3 and randomNumber <=7:
            tile = GRASS
        else:
            tile = DIRT
        tilemap[rw][cl] = tile
INVFONT = pygame.font.Font('freesansbold.ttf', 18)
print(tilemap)
while True:
    currentTile = tilemap[playerPos[1]][playerPos[0]]
    DISPLAYSURF.fill(BLACK)
    for event in pygame.event.get():
#        print(event)
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            for key in controls:
                if (event.key == controls[key]):
                    if inventory[key] > 0:
                        inventory[key] -=1
                        inventory[currentTile] += 1
                        tilemap[playerPos[1]][playerPos[0]] = key
            if(event.key == K_RIGHT) and playerPos[0] < MAPWIDTH - 1:
                playerPos[0]+=1
            elif(event.key == K_LEFT) and playerPos[0] > 0:
                playerPos[0]-=1
            elif(event.key == K_DOWN) and playerPos[1] < MAPHEIGHT - 1:
                playerPos[1]+=1
            elif(event.key == K_UP) and playerPos[1] > 0:
                playerPos[1]-=1
            if event.key == K_SPACE:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                inventory[currentTile] += 1
                tilemap[playerPos[1]][playerPos[0]] = DIRT
    for row in range(MAPHEIGHT):
        for column in range(MAPWIDTH):
                DISPLAYSURF.blit(textures[tilemap[row][column]],(column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE))
                DISPLAYSURF.blit(PLAYER,(playerPos[0]*TILESIZE,playerPos[1]*TILESIZE))
    DISPLAYSURF.blit(textures[CLOUD].convert_alpha(),(cloudx,cloudy))
    cloudx +=1
    if cloudx > MAPWIDTH*TILESIZE:
        cloudy = random.randint(0, MAPHEIGHT*TILESIZE)
        cloudx = -200
    placePosition = 10
    for item in resources:
        DISPLAYSURF.blit(textures[item],(placePosition, MAPHEIGHT*TILESIZE+10))
        placePosition+=50
        textObj = INVFONT.render(str(inventory[item]), True, WHITE, BLACK)
        DISPLAYSURF.blit(textObj,(placePosition, MAPHEIGHT*TILESIZE+20))
        placePosition += 50
    pygame.display.update()
    fpsClock.tick(24)
    for x in range(MAPWIDTH):
        for y in range(MAPHEIGHT):
            if tilemap[x][y] == WALL:
                go_left = x > 1
                go_right = x < MAPWIDTH - 1
                go_up = y > 1
                go_down = y < MAPHEIGHT - 1
                if go_left:
                    tilemap[x - 1][y] = CWALL
                    if go_up:
                        pass
                if go_right:
                    tilemap[x + 1][y] = WALL 
                if go_up:
                    pass
                if go_down:
                    pass
                print('WALL')
    pygame.display.update()

And here are the links to the sprites: https://framadrop.org/r/fmReup_rTK#bMSywSUa7nxb1qL/a4FIbns+VaspgE0c/FU+9f1drHI=

https://framadrop.org/r/pBOfrnKcdT#eNEZQ9QjX5Cl6X4gH4UwdIg3eBPnY/L4WcSGYtUR5PE=

https://framadrop.org/r/ZFfTz_Lq9V#2Nd5ba1iE7miyFg8JpPFvwabAkdnHds/GfVkSAQeJaQ=

https://framadrop.org/r/gN9Y748L9G#Z552pPpgjTcSubt9tn74mZ0tT1COv7UCFdkUq2DorAU=

https://framadrop.org/r/d9k4hyCUni#OTza8UbsR8Am/R1PA9MAWkLDPRDBsT1rAHMgr61jusc=

https://framadrop.org/r/1mv777OR6d#pkqwaQrmVRElUPcdEV5K4UhmALsJSYX7z3WtrZXl4TE=

https://framadrop.org/r/CyF-tk7yUb#IFexcePe418JizElZzCJzDENTJPDfz7i1nr+lGns0rU=

https://framadrop.org/r/VzVfAz6bnL#oLHivyHPtTD8+IxliDD4yc+6LS9kpGyEp1HNFGUsBHo=

https://framadrop.org/r/0V0ShMH0uq#PZHdPSQNbgL7QqH2niwdS4HO34ZRMfIlhpvpRqbWwng=

Answer

I'd start by generating a set offsets

// 1
//0 2  Neighbour directions
// 3
//       0  1  2  3  Corresponding offsets
dx   = [-1, 0, 1, 0]
dy   = [0, -1, 0, 1]
Nmax = 4

Now, I can get the n-values of the neighbouring walls, like so:

nwalls = []
for n in range(Nmax):    #n is the direction of the neighbour
  #Ensure that the neighbour tile, identified as (x+dx[n], y+dy[n])
  #is in the map and check to see if it is a wall
  if 1<x+dx[n]<WIDTH and 1<y+dy[n]<HEIGHT and tilemap[x+dx[n]][y+dy[n]]==WALL:  
    nwalls.append(n) #Neighbour was a wall, add its direction to this list

Now, I can convert my list into a tile name:

#nwalls is a list of all the directions pointing to a wall
nwalls.sort()            #Sort list, e.g. 3,1,2 -> 1,2,3
nwalls = map(str,nwalls) #Convert from numbers to strings
nwalls = ''.join(nwalls) #Append strings together: ['1','2','3'] -> '123'
if nwalls:               #If the string is not empty
  nwalls = 'corner_tile_{0}.jpg'.format(nwalls) #Convert string to tile name

Now I just need a bunch of tiles named, e.g.:

corner_tile_01.jpg
corner_tile_013.jpg

Then I can say:

if nwalls: #Only true if this was a corner
  Code to display the tile whose name is stored in `nwalls`