[Python] How do I fix the collision mechanism using raycast 3D in Pygame?

Discussão em 'Python' iniciado por Stack, Setembro 29, 2024.

  1. Stack

    Stack Membro Participativo

    import pygame
    import math
    import numpy as np
    from pygame.locals import *
    import game_map

    # Define color
    B_RED = (125, 22, 22)
    M_RED = (107, 19, 16)
    L_RED = (69, 15, 16)
    BLACK = (5, 5, 10)
    WHITE = (255,255,255)
    GRAY = (25,25,25)

    # Define the world map
    world_map = game_map.world_map # World map is from another python file

    def close():
    """ Close the application """
    pygame.display.quit()
    pygame.quit()
    return

    clock = pygame.time.Clock()

    def main():
    """ Main function to run the game """
    pygame.init()

    # Display information
    WIDTH = 1400
    HEIGHT = 800
    window = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("Autophobia")

    # Initialize player position and direction
    position_x = 5 # Initial X position
    position_y = 8 # Initial Y position
    direction_x = 1 # Initial direction X
    direction_y = 0 # Initial direction Y
    plane_x = 0 # Camera plane X
    plane_y = 0.66 # Camera plane Y (for FOV)

    # Define movement and rotation speeds
    move_speed = 0.1
    rotation_speed = 0.05

    ## Main loop of the program
    while True:
    # Check the key if the player is quitting or not
    for event in pygame.event.get():
    if event.type == QUIT:
    close()

    # Key binding
    keys = pygame.key.get_pressed()
    if keys[K_ESCAPE]:
    close()
    if keys[K_UP]:
    position_x += direction_x * move_speed
    position_y += direction_y * move_speed
    if keys[K_DOWN]:
    position_x -= direction_x * move_speed
    position_y -= direction_y * move_speed
    if keys[K_RIGHT]:
    # Rotate RIGHT
    old_dir_x = direction_x
    direction_x = direction_x * math.cos(rotation_speed) - direction_y * math.sin(rotation_speed)
    direction_y = old_dir_x * math.sin(rotation_speed) + direction_y * math.cos(rotation_speed)
    # Rotate plane
    old_plane_x = plane_x
    plane_x = plane_x * math.cos(rotation_speed) - plane_y * math.sin(rotation_speed)
    plane_y = old_plane_x * math.sin(rotation_speed) + plane_y * math.cos(rotation_speed)
    if keys[K_LEFT]:
    # Rotate LEFT
    old_dir_x = direction_x
    direction_x = direction_x * math.cos(-rotation_speed) - direction_y * math.sin(-rotation_speed)
    direction_y = old_dir_x * math.sin(-rotation_speed) + direction_y * math.cos(-rotation_speed)
    # Rotate plane
    old_plane_x = plane_x
    plane_x = plane_x * math.cos(-rotation_speed) - plane_y * math.sin(-rotation_speed)
    plane_y = old_plane_x * math.sin(-rotation_speed) + plane_y * math.cos(-rotation_speed)

    # Raycasting Logic
    window.fill((25, 25, 25)) # Clear the screen
    pygame.draw.rect(window, (50,50,50), (0, HEIGHT/2, WIDTH, HEIGHT/2)) # Draw floor

    # Calculate ray direction for each column
    for columns in range(WIDTH):
    camera_x = 2.0 * columns / WIDTH - 1.0
    ray_pos_x = position_x
    ray_pos_y = position_y
    ray_dir_x = direction_x + plane_x * (2 * columns / WIDTH - 1) + 0.000001 # To avoid division by 0
    ray_dir_y = direction_y + plane_y * (2 * columns / WIDTH - 1) + 0.000001

    map_x = int(ray_pos_x)
    map_y = int(ray_pos_y)

    # Delta distance
    delta_dis_x = math.sqrt(1 + (ray_dir_y / ray_dir_x) ** 2)
    delta_dis_y = math.sqrt(1 + (ray_dir_x / ray_dir_y) ** 2)

    # Step and initial side distance
    step_x, step_y = 0, 0
    side_dis_x, side_dis_y = 0.0, 0.0

    # Initialize side
    if ray_dir_x < 0:
    step_x = -1
    side_dis_x = (ray_pos_x - map_x) * delta_dis_x
    else:
    step_x = 1
    side_dis_x = (map_x + 1.0 - ray_pos_x) * delta_dis_x
    if ray_dir_y < 0:
    step_y = -1
    side_dis_y = (ray_pos_y - map_y) * delta_dis_y
    else:
    step_y = 1
    side_dis_y = (map_y + 1.0 - ray_pos_y) * delta_dis_y

    # Perform DDA

    hit = 0
    while (hit == 0):
    if side_dis_x < side_dis_y:
    side_dis_x += delta_dis_x
    map_x += step_x
    side = 0 # X-axis hit
    else:
    side_dis_y += delta_dis_y
    map_y += step_y
    side = 1 # Y-axis hit
    if (world_map[map_x][map_y]) > 0:
    hit = 1

    # Correction of the POV
    if side == 0:
    perp_wall_dist = abs((map_x - ray_pos_x + (1 - step_x) / 2) / ray_dir_x)
    else:
    perp_wall_dist = abs((map_y - ray_pos_y + (1 - step_y) / 2) / ray_dir_y)

    # Calculate the height of the wall
    line_height = int(HEIGHT / (perp_wall_dist + 0.00001))

    # Calculate the draw start and end
    draw_start = -line_height / 2 + HEIGHT / 2
    if draw_start < 0:
    draw_start = 0
    draw_end = line_height / 2 + HEIGHT / 2
    if draw_end >= HEIGHT:
    draw_end = HEIGHT - 1

    # Choose the color based on the map value
    if 0 <= map_x < len(world_map[0]) and 0 <= map_y < len(world_map):
    color = L_RED if world_map[map_y][map_x] == 1 else M_RED
    else:
    color = (25, 25, 25) # or some other default color

    # Draw the vertical line
    pygame.draw.line(window, color, (columns, draw_start), (columns, draw_end),1)

    pygame.event.pump()
    pygame.display.flip()
    pygame.display.update()
    clock.tick(60)

    if __name__ == "__main__":
    main()


    The problem within the code is that when I run it, the game is working as normal but however the collision system doesn't seem to be working. I think the problem should be inside the DDA algorithm code, no matter how much I modify it (tried changing from x to y and y to x in the if(world_map[][]) or it might have to do something with the algorithm of the ray cast itself? I don't know anymore at this point, I would be appreciated if you can help me solve this problem.

    In this code I tried changing the algorithm using ChatGPT like changing the if (world_map[map_y][may_x]) multiple times and tried adding more conditions like:

    hit = 1
    ... # Three dots mean there are more lines of codes between the two lines above and below
    while (hit == 0):
    if side_dis_x < side_dis_y:
    side_dis_x += delta_dis_x
    map_x += step_x
    side = 0 # X-axis hit
    else:
    side_dis_y += delta_dis_y
    map_y += step_y
    side = 1 # Y-axis hit

    # Extra condition still doesn't work
    if map_x < 0 or map_x >= len(world_map[0]) or map_y < 0 or map_y >= len(world_map):
    break
    # Copied from ChatGPT
    if world_map[map_y][map_x] > 0 and (abs(ray_pos_x - map_x) < 0.5 or abs(ray_pos_y - map_y) < 0.5):
    hit = 1


    Basically if the hit = 1 then it should stop the player from going through wall then it will continue checking if the player hits the wall or not but in this code everything works perfectly except for the collision system somehow. I tired to fix the problem for a really long time but it's still doesn't work.

    Continue reading...

Compartilhe esta Página