[Python] Is there a way to allow the player to slide along the walls?

Discussão em 'Python' iniciado por Stack, Abril 26, 2025.

  1. Stack

    Stack Membro Participativo

    Is there a way to allow the player to slide along the walls?

    I am making a 2D FPS game and the player needs to be able to move swiftly around the map. In order to do this I need the player to slide along the walls (to allow for faster and easier gameplay) but I have no clue on how to do that. I have attempted some solutions but all of them still "stuck" to the walls.

    Is there any way to do this?

    Assets: gunImg.png

    Code:

    ##############################################################################

    import pygame
    import math

    #######################################

    pygame.init()

    X, Y = 800, 800
    DISPLAY = pygame.display.set_mode((X, Y))
    clock = pygame.time.Clock()
    FPS = 60
    pygame.display.set_caption("2D First Person Shooter")

    white = (255, 255, 255)
    black = (0, 0, 0)
    grey = (128, 128, 128)
    red = (255, 0, 0)

    ##############################################################################

    def renderPlayer(playerXY, gunImg, mouseXY):
    playerRect = pygame.draw.circle(DISPLAY, white, playerXY, 10)

    dx, dy = mouseXY[0]-playerRect.centerx, mouseXY[1]-playerRect.centery
    angle = math.degrees(math.atan2(-dy, dx))-90
    rotatedImg = pygame.transform.rotate(gunImg, angle)
    rotatedImgRect = rotatedImg.get_rect(center=playerRect.center)
    DISPLAY.blit(rotatedImg, rotatedImgRect.topleft)

    return playerRect

    #######################################

    def renderObjects(map, mapDimensions):
    wallRects = []
    for tile in range(len(map)):
    if map[tile] == 1:
    wallRects.append(pygame.Rect((tile%mapDimensions[0])*X/mapDimensions[0], (tile//mapDimensions[1])*Y/mapDimensions[1], X/mapDimensions[0], Y/mapDimensions[1]))
    return wallRects

    #######################################

    def checkCollisions(playerRect, nextPlayerXY, wallRects):
    tempRect = playerRect.copy()
    tempRect.center = nextPlayerXY
    for rect in wallRects:
    if tempRect.colliderect(rect):
    return True
    return False

    #######################################

    def DDA(targetX, targetY):
    targetX /= cellSize
    targetY /= cellSize

    rayStartX, rayStartY = (playerXY[0]/cellSize), (playerXY[1]/cellSize)
    rayDirX = (targetX-(playerXY[0]/cellSize))
    rayDirY = (targetY-(playerXY[1]/cellSize))
    rayDirLen = math.sqrt((rayDirX**2)+(rayDirY**2))
    if rayDirLen != 0:
    rayDirX /= rayDirLen
    rayDirY /= rayDirLen

    rayUnitStepX = math.sqrt(1+(rayDirY/rayDirX)**2) if rayDirX != 0 else float('inf')
    rayUnitStepY = math.sqrt(1+(rayDirX/rayDirY)**2) if rayDirY != 0 else float('inf')

    mapCheckX, mapCheckY = int(rayStartX), int(rayStartY)
    rayLengthX, rayLengthY = 0, 0
    stepX, stepY = 0, 0

    if rayDirX < 0:
    stepX = -1
    rayLengthX = (rayStartX-mapCheckX)*rayUnitStepX
    else:
    stepX = 1
    rayLengthX = (mapCheckX+1-rayStartX)*rayUnitStepX

    if rayDirY < 0:
    stepY = -1
    rayLengthY = (rayStartY-mapCheckY)*rayUnitStepY
    else:
    stepY = 1
    rayLengthY = (mapCheckY+1-rayStartY)*rayUnitStepY

    tileFound = False
    maxDistance = 100
    distance = 0

    while not tileFound and distance < maxDistance:
    if rayLengthX < rayLengthY:
    mapCheckX += stepX
    distance = rayLengthX
    rayLengthX += rayUnitStepX
    else:
    mapCheckY += stepY
    distance = rayLengthY
    rayLengthY += rayUnitStepY

    if 0 <= mapCheckX < mapDimensions[0] and 0 <= mapCheckY < mapDimensions[1]:
    if map[(mapCheckY*mapDimensions[0])+mapCheckX] == 1:
    tileFound = True

    intersectionX, intersectionY = 0, 0
    if tileFound:
    intersectionX = rayStartX+(rayDirX*distance)
    intersectionY = rayStartY+(rayDirY*distance)

    return intersectionX*cellSize, intersectionY*cellSize

    #######################################

    #def fireBullet(playerXY, bullets):

    ##############################################################################

    playerXY = [375, 375]
    playerSpeed = 180/FPS

    map = [
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
    1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1,
    1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1,
    1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1,
    1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
    1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1,
    1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
    1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1,
    1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
    1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    ]
    mapDimensions = (16, 16)
    cellSize = int(X/mapDimensions[0])

    gunImg = pygame.image.load("Assets\gun.png")
    gunImg = pygame.transform.smoothscale(gunImg, (40, 40))

    playerRect = renderPlayer(playerXY, gunImg, (0, 0))

    #######################################

    while True:
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    pygame.quit()
    exit()

    heldKeys = pygame.key.get_pressed()
    mouseXY = pygame.mouse.get_pos()

    if heldKeys[pygame.K_w] or heldKeys[pygame.K_s]:
    directionX = mouseXY[0]-playerRect.centerx
    directionY = mouseXY[1]-playerRect.centery
    distance = math.hypot(directionX, directionY)
    if distance > 1:
    normalizedDX = directionX/distance
    normalizedDY = directionY/distance
    if heldKeys[pygame.K_w]:
    nextPlayerXY = [playerXY[0]+normalizedDX*playerSpeed, playerXY[1]+normalizedDY*playerSpeed]
    elif heldKeys[pygame.K_s]:
    nextPlayerXY = [playerXY[0]-normalizedDX*playerSpeed, playerXY[1]-normalizedDY*playerSpeed]
    if not checkCollisions(playerRect, nextPlayerXY, wallRects):
    playerXY = nextPlayerXY
    if heldKeys[pygame.K_a]:
    angleToMouse = math.atan2(mouseXY[1]-playerXY[1], mouseXY[0]-playerXY[0])
    moveAngle = angleToMouse+math.pi/2
    moveX = playerSpeed*math.cos(moveAngle)
    moveY = playerSpeed*math.sin(moveAngle)
    nextPlayerXY = [playerXY[0]+moveX, playerXY[1]+moveY]
    if not checkCollisions(playerRect, nextPlayerXY, wallRects):
    playerXY = nextPlayerXY
    if heldKeys[pygame.K_d]:
    angleToMouse = math.atan2(mouseXY[1]-playerXY[1], mouseXY[0]-playerXY[0])
    moveAngle = angleToMouse-math.pi/2
    moveX = playerSpeed*math.cos(moveAngle)
    moveY = playerSpeed*math.sin(moveAngle)
    nextPlayerXY = [playerXY[0]+moveX, playerXY[1]+moveY]
    if not checkCollisions(playerRect, nextPlayerXY, wallRects):
    playerXY = nextPlayerXY

    DISPLAY.fill(black)

    wallRects = renderObjects(map, mapDimensions)

    intersectionsPoints = []
    for x in range(0, X): # Top
    intersectionsPoints.append(DDA(x, 0))
    for y in range(0, Y): # Right
    intersectionsPoints.append(DDA(X, y))
    for x in range(0, X): # Bottom
    intersectionsPoints.append(DDA(X-x, Y))
    for y in range(0, Y): # Left
    intersectionsPoints.append(DDA(0, Y-y))
    pygame.draw.polygon(DISPLAY, white, intersectionsPoints, 1)

    #rayDistances = []
    #for rayEnd in intersectionsPoints:
    # rayDistances.append(math.dist(playerXY, rayEnd))

    playerRect = renderPlayer(playerXY, gunImg, mouseXY)

    pygame.display.update()
    clock.tick(FPS)

    ##############################################################################

    Continue reading...

Compartilhe esta Página