Problem: When users shook the device, bubbles were moving excessively, bouncing around, and sometimes changing sizes uncontrollably.
Root Cause: The addShakeEffect() method was applying movement effects (MoveEffect.by()) on top of the existing physics system, causing conflicting forces.
Solution:
ScaleEffect.by() to ScaleEffect.to() with absolute scaling to prevent conflict with lifecycle scalingProblem: Existing bubbles were flickering and momentarily changing to maximum size during shake.
Root Cause: ScaleEffect.by() was adding to the bubble's current scale, which is already dynamically changing based on lifecycle progress, causing conflict between the two scaling systems.
Solution:
ScaleEffect.by()) to absolute (ScaleEffect.to()) scalingProblem: Bubbles were overlapping/intersecting each other, especially after collisions or shake effects.
Root Cause: Insufficient collision detection and separation logic that didn't account for dynamic bubble scaling.
Solution:
_handleBubbleCollision() now calculates required separation based on actual bubble sizes including scale_getValidSpawnPosition() accounts for bubble scaling when calculating safe distances// Before: Movement + Scale + Rotation effects
void addShakeEffect() {
final moveEffect = MoveEffect.by(shakeDirection, ...); // REMOVED
final scaleEffect = ScaleEffect.by(Vector2.all(0.3), ...); // Reduced to 0.2
final rotateEffect = RotateEffect.by(0.4, ...); // Reduced to 0.2
}
// After: Only visual effects
void addShakeEffect() {
final scaleEffect = ScaleEffect.by(Vector2.all(0.2), ...); // Visual only
final rotateEffect = RotateEffect.by(0.2, ...); // Visual only
// No movement effects
}
void _handleBubbleCollision(Bubble other, Set<Vector2> intersectionPoints) {
// Calculate actual bubble sizes including scale
final thisRadius = (startSize / 2) * scale.x;
final otherRadius = (startSize / 2) * other.scale.x;
final requiredDistance = thisRadius + otherRadius + 5.0; // 5px padding
// Immediate separation if overlapping
if (distance < requiredDistance) {
final separationNeeded = requiredDistance - distance;
final separationVector = direction * (separationNeeded / 2);
position.add(separationVector);
other.position.sub(separationVector);
}
}
Vector2? _getValidSpawnPosition() {
// Account for bubble scaling in distance calculations
final bubbleRadius = (bubbleMaxDiameter / 2) * bubble.scale.x;
final newBubbleRadius = bubbleMaxDiameter / 2;
final requiredDistance = bubbleRadius + newBubbleRadius + 20.0; // 20px padding
}
✅ Shake Response: Bubbles now show subtle visual feedback without unwanted movement ✅ Collision Prevention: Bubbles maintain proper spacing and don't overlap ✅ Tilt Sensitivity: Reduced excessive movement during device orientation changes ✅ Performance: No impact on game performance, all optimizations maintained