@name bt_test
@inputs 
@outputs 
@persist [PX PY DX DY]:array Num CT DT [Mass Mass2 Friction Radius Diameter Coeff] E:entity
@trigger none

if (first()) {
    #-- settings
    E = entity()

    Radius = 2
    Mass = 10
    Friction = 0.98
    Diameter = Radius*2
    Coeff = (Mass / (Mass + Mass))
    Mass2 = Mass*2

    function void ball(N,Pos:vector) {
        holoCreate(N)
        holoPos(N, E:toWorld(Pos))
        holoParent(N, E)
        holoScaleUnits(N, vec(Radius * 2))
        holoModel(N, "hq_sphere")
    }
    
    #-- Cue ball
    Num++
    PX[Num, number] = 0
    PY[Num, number] = 0
    DX[Num, number] = 200
    DY[Num, number] = 0
    
    ball(Num, vec(PX[Num, number], PY[Num, number], 0))
    
    #-- Balls
    for (I = 0, 4) {
        for (J = 0, I) {
            Num++
            
            PX[Num, number] = I*Radius*2 + 200
            PY[Num, number] = J*Radius*2 - I*Radius
            DX[Num, number] = 0
            DY[Num, number] = 0
    
            ball(Num, vec(PX[Num, number], PY[Num, number], 0))           
        }
    }

    ball(Num, vec(PX[Num, number], PY[Num, number], 0))
    
    CT = curtime()
}

interval(60)

DT = curtime() - CT
CT = curtime()

local N = 0
while (opcounter() < maxquota() & N < Num) {
        N++
        
        PX[N, number] = PX[N, number] + DX[N, number]*DT
        PY[N, number] = PY[N, number] + DY[N, number]*DT
        DX[N, number] = DX[N, number]*Friction
        DY[N, number] = DY[N, number]*Friction
        
        local R = N
        while (R < Num) {
            R++
            
            local Distance = sqrt((PX[R, number] - PX[N, number])^2 + (PY[R, number] - PY[N, number])^2)
            if (Distance < Diameter) {
                local Normal = atan(PY[R, number] - PY[N, number], PX[R, number] - PX[N, number])
                
                local Impulse = (Diameter - Distance)*Coeff
                
                PX[N, number] = PX[N, number] + Impulse*cos(Normal + 180)
                PY[N, number] = PY[N, number] + Impulse*sin(Normal + 180)
                PX[R, number] = PX[R, number] + Impulse*cos(Normal)
                PY[R, number] = PY[R, number] + Impulse*sin(Normal)    
                
                local NX = cos(Normal)
                local NY = sin(Normal)
                
                local A1 = DX[N, number]*NX + DY[N, number]*NY
                local A2 = DX[R, number]*NX + DY[R, number]*NY
                
                local DP = (2 * (A1 - A2)) / Mass2
                
                DX[N, number] = DX[N, number] - (DP*Mass*NX)
                DY[N, number] = DY[N, number] - (DP*Mass*NY)
                DX[R, number] = DX[R, number] + (DP*Mass*NX)
                DY[R, number] = DY[R, number] + (DP*Mass*NY)
            }
        }

        holoPos(N, E:toWorld(vec(PX[N, number], PY[N, number], 0)))

}


