萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 軟體知識 >  >> 影像處理 >> Flash 教學

Flash CS4 氣泡動畫實戰:AS3 物理碰撞彈射完整程式碼解析

效果預覽

10 個彩色氣泡在舞台內自由浮動、邊界反彈、相互碰撞彈開,擁有真實物理質感。純 AS3 程式碼生成,無時間軸動畫,效能極佳。

核心架構

  • Ball 類別: 程式繪製漸層圓形、物理屬性
  • 主類別: 陣列管理所有球、ENTER_FRAME 驅動、碰撞檢測雙重迴圈

完整程式碼逐段解析

1. 氣泡繪製函式 ball(r)


function ball(r:int):MovieClip {
    var col:uint = 0xffffff * Math.random();  // 隨機顏色
    var sh:MovieClip = new MovieClip();
    
    // 放射狀漸層:白(中心半透明) → 隨機色(不透明) → 同色(邊緣)
    sh.graphics.beginGradientFill(
        GradientType.RADIAL, 
        [0xffffff, col, col],      // 顏色陣列
        [0.5, 1, 1],               // Alpha 陣列
        [0, 200, 255]              // 色標位置(0-255)
    );
    sh.graphics.drawCircle(0, 0, r);  // 圓心 (0,0),半徑 r
    sh.graphics.endFill();
    return sh;
}

視覺效果: 中心高光(白、半透明)→ 主體色 → 邊緣同色,模擬氣泡折射光澤。

2. 初始化 10 顆氣泡


var ballArr:Array = [];
for (var i:int = 0; i < 10; i++) {
    var balls:MovieClip = ball(Math.random() * 20 + 20);  // 半徑 20-40
    addChild(balls);
    
    // 隨機初始位置(確保完整在舞台內)
    balls.x = Math.random() * (stage.stageWidth - balls.width) + balls.width/2;
    balls.y = Math.random() * (stage.stageHeight - balls.height) + balls.height/2;
    
    // 自訂物理屬性
    balls.vx = Math.random() * 2 - 1;  // -1 到 1
    balls.vy = Math.random() * 2 - 1;
    
    ballArr.push(balls);
}
addEventListener(Event.ENTER_FRAME, frame);

3. 幀驅動函式 frame(e)


function frame(e):void {
    // 第一輪:邊界檢測 + 位置更新
    for (var i:int = 0; i < ballArr.length; i++) {
        var balls:MovieClip = ballArr[i];
        balls.x += balls.vx;
        balls.y += balls.vy;
        
        // 左/右邊界
        if (balls.x < balls.width/2) {
            balls.x = balls.width/2;
            balls.vx *= -1;
        }
        if (balls.x > stage.stageWidth - balls.width/2) {
            balls.x = stage.stageWidth - balls.width/2;
            balls.vx *= -1;
        }
        // 上/下邊界
        if (balls.y < balls.height/2) {
            balls.y = balls.height/2;
            balls.vy *= -1;
        }
        if (balls.y > stage.stageHeight - balls.height/2) {
            balls.y = stage.stageHeight - balls.height/2;
            balls.vy *= -1;
        }
    }
    
    // 第二輪:兩兩碰撞檢測(O(n²) 但 n=10 極輕量)
    for (var j:int = 0; j < ballArr.length; j++) {
        var ball0:MovieClip = ballArr[j];
        for (var m:int = j + 1; m < ballArr.length; m++) {
            var ball1:MovieClip = ballArr[m];
            
            var dx:Number = ball1.x - ball0.x;
            var dy:Number = ball1.y - ball0.y;
            var dist:Number = Math.sqrt(dx*dx + dy*dy);  // 兩心距離
            var minDist:Number = ball0.width/2 + ball1.width/2;  // 半徑和
            
            if (dist <= minDist) {  // 碰撞!
                // 碰撞角度
                var angle:Number = Math.atan2(dy, dx);
                // 目標分離位置(稍微超出避免黏連)
                var tx:Number = ball0.x + Math.cos(angle) * minDist * 1.01;
                var ty:Number = ball0.y + Math.sin(angle) * minDist * 1.01;
                
                // 簡易動量交換(質量相等)
                ball0.vx = -(tx - ball1.x);
                ball0.vy = -(ty - ball1.y);
                ball1.vx =  (tx - ball1.x);
                ball1.vy =  (ty - ball1.y);
            }
        }
    }
}

物理演算法解析

邊界反彈

位置修正到邊界內側 + 速度分量取反(vx *= -1),完美彈性碰撞。

球球碰撞

  1. 計算兩心向量 (dx, dy) 與距離 dist
  2. 若 dist <= r0 + r1 → 碰撞
  3. 碰撞法線角度 angle = atan2(dy, dx)
  4. 目標分離位置:沿法線方向推開至 minDist * 1.01
  5. 速度更新:簡化為沿法線交換速度分量(等質量彈性碰撞近似)

效能與擴展建議

創意變化

  • 重力場: 每幀 vy += gravity,底部堆疊
  • 滑鼠吸引/排斥: 計算滑鼠向量施加力
  • 連結彈簧: 相鄰球用 Hooke 定律連結,形成軟體體
  • 流體模擬: SPH 算法、密度壓力場(需更複雜架構)
  • 視覺風格: 發光濾鏡、半透明疊加、貼圖材質

常見 Bug 與修正

  1. 球卡在邊界: 位置修正必須在速度反轉之前,且修正到 radius 而非 0
  2. 重疊不分離: 1.01 係數關鍵,無此微量分離會反覆碰撞卡死
  3. 高速穿透: 幀位移 > 直徑時會穿透,需連續碰撞檢測 (CCD) 或限制最大速度
  4. 記憶體洩漏: 移除球時必須 removeChild + 陣列 splice + 移除事件監聽
copyright © 萬盛學電腦網 all rights reserved
優化方向做法
空間分割網格/四叉樹減少碰撞檢測對數(n>100 時必要)
對象池預建球對象池,避免頻繁 new/GC
cacheAsBitmap靜態外觀球啟用 ball.cacheAsBitmap = true
向量繪製優化共用一個 Shape 實例繪製所有球(進階)