<filename>Juego(por nombrar)/src/clases/ambiente.py
import pygame as pg
from pygame import sprite
from itertools import cycle
from pygame.locals import *
import imutils
import math, random, sys
import cv2 as cv
import numpy as np
from settings import *
from ImageProcessing import *
from glob import glob
def delta(t, x0, x): #experimento para ver como funciona el posc de las sombras
    if x == x0:
        return t
    else:
        return t*(math.sin(x)+math.cos(x))
class circle(pg.sprite.Sprite): #no es realmente necesario
    def __init__(self, xy, radius, id, surface):
        super().__init__()
        self.xy = xy
        self.radius = radius
        self.id = id
        self.surface = surface
        self.color = (random.randint(128, 255), random.randint(128, 255),
                random.randint(128, 255), 255) if id != 5 else (255,255,0)
    def hasOverlapped(self, xy, radius):
        minDistance = 0.0 + radius + self.radius
        distance = math.hypot(xy[0] - self.xy[0], xy[1] - self.xy[1])
        if distance >= minDistance: return False

        radians = math.atan2(xy[1] - self.xy[1], xy[0] - self.xy[0])
        overlap = 1 + (minDistance - distance)
        return (math.cos(radians) * overlap, math.sin(radians) * overlap, overlap)
    def setXY(self, xy):
        self.xy = xy
    def draw(self):
        pg.draw.circle(self.surface, self.color, (int(self.xy[0]), int(self.xy[1])), self.radius, 0)
class fuenteLuz(pg.sprite.Sprite): #clase base para las fuentes de luz
    def __init__(self, imgPath, lightRadius, lightable):
        super().__init__() #sí, son sprites
        self.center = (0,0) #inútil
        self.x = 300
        self.y = 500
        self.lightable = lightable
        self.lightRadius = lightRadius
        self.animations = cycle(self.get_animations(imgPath)) #obtención de imagenes
        self.animation_counter = 0
        self.__image = next(self.animations)
        array = pg.surfarray.array3d(self.__image)
        self.circ = circle(self.__image.get_rect().center, lightRadius, 5, self.__image)
        self.rect = pg.rect.Rect(self.x, self.y, self.x+lightRadius, self.y+ lightRadius) #se centra la figura


        self.radius = self.circ.radius

    def get_animations(self, imgPath): #se consiguen animaciones y se agrandan para poder hacer un cubo de detección de luz
        self.preAnimation = [pg.image.load(img) for img in glob("animations/{}**".format(imgPath))]
        for a in self.preAnimation:
            a.convert()
        self.postAnimation = [pg.surfarray.make_surface(
                               cv.copyMakeBorder(pg.surfarray.array3d(surface),
                                                round(self.lightRadius-sizes[1]/2),
                                                round(self.lightRadius-sizes[1]/2),
                                                round(self.lightRadius-sizes[0]/2),
                                                round(self.lightRadius-sizes[0]/2),
                                                cv.BORDER_ISOLATED)
                                                )
                                for sizes, surface in zip([pg.surfarray.array3d(surf).shape for surf in self.preAnimation],
                                                          self.preAnimation)]
        for a in self.postAnimation:
            a.set_colorkey((0,0,0))
        return self.postAnimation
    @property
    def image(self): #bastante estandar

        if self.animation_counter > 4:
            self.animation_counter = 0
            self.__image = next(self.animations)
        return self.__image
    def update(self, x, y): #método que ocupa el grupo
        self.set_position(x,y)
        self.check_area()

        self.animation_counter += 1
    def set_position(self, CAMERA_X, CAMERA_Y): #mover la fuente de luz

        self.rect.x, self.rect.y = self.x-CAMERA_X, self.y-CAMERA_Y
    def check_area(self): #función que por ahora contiene la creación de sombras
        obj = pg.sprite.spritecollideany(self, self.lightable) #se buscavcolisiones entre el sprite de la luz y cualquier otro que este en el grupo de los colisionables
        if obj != None: #pulir si se puede (se puede)
            objX = obj.rect.centerx+obj.corrections[0] #se aplican correciones
            objY = obj.rect.centery+obj.corrections[1]
            Vect = np.array([self.rect.centerx-objX, #vextor móvil,  este va del centor del jugador al de la luz
                             self.rect.centery-objY
                            ])
            E_1 = np.array([1,0]) #vector canónico para comparar

            norm = np.linalg.norm(Vect)
            angle = math.acos(np.vdot(E_1, Vect/norm)) if objY < self.rect.centery else -math.acos(np.vdot(E_1, Vect/norm))
            rnorm = int(round(norm))^2 #transparencia 1/x^2
            angleShadow = angle - np.radians(90)
            angle -= np.radians(180)
            angle = -angle #comportamientos raros
            print(np.degrees(angle), delta(-30, math.pi/4, angle))
            if norm <= self.radius:
                alpha = 50/rnorm*255 if norm != 0 else 0
                shadow = Shadow(obj, alpha, angleShadow)
                xOffset, yOffset = 0, 0
                if angle >= 0 and angle < math.pi/2:
                    xOffset = math.cos(angle)*shadow.corrections[0]+delta(-15, math.pi/4, angle)
                    yOffset = math.cos(angle)*shadow.corrections[1]+delta(-15, math.pi/4, angle)
                d = pg.display.get_surface()

                d.blit(shadow.image, (obj.rect.x + xOffset , obj.rect.y + yOffset))
                d.blit(obj.image, (obj.rect.x, obj.rect.y))

                del shadow



    def draw(self, surface, point):
        x, y = point
        surface.blit(self, (x+self.w/2, y+h/2))

if __name__ == "__main__":
    clock = pg.time.Clock()
    fire = fuenteLuz("fire/frame", 3)
    pg.init()
    g = pg.sprite.Group()
    g.add(fire)
    screen =  pg.display.set_mode((500,400))
    screen.fill((255,255,255))



    while True:
        for event in pg.event.get():
            if event.type is pg.QUIT:
                pg.quit() # quit the screen
                break

        screen.fill((255,255,255))
        g.update()
        g.draw(screen)
        pg.display.update()
        clock.tick(60)

<filename>Juego(por nombrar)/src/clases/ambiente.py
import pygame as pg
from pygame import sprite
from itertools import cycle
from pygame.locals import *
import imutils
import math, random, sys
import cv2 as cv
import numpy as np
from settings import *
from ImageProcessing import *
from glob import glob
def delta(t, x0, x): #experimento para ver como funciona el posc de las sombras
    if x == x0:
        return t
    else:
        return t*(math.sin(x)+math.cos(x))
class circle(pg.sprite.Sprite): #no es realmente necesario
    def __init__(self, xy, radius, id, surface):
        super().__init__()
        self.xy = xy
        self.radius = radius
        self.id = id
        self.surface = surface
        self.color = (random.randint(128, 255), random.randint(128, 255),
                random.randint(128, 255), 255) if id != 5 else (255,255,0)
    def hasOverlapped(self, xy, radius):
        minDistance = 0.0 + radius + self.radius
        distance = math.hypot(xy[0] - self.xy[0], xy[1] - self.xy[1])
        if distance >= minDistance: return False

        radians = math.atan2(xy[1] - self.xy[1], xy[0] - self.xy[0])
        overlap = 1 + (minDistance - distance)
        return (math.cos(radians) * overlap, math.sin(radians) * overlap, overlap)
    def setXY(self, xy):
        self.xy = xy
    def draw(self):
        pg.draw.circle(self.surface, self.color, (int(self.xy[0]), int(self.xy[1])), self.radius, 0)
class fuenteLuz(pg.sprite.Sprite): #clase base para las fuentes de luz
    def __init__(self, imgPath, lightRadius, lightable):
        super().__init__() #sí, son sprites
        self.center = (0,0) #inútil
        self.x = 300
        self.y = 500
        self.lightable = lightable
        self.lightRadius = lightRadius
        self.animations = cycle(self.get_animations(imgPath)) #obtención de imagenes
        self.animation_counter = 0
        self.__image = next(self.animations)
        array = pg.surfarray.array3d(self.__image)
        self.circ = circle(self.__image.get_rect().center, lightRadius, 5, self.__image)
        self.rect = pg.rect.Rect(self.x, self.y, self.x+lightRadius, self.y+ lightRadius) #se centra la figura


        self.radius = self.circ.radius

    def get_animations(self, imgPath): #se consiguen animaciones y se agrandan para poder hacer un cubo de detección de luz
        self.preAnimation = [pg.image.load(img) for img in glob("animations/{}**".format(imgPath))]
        for a in self.preAnimation:
            a.convert()
        self.postAnimation = [pg.surfarray.make_surface(
                               cv.copyMakeBorder(pg.surfarray.array3d(surface),
                                                round(self.lightRadius-sizes[1]/2),
                                                round(self.lightRadius-sizes[1]/2),
                                                round(self.lightRadius-sizes[0]/2),
                                                round(self.lightRadius-sizes[0]/2),
                                                cv.BORDER_ISOLATED)
                                                )
                                for sizes, surface in zip([pg.surfarray.array3d(surf).shape for surf in self.preAnimation],
                                                          self.preAnimation)]
        for a in self.postAnimation:
            a.set_colorkey((0,0,0))
        return self.postAnimation
    @property
    def image(self): #bastante estandar

        if self.animation_counter > 4:
            self.animation_counter = 0
            self.__image = next(self.animations)
        return self.__image
    def update(self, x, y): #método que ocupa el grupo
        self.set_position(x,y)
        self.check_area()

        self.animation_counter += 1
    def set_position(self, CAMERA_X, CAMERA_Y): #mover la fuente de luz

        self.rect.x, self.rect.y = self.x-CAMERA_X, self.y-CAMERA_Y
    def check_area(self): #función que por ahora contiene la creación de sombras
        obj = pg.sprite.spritecollideany(self, self.lightable) #se buscavcolisiones entre el sprite de la luz y cualquier otro que este en el grupo de los colisionables
        if obj != None: #pulir si se puede (se puede)
            objX = obj.rect.centerx+obj.corrections[0] #se aplican correciones
            objY = obj.rect.centery+obj.corrections[1]
            Vect = np.array([self.rect.centerx-objX, #vextor móvil,  este va del centor del jugador al de la luz
                             self.rect.centery-objY
                            ])
            E_1 = np.array([1,0]) #vector canónico para comparar

            norm = np.linalg.norm(Vect)
            angle = math.acos(np.vdot(E_1, Vect/norm)) if objY < self.rect.centery else -math.acos(np.vdot(E_1, Vect/norm))
            rnorm = int(round(norm))^2 #transparencia 1/x^2
            angleShadow = angle - np.radians(90)
            angle -= np.radians(180)
            angle = -angle #comportamientos raros
            print(np.degrees(angle), delta(-30, math.pi/4, angle))
            if norm <= self.radius:
                alpha = 50/rnorm*255 if norm != 0 else 0
                shadow = Shadow(obj, alpha, angleShadow)
                xOffset, yOffset = 0, 0
                if angle >= 0 and angle < math.pi/2:
                    xOffset = math.cos(angle)*shadow.corrections[0]+delta(-15, math.pi/4, angle)
                    yOffset = math.cos(angle)*shadow.corrections[1]+delta(-15, math.pi/4, angle)
                d = pg.display.get_surface()

                d.blit(shadow.image, (obj.rect.x + xOffset , obj.rect.y + yOffset))
                d.blit(obj.image, (obj.rect.x, obj.rect.y))

                del shadow



    def draw(self, surface, point):
        x, y = point
        surface.blit(self, (x+self.w/2, y+h/2))

if __name__ == "__main__":
    clock = pg.time.Clock()
    fire = fuenteLuz("fire/frame", 3)
    pg.init()
    g = pg.sprite.Group()
    g.add(fire)
    screen =  pg.display.set_mode((500,400))
    screen.fill((255,255,255))



    while True:
        for event in pg.event.get():
            if event.type is pg.QUIT:
                pg.quit() # quit the screen
                break

        screen.fill((255,255,255))
        g.update()
        g.draw(screen)
        pg.display.update()
        clock.tick(60)

#experimento para ver como funciona el posc de las sombras #no es realmente necesario #clase base para las fuentes de luz #sí, son sprites #inútil #obtención de imagenes #se centra la figura #se consiguen animaciones y se agrandan para poder hacer un cubo de detección de luz #bastante estandar #método que ocupa el grupo #mover la fuente de luz #función que por ahora contiene la creación de sombras #se buscavcolisiones entre el sprite de la luz y cualquier otro que este en el grupo de los colisionables #pulir si se puede (se puede) #se aplican correciones #vextor móvil,  este va del centor del jugador al de la luz #vector canónico para comparar #transparencia 1/x^2 #comportamientos raros # quit the screen