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()
代码中的问题是,当我运行它时,游戏正常工作,但碰撞系统似乎不起作用。我认为问题应该出在 DDA 算法代码内部,无论我修改了多少(尝试在
if(world_map[][])
中将 x 更改为 y,将 y 更改为 x,或者可能需要对光线投射本身的算法做一些处理) ?我现在不知道了,如果您能帮我解决这个问题,我将不胜感激。
在这段代码中,我尝试使用 ChatGPT 更改算法,例如多次更改
if (world_map[map_y][may_x])
,并尝试添加更多条件,例如:
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
基本上,如果 hit = 1,那么它应该阻止玩家穿过墙壁,然后它将继续检查玩家是否撞到墙壁,但在这段代码中,除了碰撞系统之外,一切都运行良好。我厌倦了解决这个问题很长一段时间,但它仍然不起作用。
在您的移动代码中,当用户按下箭头键时,玩家的位置更新如下:
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_UP]:
new_position_x = position_x + direction_x * move_speed
new_position_y = position_y + direction_y * move_speed
if world_map[int(new_position_x)][int(position_y)] == 0:
position_x = new_position_x
if world_map[int(position_x)][int(new_position_y)] == 0:
position_y = new_position_y
if keys[K_DOWN]:
new_position_x = position_x - direction_x * move_speed
new_position_y = position_y - direction_y * move_speed
if world_map[int(new_position_x)][int(position_y)] == 0:
position_x = new_position_x
if world_map[int(position_x)][int(new_position_y)] == 0:
position_y = new_position_y