Self organising variation

import coracle.Drawing
import coracle.Vector
import coracle.random
import coracle.randomInt
import coracle.shapes.Circle

class SelfOrganising2: Drawing() {

    val worldColour = 0xf5f2f0
    val boidColour = 0xffffff
    val nucleusColour = 0x000000
    var boids = mutableListOf()


    var inited = false

    val birthWaitMax = 30
    var birthWait = randomInt(birthWaitMax)

    private lateinit var blackHole: Vector
    
    override fun setup() {
        size(450, 450)
        blackHole = Vector(width/2, height/2)
        boids.add(Boid(width/2f, height/2f, 1f))
    }

    override fun draw() {
        background(worldColour)

        if(frame >= birthWait && boids.size < 150){
            boids.add(Boid(width/2 + random(-5, 5), height/2 + random(-5, 5), 1f))
            frame = 0
            birthWait = randomInt(birthWaitMax)
        }

        boids.forEach { boid ->
            boid.update().draw()
        }
    }

    inner class Boid(x: Float, y: Float, r: Float): Circle(x, y, r) {
        val maxRadius = 15
        private val maxSpeed = 0.3f
        private var location = Vector(x, y)
        private var velocity = Vector(0, 0)

        fun update(): Boid {

            if(r < maxRadius){
                r += 0.1f
            }

            var blackholeDirection = blackHole - location
            blackholeDirection.normalize()
            blackholeDirection *= 0.2f

            velocity += blackholeDirection
            location += velocity

            var closestDistance = Float.MAX_VALUE
            var closestIndex = -1

            if(boids.size == 1) return this

            boids.forEachIndexed { index, other ->
                if(other != this){
                    val distance = edgeDistance(other)
                    if(distance < closestDistance){
                        closestIndex = index
                        closestDistance = distance
                    }
                }

                var direction = location.direction(other.location)
                direction.normalize()
                direction *= (0.008f)/boids.size.toFloat()

                velocity += (direction)
                velocity.limit(maxSpeed)

            }

            val closest = boids[closestIndex]

            if(closestDistance < r) {
                var direction = location.direction(closest.location)
                direction.normalize()
                direction *= -0.4f

                velocity += (direction)
                velocity.limit(maxSpeed)

            }

            location += (velocity)

            if (this.location.x > width + r) this.location.x = -r
            if (this.location.x < -r) this.location.x = width.toFloat() + r
            if (this.location.y > height + r) this.location.y = -r
            if (this.location.y < -r) this.location.y = height.toFloat() + r

            x = location.x
            y = location.y

            return this
        }

        override fun draw(){
            noStroke()
            fill(boidColour, 0.60f)
            circle(location.x, location.y, r)

            fill(nucleusColour, 0.7f)
            circle(location.x, location.y, 1)
        }
    }
}