203 lines
No EOL
5.1 KiB
Python
203 lines
No EOL
5.1 KiB
Python
import random
|
|
import pygame
|
|
import sys
|
|
|
|
pygame.init()
|
|
|
|
# Window Setup
|
|
WIDTH, HEIGHT = 1000, 700
|
|
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
|
pygame.display.set_caption("Traffic Simulation")
|
|
|
|
FPS = 60
|
|
clock = pygame.time.Clock()
|
|
|
|
# Colours
|
|
ROAD = (60, 60, 60)
|
|
CAR = (200, 40, 40)
|
|
GREEN = (0, 200, 0)
|
|
YELLOW= (255, 180, 0)
|
|
RED = (200, 0, 0)
|
|
WHITE = (255, 255, 255)
|
|
UI_BG = (30, 30, 30)
|
|
|
|
#Classes
|
|
|
|
#Traffic Light Class
|
|
class TrafficLight:
|
|
def __init__(self, x, y):
|
|
self.x = x
|
|
self.y = y
|
|
self.states = ["green", "yellow", "red"]
|
|
self.current = "green"
|
|
self.timer = 0
|
|
self.cycle_time = 120
|
|
|
|
def update(self):
|
|
self.timer += 1
|
|
if self.timer > self.cycle_time:
|
|
self.timer = 0
|
|
idx = self.states.index(self.current)
|
|
self.current = self.states[(idx +1) % 3]
|
|
|
|
def draw(self, surf):
|
|
colour = GREEN if self.current == "green" else YELLOW if self.current == "yellow" else RED
|
|
pygame.draw.circle(surf, colour, (self.x, self.y), 12)
|
|
|
|
#Vehicle Class
|
|
class Vehicle:
|
|
def __init__(self, x, y, speed=2):
|
|
self.x = x
|
|
self.y = y
|
|
self.speed = speed
|
|
self.wait = 0
|
|
|
|
def update(self, lights):
|
|
#check if light ahead
|
|
|
|
for light in lights:
|
|
if abs(self.x - light.x) < 10 and self.y < light.y < self.y + 40:
|
|
if light.current != "green":
|
|
self.wait += 1
|
|
return
|
|
|
|
self.y += self.speed
|
|
|
|
def draw(self, surf):
|
|
pygame.draw.rect(surf, CAR, (self.x - 10, self.y - 20, 20, 40))
|
|
|
|
|
|
|
|
|
|
#sim state
|
|
vehicles = []
|
|
lights = []
|
|
intersections = []
|
|
|
|
spawn_timer = 0
|
|
SPAWN_RATE = 60 #every second spawn one
|
|
|
|
|
|
placing_mode = "intersection"
|
|
|
|
#loop
|
|
|
|
running = True
|
|
while running:
|
|
clock.tick(FPS)
|
|
screen.fill((40, 140, 40))
|
|
|
|
#event handling
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
running = False
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
mx, my = pygame.mouse.get_pos()
|
|
if event.button == 1:
|
|
|
|
if mx < 800: #sim area
|
|
|
|
if placing_mode == "intersection":
|
|
intersections.append((mx, my))
|
|
elif placing_mode == "light":
|
|
lights.append(TrafficLight(mx, my))
|
|
|
|
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
mx, my = pygame.mouse.get_pos()
|
|
|
|
if placing_mode == "remove" and event.button == 3:
|
|
|
|
DEL_RADIUS = 25
|
|
|
|
intersections = [
|
|
(x, y) for (x, y) in intersections
|
|
if (mx - x) ** 2 + (my - y) ** 2 > DEL_RADIUS ** 2
|
|
]
|
|
|
|
lights = [
|
|
light for light in lights
|
|
if (mx - light.x) ** 2 + (my - light.y) ** 2 > DEL_RADIUS ** 2
|
|
]
|
|
|
|
# if event.type == pygame.MOUSEBUTTONDOWN: #delete things
|
|
# mx, my = pygame.mouse.get_pos()
|
|
# if event.button == 3: # right mouse
|
|
# if placing_mode == "intersection":
|
|
# #remove within 20px
|
|
# intersections = [
|
|
# (x, y) for (x, y) in intersections if not (abs(mx - x) < 20 and abs(my - y) < 20)
|
|
# ]
|
|
# if placing_mode == "light":
|
|
# lights = [
|
|
# light for light in lights if not (abs(mx - light.x) < 20 and abs(my - light.y) < 20)
|
|
# ]
|
|
|
|
|
|
#switch placing mode
|
|
if event.type == pygame.KEYDOWN:
|
|
if event.key == pygame.K_1:
|
|
placing_mode = "intersection"
|
|
if event.key == pygame.K_2:
|
|
placing_mode = "light"
|
|
if event.key == pygame.K_3:
|
|
placing_mode = "remove"
|
|
|
|
|
|
|
|
|
|
|
|
#roads
|
|
pygame.draw.rect(screen, ROAD, (380, 0, 240, HEIGHT))
|
|
|
|
#veichles
|
|
spawn_timer += 1
|
|
if spawn_timer > SPAWN_RATE:
|
|
spawn_timer = 0
|
|
vehicles.append(Vehicle(500, -20))
|
|
|
|
#update lights
|
|
for light in lights:
|
|
light.update()
|
|
light.draw(screen)
|
|
|
|
#update vehicles
|
|
for v in vehicles:
|
|
v.update(lights)
|
|
v.draw(screen)
|
|
|
|
#draw intersections
|
|
for x, y in intersections:
|
|
pygame.draw.rect(screen, WHITE, (x - 20, y - 20, 40, 40), 2)
|
|
|
|
#ui
|
|
pygame.draw.rect(screen, UI_BG, (800, 0, 200, HEIGHT))
|
|
font = pygame.font.SysFont(None, 28)
|
|
|
|
# circle wowwwwww so prettyyy
|
|
if placing_mode == "remove":
|
|
mx, my = pygame.mouse.get_pos()
|
|
pygame.draw.circle(screen, RED, (mx, my), 25, 2, )
|
|
|
|
ui_text = [
|
|
"Placement Mode:",
|
|
f"{placing_mode.upper()}",
|
|
"",
|
|
"Press 1: Intersection",
|
|
"Press 2: Traffic Light",
|
|
"Press 3: Remove Tool",
|
|
"",
|
|
f"Cars: {len(vehicles)}",
|
|
f"Lights: {len(lights)}",
|
|
f"Intersections: {len(intersections)}",
|
|
]
|
|
|
|
y_offset = 20
|
|
for line in ui_text:
|
|
txt = font.render(line, True, WHITE)
|
|
screen.blit(txt, (820, y_offset))
|
|
y_offset += 30
|
|
|
|
pygame.display.flip() |