10 個彩色氣泡在舞台內自由浮動、邊界反彈、相互碰撞彈開,擁有真實物理質感。純 AS3 程式碼生成,無時間軸動畫,效能極佳。
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;
}
視覺效果: 中心高光(白、半透明)→ 主體色 → 邊緣同色,模擬氣泡折射光澤。
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);
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),完美彈性碰撞。
(dx, dy) 與距離 distdist <= r0 + r1 → 碰撞angle = atan2(dy, dx)minDist * 1.01| 優化方向 | 做法 |
|---|---|
| 空間分割 | 網格/四叉樹減少碰撞檢測對數(n>100 時必要) |
| 對象池 | 預建球對象池,避免頻繁 new/GC |
| cacheAsBitmap | 靜態外觀球啟用 ball.cacheAsBitmap = true |
| 向量繪製優化 | 共用一個 Shape 實例繪製所有球(進階) |