I need help in making the player not be able to walk through walls. The turrets do not spawn in, and the stairs to the 2nd floor does not generate in the circular rooms. And I would like to optimize the game, maybe it might be my computer that is running slow but I would like to know how to optimize it. And sometimes the rooms are not connected I added checks but the checks do not help.
import pygame
import math
import random
# Initialize Pygame
pygame.init()
width, height = 1440, 800
screen = pygame.display.set_mode((width, height))
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
def generate_dungeon(width, height, min_room_size=5, max_room_size=25, min_rooms=10, max_rooms=20):
dungeon = [[1 for _ in range(width)] for _ in range(height)]
rooms = []
num_rooms = random.randint(min_rooms, max_rooms)
for _ in range(num_rooms):
room_width = random.randint(min_room_size, max_room_size)
room_height = random.randint(min_room_size, max_room_size)
x = random.randint(0, width - room_width - 1)
y = random.randint(0, height - room_height - 1)
new_room = (x, y, room_width, room_height)
failed = False
for other_room in rooms:
if intersect(new_room, other_room):
failed = True
break
if not failed:
create_room(dungeon, new_room)
(new_x, new_y, new_width, new_height) = new_room
if len(rooms) == 0:
player_x = new_x + new_width // 2
player_y = new_y + new_height // 2
else:
(prev_x, prev_y, _, _) = rooms[-1]
if random.randint(0, 1) == 1:
create_h_tunnel(dungeon, prev_x, new_x, prev_y + new_height // 2)
create_v_tunnel(dungeon, prev_y, new_y, new_x + new_width // 2)
else:
create_v_tunnel(dungeon, prev_y, new_y, prev_x + new_width // 2)
create_h_tunnel(dungeon, prev_x, new_x, new_y + new_height // 2)
rooms.append(new_room)
# Add custom structures
for _ in range(5): # Add 5 circular rooms
radius = random.randint(3, 6)
center_x = random.randint(radius, width - radius - 1)
center_y = random.randint(radius, height - radius - 1)
create_circle_room(dungeon, center_x, center_y, radius)
# Add stairs with a 20% chance in each circular room
if random.random() < 0.2:
stairs_x = random.randint(center_x - radius, center_x + radius)
stairs_y = random.randint(center_y - radius, center_y + radius)
dungeon[stairs_y][stairs_x] = 2 # Different value for stairs
# Forcefully generate stairs in one circular room if none are generated
if not any(tile == 2 for row in dungeon for tile in row):
radius = random.randint(3, 6)
center_x = random.randint(radius, width - radius - 1)
center_y = random.randint(radius, height - radius - 1)
stairs_x = random.randint(center_x - radius, center_x + radius)
stairs_y = random.randint(center_y - radius, center_y + radius)
dungeon[stairs_y][stairs_x] = 2 # Different value for stairs
return dungeon, player_x, player_y
def create_circle_room(dungeon, center_x, center_y, radius):
for y in range(center_y - radius, center_y + radius + 1):
for x in range(center_x - radius, center_x + radius + 1):
if (x - center_x) ** 2 + (y - center_y) ** 2 <= radius ** 2:
dungeon[y][x] = 0
def intersect(rect1, rect2):
return (rect1[0] <= rect2[0] + rect2[2] and rect1[0] + rect1[2] >= rect2[0] and
rect1[1] <= rect2[1] + rect2[3] and rect1[1] + rect1[3] >= rect2[1])
def create_room(dungeon, room):
(x, y, w, h) = room
for i in range(x, x + w):
for j in range(y, y + h):
dungeon[j][i] = 0
def create_h_tunnel(dungeon, x1, x2, y):
for x in range(min(x1, x2), max(x1, x2) + 1):
for y_off in range(-1, 2):
dungeon[y + y_off][x] = 0
def create_v_tunnel(dungeon, y1, y2, x):
for y in range(min(y1, y2), max(y1, y2) + 1):
for x_off in range(-1, 2):
dungeon[y][x + x_off] = 0
def cast_ray(angle, player_x, player_y, world_map):
ray_dx = math.cos(angle)
ray_dy = math.sin(angle)
# Initialize ray starting position
ray_x = player_x
ray_y = player_y
# Incremental steps for ray
step_x = 1 if ray_dx >= 0 else -1
step_y = 1 if ray_dy >= 0 else -1
# Distance to next x or y intersection
delta_dist_x = abs(1 / ray_dx)
delta_dist_y = abs(1 / ray_dy)
# Initial distance to the first x or y side
dist_x = (ray_x + 1 - player_x) * delta_dist_x
dist_y = (ray_y + 1 - player_y) * delta_dist_y
# Step variables to keep track of the current cell
map_x = int(ray_x)
map_y = int(ray_y)
# Ray casting loop
hit_wall = False
while not hit_wall:
# Jump to next map square, OR in x-direction, OR in y-direction
if dist_x < dist_y:
dist_x += delta_dist_x
map_x += step_x
side = 0 # Hit a vertical wall
else:
dist_y += delta_dist_y
map_y += step_y
side = 1 # Hit a horizontal wall
# Check if ray has hit a wall
if world_map[map_y][map_x] == 1:
hit_wall = True
# Calculate distance to the wall
if side == 0:
wall_dist = (map_x - player_x + (1 - step_x) / 2) / ray_dx
else:
wall_dist = (map_y - player_y + (1 - step_y) / 2) / ray_dy
return wall_dist
# Generate the dungeon
dungeon, player_x, player_y = generate_dungeon(128, 128)
world_map = dungeon
# Player setup
player_x, player_y, player_angle = player_x, player_y, math.pi / 2
fov = math.pi / 3.0
move_speed = 0.1
rotate_speed = 0.02
run_speed = 0.2 # Speed multiplier when running
stamina_max = 100 # Maximum stamina
stamina = stamina_max # Current stamina
stamina_regen_rate = 1 # Stamina regeneration rate per second
stamina_regen_delay = 3 # Delay in seconds before stamina starts regenerating
stamina_regen_timer = 0 # Timer to track stamina regeneration delay
# Health setup
health_max = 100 # Maximum health
health = health_max # Current health
# Mini-map dimensions and scaling factor
mini_map_scale = 6
mini_map_width = len(world_map[0]) * mini_map_scale
mini_map_height = len(world_map) * mini_map_scale
# Turret setup
turret_size = 10
turret_countdown = 3 # Countdown in seconds before turret starts shooting
turret_bullet_speed = 0.3
turret_bullet_damage = 30
turrets = []
def draw_turret(turret):
# Draw turret body
pygame.draw.rect(screen, BLACK, (turret[0] - turret_size // 2, turret[1] - turret_size // 2, turret_size, turret_size))
# Draw turret faces
for face_angle in turret[3]:
face_x = turret[0] + turret_size * 0.4 * math.cos(face_angle)
face_y = turret[1] + turret_size * 0.4 * math.sin(face_angle)
pygame.draw.line(screen, BLACK, (turret[0], turret[1]), (face_x, face_y))
# Draw turret laser
if turret[4] > 0:
laser_end_x = turret[0] + 1000 * math.cos(turret[2])
laser_end_y = turret[1] + 1000 * math.sin(turret[2])
pygame.draw.line(screen, RED, (turret[0], turret[1]), (laser_end_x, laser_end_y))
def update_turret(turret, player_x, player_y, world_map):
# Check if turret can see player
turret_angle = math.atan2(player_y - turret[1], player_x - turret[0])
angle_diff = normalize_angle(turret_angle - turret[2])
if abs(angle_diff) <= math.pi / 3 and not is_blocked(turret, player_x, player_y, world_map):
turret[4] = turret_countdown # Start countdown
# Countdown logic
if turret[4] > 0:
turret[4] -= 1 / 60 # Assuming 60 FPS
if turret[4] <= 0:
# Fire bullets
bullet_angle = math.atan2(player_y - turret[1], player_x - turret[0])
bullets.append([turret[0], turret[1], bullet_angle, turret_bullet_speed, turret_bullet_damage])
def normalize_angle(angle):
while angle < -math.pi:
angle += 2 * math.pi
while angle > math.pi:
angle -= 2 * math.pi
return angle
def is_blocked(turret, target_x, target_y, world_map):
dx = target_x - turret[0]
dy = target_y - turret[1]
distance = math.sqrt(dx ** 2 + dy ** 2)
step_x = dx / distance
step_y = dy / distance
current_x = turret[0]
current_y = turret[1]
for _ in range(int(distance)):
current_x += step_x
current_y += step_y
if world_map[int(current_y)][int(current_x)] == 1:
return True
return False
# Main loop
clock = pygame.time.Clock()
running = True
show_mini_map = False # Flag to track if the mini-map should be shown
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_m:
# Toggle mini-map visibility
show_mini_map = not show_mini_map
# Mouse movement
dx, dy = pygame.mouse.get_rel()
player_angle += dx * 0.002
# Lock the mouse in the center of the screen
pygame.mouse.set_pos(width // 2, height // 2)
# Player movement
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
# Move left
player_x -= math.cos(player_angle + math.pi / 2) * move_speed
player_y -= math.sin(player_angle + math.pi / 2) * move_speed
if keys[pygame.K_d]:
# Move right
player_x += math.cos(player_angle + math.pi / 2) * move_speed
player_y += math.sin(player_angle + math.pi / 2) * move_speed
if keys[pygame.K_w]:
# Move forward
player_x += math.cos(player_angle) * move_speed
player_y += math.sin(player_angle) * move_speed
if keys[pygame.K_s]:
# Move backward
player_x -= math.cos(player_angle) * move_speed
player_y -= math.sin(player_angle) * move_speed
# Running
if keys[pygame.K_LSHIFT] and stamina > 0:
move_speed = run_speed
stamina -= 1
stamina_regen_timer = 0
else:
move_speed = 0.1
if stamina < stamina_max:
stamina_regen_timer += 1 / 30 # Assuming 60 FPS
if stamina_regen_timer >= stamina_regen_delay:
stamina += stamina_regen_rate
if stamina > stamina_max:
stamina = stamina_max
# Update turrets
for turret in turrets:
update_turret(turret, player_x, player_y, world_map)
screen.fill(BLACK)
# Raycasting
for x in range(width):
# Ray direction
camera_x = 2 * x / width - 1
ray_angle = player_angle + fov * camera_x
ray_dx = math.cos(ray_angle)
ray_dy = math.sin(ray_angle)
# Perform raycasting
distance_to_wall = 0
hit_wall = False
while not hit_wall and distance_to_wall < 10:
distance_to_wall += 0.1
test_x = int(player_x + ray_dx * distance_to_wall)
test_y = int(player_y + ray_dy * distance_to_wall)
if test_x < 0 or test_x >= len(world_map[0]) or test_y < 0 or test_y >= len(world_map):
hit_wall = True
distance_to_wall = 10
elif world_map[test_y][test_x] == 1:
hit_wall = True
ceiling = height // 2 - height // distance_to_wall
floor = height - ceiling
pygame.draw.line(screen, WHITE, (x, ceiling), (x, floor))
# Draw player
pygame.draw.circle(screen, RED, (int(player_x * width), int(player_y * height)), 6) # Increased size
# Draw turrets
for turret in turrets:
draw_turret(turret)
# Draw mini-map if it should be shown
if show_mini_map:
mini_map_surf = pygame.Surface((mini_map_width, mini_map_height))
for y, row in enumerate(world_map):
for x, tile in enumerate(row):
if tile == 1:
pygame.draw.rect(mini_map_surf, WHITE, (x * mini_map_scale, y * mini_map_scale, mini_map_scale, mini_map_scale))
elif tile == 2: # Stairs
pygame.draw.rect(mini_map_surf, (0, 255, 0), (x * mini_map_scale, y * mini_map_scale, mini_map_scale, mini_map_scale))
# Draw player on mini-map
pygame.draw.circle(mini_map_surf, RED, (int(player_x * mini_map_scale), int(player_y * mini_map_scale)), 6) # Increased size
# Draw mini-map on screen
screen.blit(mini_map_surf, (width - mini_map_width - 10, 10))
# Draw stamina bar
pygame.draw.rect(screen, BLACK, (10, 10, 100, 10)) # Background
pygame.draw.rect(screen, RED, (10, 10, stamina, 10)) # Fill
# Draw health bar
pygame.draw.rect(screen, BLACK, (10, 25, 100, 10)) # Background
pygame.draw.rect(screen, GREEN, (10, 25, health, 10)) # Fill
pygame.display.flip()
clock.tick(60)
pygame.quit()
I am trying to make a horror game using ray casting but adding a turet seems to be hard for me and adding stairs to the end floor also does not work.