update method
void
update()
Tick principal de la simulación - OPTIMIZADO
Implementation
void update() {
if (boids.isEmpty) return;
// Reconstruir spatial grid
_buildSpatialGrid();
// Parámetros dinámicos basados en audio
final dynamicPerception = perceptionRadius + (audioAmplitude * 15);
final dynamicMaxSpeed = maxSpeed + (audioAmplitude * 1.2);
final dynamicCohesion = cohesionWeight + (sin(audioPhase) * 0.15);
for (var boid in boids) {
final neighbors = _getNeighbors(boid, dynamicPerception);
// Acumuladores para las 3 reglas
double sepX = 0, sepY = 0;
double aliX = 0, aliY = 0;
double cohX = 0, cohY = 0;
int sepCount = 0, aliCount = 0;
for (var other in neighbors) {
final dx = boid.x - other.x;
final dy = boid.y - other.y;
final dSq = dx * dx + dy * dy;
final d = sqrt(dSq);
// Separación (muy cercanos)
final sepRadius = dynamicPerception * 0.35;
if (d < sepRadius && d > 0.001) {
final invD = 1 / (dSq + 1);
sepX += dx * invD;
sepY += dy * invD;
sepCount++;
}
// Alineación y cohesión
aliX += other.vx;
aliY += other.vy;
cohX += other.x;
cohY += other.y;
aliCount++;
}
double ax = 0, ay = 0;
// Aplicar separación
if (sepCount > 0) {
sepX /= sepCount;
sepY /= sepCount;
final sepMag = sqrt(sepX * sepX + sepY * sepY);
if (sepMag > 0.001) {
sepX = sepX / sepMag * maxSpeed - boid.vx;
sepY = sepY / sepMag * maxSpeed - boid.vy;
final steerMag = sqrt(sepX * sepX + sepY * sepY);
if (steerMag > maxForce) {
sepX = sepX / steerMag * maxForce;
sepY = sepY / steerMag * maxForce;
}
}
ax += sepX * separationWeight;
ay += sepY * separationWeight;
}
// Aplicar alineación y cohesión
if (aliCount > 0) {
// Alineación
aliX /= aliCount;
aliY /= aliCount;
final aliMag = sqrt(aliX * aliX + aliY * aliY);
if (aliMag > 0.001) {
aliX = aliX / aliMag * maxSpeed - boid.vx;
aliY = aliY / aliMag * maxSpeed - boid.vy;
final steerMag = sqrt(aliX * aliX + aliY * aliY);
if (steerMag > maxForce) {
aliX = aliX / steerMag * maxForce;
aliY = aliY / steerMag * maxForce;
}
}
ax += aliX * (alignmentWeight + audioFrequency * 0.2);
ay += aliY * (alignmentWeight + audioFrequency * 0.2);
// Cohesión
cohX = cohX / aliCount - boid.x;
cohY = cohY / aliCount - boid.y;
final cohMag = sqrt(cohX * cohX + cohY * cohY);
if (cohMag > 0.001) {
cohX = cohX / cohMag * maxSpeed - boid.vx;
cohY = cohY / cohMag * maxSpeed - boid.vy;
final steerMag = sqrt(cohX * cohX + cohY * cohY);
if (steerMag > maxForce) {
cohX = cohX / steerMag * maxForce;
cohY = cohY / steerMag * maxForce;
}
}
ax += cohX * dynamicCohesion;
ay += cohY * dynamicCohesion;
}
// Attractor
if (attractor != null) {
final toAttrX = attractor!.dx - boid.x;
final toAttrY = attractor!.dy - boid.y;
ax += toAttrX * attractorStrength * (1 + audioAmplitude);
ay += toAttrY * attractorStrength * (1 + audioAmplitude);
}
// Fuerza de pulso con el beat (simplificado)
if (audioBeat > 0 && audioAmplitude > 0.15) {
final beatPulse = sin(audioPhase * audioBeat * 0.5) * audioAmplitude * 0.2;
final centerX = width / 2;
final centerY = height / 2;
final fromCenterX = boid.x - centerX;
final fromCenterY = boid.y - centerY;
final dist = sqrt(fromCenterX * fromCenterX + fromCenterY * fromCenterY) + 1;
ax += (fromCenterX / dist) * beatPulse;
ay += (fromCenterY / dist) * beatPulse;
}
// Actualizar velocidad
boid.vx += ax;
boid.vy += ay;
// Limitar velocidad
final speed = sqrt(boid.vx * boid.vx + boid.vy * boid.vy);
if (speed > dynamicMaxSpeed) {
boid.vx = boid.vx / speed * dynamicMaxSpeed;
boid.vy = boid.vy / speed * dynamicMaxSpeed;
}
// Actualizar posición
boid.x += boid.vx;
boid.y += boid.vy;
// Actualizar profundidad Z (movimiento lento de vaivén)
boid.vz += (_random.nextDouble() - 0.5) * 0.001;
boid.vz = boid.vz.clamp(-0.008, 0.008);
boid.z += boid.vz;
boid.z = boid.z.clamp(0.0, 1.0);
// Wrap around edges
if (boid.x < 0) boid.x += width;
if (boid.x > width) boid.x -= width;
if (boid.y < 0) boid.y += height;
if (boid.y > height) boid.y -= height;
// Actualizar energía y tamaño
boid.energy = 0.5 + audioAmplitude * 0.5;
boid.size = 2.5 + (speed / dynamicMaxSpeed) * 1.2 + audioAmplitude * 1.0;
}
// Actualizar conexiones cada 4 frames para ahorrar CPU
_connectionUpdateCounter++;
if (_connectionUpdateCounter >= 4) {
_updateConnections();
_connectionUpdateCounter = 0;
}
notifyListeners();
}