光线投射如何具有多个纹理?

时间:2018-12-16 23:14:53

标签: python pygame raycasting

我当时正在网上寻找python的射线广播,并决定调查一些已发布的代码;所以大部分不是我本来的代码我只想了解它的工作原理。

程序从读取文本文档开始运行其地图,每个文本文档均由“ 1”和空格组成,如下所示:

    11111111111111111
    1     11       11
    1 111 11 11 11 11
    1 1       1 11 11
    1 1 1       1  11
    1 1 111  11     1
    1 1      1111  11
    1   1  11   11 11
    1 1         1  11
    1 1    11   1  11
    1 1  1   1 111 11
    1 1   11     1 11
    1 1        1 1 11
    1 11 1     1    1
    1    1        111
    11111111111111111

读取将其编译为可用信息的代码表明...

它将字符串转换为列表,将空格更改为“ 0”,对列表进行两次枚举(以便可以隔离每个字符),然后将其以地图的网格形式发送出去(每个“ 1”或“ 0”是列表中自己的元素。

那部分代码看起来像这样:

    def create_level(file):
        if file[-4:] != '.txt': file += '.txt'
        f = open(os.path.join(path, file), 'r')
        file = f.readlines()

        for i, line in enumerate(file):
            file[i] = list(line.rstrip('\n'))
            for j, char in enumerate(file[i]):
                if char == ' ':
                    file[i][j] = 0
                else:
                    file[i][j] = int(char)

        f.close()

        mapBoundX  = len(file)
        mapBoundY  = len(file[0])
        mapGrid    = []

        for i, line in enumerate(file):
            mapGrid.append([])
            for j, char2 in enumerate(file[i]):
                if char2 != 0:
                    mapGrid[i].append(char2)
                else:
                    mapGrid[i].append(0)

        return mapBoundX, mapBoundY, mapGrid

在某些后续功能中,将从先前代码中获取的数据转换为实际的射线投射。我并不完全热衷于它的全部含义,但是我正在学习。这是那部分:

    def main():
        mapBoundX, mapBoundY, mapGrid = create_level(levelNum)
        posX, posY     = 8.5, 10.5
        dirX, dirY     = 1.0, 0.0
        planeX, planeY = 0.0, 0.66

        while True:
            #Input handling
            for event in pygame.event.get():
                if event.type == QUIT:
                    Quit()
                    return
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        Quit()
                        return

            #CEILING AND FLOOR
            pygame.draw.rect(SCREEN, ceiling_colour, (0, 0, WIDTH, (HEIGHT - map_size) / 2))
            pygame.draw.rect(SCREEN,   floor_colour, (0, (HEIGHT - map_size) / 2, WIDTH, (HEIGHT - map_size) / 2))

            for x in range(0, WIDTH, resolution):
                #Initial setup
                cameraX    = 2 * x / WIDTH - 1
                rayPosX    = posX
                rayPosY    = posY
                rayDirX    = dirX + planeX * cameraX + 0.000000000000001 #Add small value to avoid division by 0
                rayDirY    = dirY + planeY * cameraX + 0.000000000000001 #Add small value to avoid division by 0

                #Which square on the map the ray is in
                mapX = int(rayPosX)
                mapY = int(rayPosY)

                #The length of one ray from one x-side or y-side to the next x-side or y-side
                deltaDistX = sqrt(1 + rayDirY ** 2 / rayDirX ** 2)
                deltaDistY = sqrt(1 + rayDirX ** 2 / rayDirY ** 2)
                zBuffer    = []

                #Calculate step and initial sideDist
                if rayDirX < 0:
                    stepX = -1
                    sideDistX = (rayPosX - mapX) * deltaDistX
                else:
                    stepX = 1
                    sideDistX = (mapX + 1 - rayPosX) * deltaDistX

                if rayDirY < 0:
                    stepY = -1
                    sideDistY = (rayPosY - mapY) * deltaDistY
                else:
                    stepY = 1
                    sideDistY = (mapY + 1 - rayPosY) * deltaDistY

                #Digital differential analysis (DDA)
                while True:
                    #Jump to next map square
                    if sideDistX < sideDistY:
                        sideDistX += deltaDistX
                        mapX += stepX
                        side = 0
                    else:
                        sideDistY += deltaDistY
                        mapY += stepY
                        side = 1

                    #Check if ray hits wall or leaves the map boundries 
                    if mapX >= mapBoundX or mapY >= mapBoundY or mapX < 0 or mapY < 0 or mapGrid[mapX][mapY] > 0:
                        break

                #Calculate the total length of the ray
                if side == 0: rayLength = (mapX - rayPosX + (1 - stepX) / 2) / rayDirX
                else:         rayLength = (mapY - rayPosY + (1 - stepY) / 2) / rayDirY

                #Calculate the length of the line to draw on the screen
                lineHeight = (HEIGHT / rayLength) * wall_height

                #Calculate the start and end point of each line
                drawStart  = -lineHeight / 2 + (HEIGHT - map_size) / 2
                drawEnd    =  lineHeight / 2 + (HEIGHT - map_size) / 2

                #Calculate where exactly the wall was hit
                if side == 0: wallX = rayPosY + rayLength * rayDirY
                else:         wallX = rayPosX + rayLength * rayDirX
                wallX = abs((wallX - floor(wallX)) - 1)

                #Find the x coordinate on the texture
                texX = int(wallX * texWidth)
                if side == 1 and rayDirX > 0: texX = texWidth - texX - 1
                if side == 1 and rayDirY < 0: texX = texWidth - texX - 1

                c = max(1, (255.0 - rayLength * 27.2) * (1 - side * .25))

                yStart = max(0, drawStart)
                yStop = min(HEIGHT, drawEnd)
                pixelsPerTexel = lineHeight / texHeight
                colStart = int((yStart - drawStart) / pixelsPerTexel + .5)
                colHeight = int((yStop - yStart) / pixelsPerTexel + .5)

                yStart = int(colStart * pixelsPerTexel + drawStart + .5)
                yHeight = int(colHeight * pixelsPerTexel + .5)

                column = texture.subsurface((texX, colStart, 1, colHeight))
                column = column.copy()
                column.fill((c, c, c), special_flags=BLEND_MULT)
                column = pygame.transform.scale(column, (resolution, yHeight))
                SCREEN.blit(column, (x, yStart))

现在,我的主要问题:

我在专栏文章中看到了对纹理的引用,并且该引用已经过初始化,但是我似乎无法让它一次加载两个不同的纹理。理想情况下,我希望一些墙砖成为一种纹理,而另一些成为另一种。我尝试在原始地图文本文档中添加第三个字符“ 2”,以查看程序是否可以区分它们,但我似乎也无法使它正常工作。

如果有人可以向我解释这是如何工作的,或者我在编辑中做错了什么,那将非常感谢您。谢谢!

0 个答案:

没有答案