# Ian Binstock
# 5/31/2026
# Game where you can move a dolphin around

import pygame, sys

# Visualization Tools
# - DEFAULT: False, 0.35, 8
# - CONCEPTUAL: True, 0.05, 3
SHOW_BORDERS = False
EASE = 0.35
SPEED = 8

# Constants
SCREEN_W = 800
SCREEN_H = 800
OCEAN_BLUE = (15, 75, 115)
GRAY = (150, 150, 150)


### CLASSES
class Segment:
    # Constructor
    def __init__(self, obj_x, obj_y, obj_shape, obj_color, obj_r=0, obj_w=0, obj_h=0, obj_y_offset=0):
        self.x = obj_x
        self.y = obj_y
        self.shape = obj_shape
        self.color = obj_color
        self.r = obj_r
        self.w = obj_w
        self.h = obj_h
        self.y_offset = obj_y_offset

class Dolphin:
    # A dolphin-like structure made up of 9 body segments
    def __init__(self):
        start_x = SCREEN_W // 2
        start_y = SCREEN_H // 2

        self.segments = [
            Segment(start_x, start_y, "circle", GRAY, obj_r=15), # Head
            Segment(start_x, start_y, "circle", GRAY, obj_r=28),
            Segment(start_x, start_y, "circle", GRAY, obj_r=35),
            Segment(start_x, start_y, "ellipse", GRAY, obj_w=200, obj_h=35), # Fins
            Segment(start_x, start_y, "circle", GRAY, obj_r=35),
            Segment(start_x, start_y, "ellipse", GRAY, obj_w=25,  obj_h=120, obj_y_offset=-30), # Dorsal Fin
            Segment(start_x, start_y, "circle", GRAY, obj_r=28),
            Segment(start_x, start_y, "circle", GRAY, obj_r=22),
            Segment(start_x, start_y, "ellipse", GRAY, obj_w=125, obj_h=20,  obj_y_offset=5), # Tail
        ]


### HELPER FUNCTIONS
def update_segment(segment, target_x, target_y, ease=EASE):
    # Moves the segment toward the target x and y coordinates
    segment.x += (target_x - segment.x) * ease
    segment.y += (target_y - segment.y) * ease

# Creates the TRAILING EFFECT, giving the dolphin its shape
def update_dolphin(dolphin, target_x, target_y):
    # Update Head (segment 0) to follow keyboard input directly
    update_segment(dolphin.segments[0], target_x, target_y, ease=0.4)

    # Make each subsequent segment trail the one in front of it
    for i in range(1, len(dolphin.segments)):
        prev = dolphin.segments[i - 1]
        update_segment(dolphin.segments[i], prev.x, prev.y)

def draw_segment(screen, segment, draw_border=False):
    # Handles drawing circles
    if segment.shape == "circle":
        pygame.draw.circle(screen, segment.color, (int(segment.x), int(segment.y)), segment.r)
        if draw_border:
            pygame.draw.circle(screen, "#FFFFFF", (int(segment.x), int(segment.y)), segment.r, 2)
            
    # Handles drawing ovals
    elif segment.shape == "ellipse":
        rect = pygame.Rect(
            segment.x - segment.w // 2, 
            segment.y - segment.h // 2 + segment.y_offset, 
            segment.w, 
            segment.h
        )
        pygame.draw.ellipse(screen, segment.color, rect)
        if draw_border:
            pygame.draw.ellipse(screen, "#FFFFFF", rect, 2)

def draw_dolphin(screen, dolphin, draw_borders):
    # Draws the dolphin segments back-to-front
    for segment in reversed(dolphin.segments):
        draw_segment(screen, segment, draw_borders)


### GAME LOOP
def main():
    # Basic setup
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_W, SCREEN_H))
    pygame.display.set_caption("Move the dolphin with WASD!")
    clock = pygame.time.Clock()

    # 'Target' stores the [x,y] coords that the dolphin is chasing
    target = [SCREEN_W // 2, SCREEN_H // 2] # dolphin starting position
    dolphin = Dolphin()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        # Input
        keys = pygame.key.get_pressed()
        if keys[pygame.K_w]: target[1] -= SPEED # W - Up
        if keys[pygame.K_s]: target[1] += SPEED # S - Down
        if keys[pygame.K_a]: target[0] -= SPEED # A - Left
        if keys[pygame.K_d]: target[0] += SPEED # D - Right

        # Update the target's [x,y] coords
        target[0] = max(0, min(SCREEN_W, target[0]))
        target[1] = max(0, min(SCREEN_H, target[1]))

        # Update the dolphin's position using the helper function
        update_dolphin(dolphin, *target)

        # Draw elements using the helper function
        screen.fill(OCEAN_BLUE)
        draw_dolphin(screen, dolphin, SHOW_BORDERS)
        pygame.display.flip() # Ensure drawn elements appear in front
        clock.tick(80)

# Run it
main()