# deux groupes d'agent
# chaque groupe a son propre objecti
# modifiable avec un click de souris (click gauche/ click droit)
#
# tous les agents se repoussent mutuellement



#objectif a atteindre
class Objectif():
    
    def __init__(self,x,y):
        self.x=x
        self.y=y


#agent avec un objectif
class Agent():

    
    
    def __init__(self,dx,dy,obj):
        self.objectif=obj
        self.x=dx
        self.y=dy

        #par defaut pas de dynamique
        self.vx=20
        self.vy=0
        self.ax=0
        self.ay=0
        self.dt=0.1
        
        #acceleration maximale
        self.aMax=20        

    def evoluer(self):
        self.vx=self.vx+self.ax*self.dt
        self.vy=self.vy+self.ay*self.dt
        self.x=self.x+self.vx*self.dt
        self.y=self.y+self.vy*self.dt


    def afficher(self):
        print("(x,y): "+str(self.x)+","+str(self.y)+"  vx,vy: "+str(self.vx)+","+str(self.vy))


    #retourne la norme de la force de repulsion fonction distance
    def normeSociale(self,distance):
        force=5
        if (distance>100):
            return(0)
        return force*((100)/distance-1)

    # met a jour son acceleration en fonction objectif
    # et des autres agents
    def calculerObj(self,agents):
        from math import sqrt
        
        #vitesse souhaitee (maximisee)
        vx=(self.objectif.x-self.x)
        vy=(self.objectif.y-self.y)
        vMax=50
        vnorme=sqrt(vx*vx+vy*vy)
        if (vnorme>vMax):
            vx=vx*vMax/vnorme
            vy=vy*vMax/vnorme
            
        

        #calcule la commande à donner
        dvx=vx-self.vx
        dvy=vy-self.vy

        #norme avec aMax       
        norme=sqrt(dvx*dvx+dvy*dvy)
        if (norme>self.aMax):
            dvx=dvx*self.aMax/norme
            dvy=dvy*self.aMax/norme
        self.ax=dvx
        self.ay=dvy


        #prise en compte autres agents
        for agent in agents:
            if (agent!=self):
                dx=agent.x-self.x
                dy=agent.y-self.y
                distance=self.distance(agent)
    
                #met a jour la force
                normeForce=self.normeSociale(distance)
                self.ax-=normeForce*dx/distance
                self.ay-=normeForce*dy/distance


    
        
        
            
    def distance(self,O):
        dx=(O.x-self.x)
        dy=(O.y-self.y)
        d2=dx*dx+dy*dy
        from math import sqrt
        return sqrt(d2)


# systeme c'est un agent et un objectif
class Systeme():

    #initialise le systeme avec les coordonnees de l'agent
    def __init__(self,num):
        from random import uniform
        self.num=num
        self.objectif1=Objectif(200,200)
        self.objectif2=Objectif(400,400)
        self.agents=[]
        
        for i in range(num):
            x=uniform(0,500)
            y=uniform(0,700)
            ag=Agent(x,y,self.objectif1)
            ag.groupe=1
            self.agents+=[ag]
        for i in range(num):
            x=uniform(0,500)
            y=uniform(0,700)
            ag=Agent(x,y,self.objectif2)
            ag.groupe=2
            self.agents+=[ag]

    #evoluer le jeu
    def evoluer(self):
        for agent in self.agents:
            agent.calculerObj(self.agents)
            agent.evoluer()
        

    def dessiner(self):
        WHITE = (0xFF, 0xFF, 0xFF)
        RED = (0xFF, 0x00, 0x00)
        GREEN= (0x00, 0xFF, 0x00)
        PURPLE= (0xFF, 0x00, 0xFF)
        BLUE = (0x00, 0x00, 0xFF)
        BLACK = (0x00, 0x00, 0x00)
        screen.fill(WHITE)
        pygame.draw.ellipse(screen,GREEN,(self.objectif1.x-5,jeu.objectif1.y-5,10,10))
        pygame.draw.ellipse(screen,PURPLE,(self.objectif2.x-5,jeu.objectif2.y-5,10,10))
        for agent in self.agents:
            if (agent.groupe==1):
                pygame.draw.ellipse(screen,RED,(agent.x-5,agent.y-5,10,10))
            if (agent.groupe==2):
                pygame.draw.ellipse(screen,BLUE,(agent.x-5,agent.y-5,10,10))                
            pygame.draw.line(screen,BLACK,[agent.x,agent.y],[agent.x+agent.vx,agent.y+agent.vy])


print("controle de deux groupes d'agents")
print("click de souris modifie le but")
print("- bouton 1 - but 1")
print("- bouton 2 - but 2")


           
import pygame
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Moteur")


# boolean boucle
done = False
jeu=Systeme(10)
# horloge
clock = pygame.time.Clock()
# -------- boucle de jeu
while not done:
    
    # --- gestion evenements
    for event in pygame.event.get(): 
        # quitter
        if event.type == pygame.QUIT: 
            done = True

        #si on appui souris: change objectif
        if event.type == pygame.MOUSEBUTTONDOWN:
            #si c'est bouton 1 - objectif 1
            if (pygame.mouse.get_pressed()[0]):
                jeu.objectif1.x=pygame.mouse.get_pos()[0]
                jeu.objectif1.y=pygame.mouse.get_pos()[1]
            if (pygame.mouse.get_pressed()[2]):
                jeu.objectif2.x=pygame.mouse.get_pos()[0]
                jeu.objectif2.y=pygame.mouse.get_pos()[1]
            
            

            
    # --- evolution
    jeu.evoluer()
    
    # --- dessin
    jeu.dessiner()
        
    # --- mise a jour graphique
    pygame.display.flip()
    # --- attente
    clock.tick(60)

pygame.quit()
   

