diff --git a/play/assets/tmpGame/script/utils.js b/play/assets/tmpGame/script/utils.js
index 16e03db6950cf4d70a0dce5145f56c7ecbb4b7e5..36e92fb7b834658a3c44a30063e2c033bc04e182 100644
--- a/play/assets/tmpGame/script/utils.js
+++ b/play/assets/tmpGame/script/utils.js
@@ -133,46 +133,63 @@ export async function asyncDelay(time) {
     })
 }
 
+export async function showFireworks(baseNode, nodeList, pos = cc.v2(0, 0), side = cc.v2(0, 100), range = 50, number = 100) {
+    new Array(number).fill(' ').forEach(async (_, i) => {
 
+        let rabbonNode = new cc.Node();
+        rabbonNode.parent = baseNode;
+        rabbonNode.x = pos.x;
+        rabbonNode.y = pos.y;
+        rabbonNode.angle = 60 * Math.random() - 30;
 
-export async function showFireworks(baseNode, nodeList, pos = cc.v2(0, 0), side = cc.v2(0, 100), range = 50, number = 100) {
-    for (let i = 0; i < number; i++) {
-        const node = cc.instantiate(nodeList[RandomInt(nodeList.length)]);
-        node.parent = baseNode;
+        let node = cc.instantiate(nodeList[RandomInt(nodeList.length)]);
+        node.parent = rabbonNode;
         node.active = true;
-        node.x = pos.x;
-        node.y = pos.y;
-        node.angle = 360 * Math.random();
-        node.scale = 0.5;
+        node.x = 0;
+        node.y = 0;
+        node.angle = 0;
 
         const rate = Math.random();
         const angle = Math.PI * (Math.random() * 2 - 1);
 
+        await asyncTweenBy(rabbonNode, 0.3, {
+            x: side.x * rate + Math.cos(angle) * range * rate,
+            y: side.y * rate + Math.sin(angle) * range * rate
+        }, {
+            easing: 'quadIn'
+        });
+
+        cc.tween(rabbonNode)
+            .by(8, { y: -2000 })
+            .start();
+
+        rabbonFall(rabbonNode);
+
+        await asyncDelay(Math.random());
         cc.tween(node)
-            .by(0.3, {
-                x: side.x * rate + Math.cos(angle) * range * rate,
-                y: side.y * rate + Math.sin(angle) * range * rate
-            })
-            .call(async () => {
-                for (let i = 0; i < 8; i++) {
-                    await rabbonFall(node);
-                }
-                cc.tween(node)
-                    .to(0.3, { opacity: 0 })
-                    .call(() => {
-                        node.active = false;
-                        node.parent = null;
-                        node = null;
-                    })
-                    .start();
+            .by(0.15, { x: -10, angle: -10 })
+            .by(0.3, { x: 20, angle: 20 })
+            .by(0.15, { x: -10, angle: -10 })
+            .union()
+            .repeatForever()
+            .start();
+
+        cc.tween(rabbonNode)
+            .delay(5)
+            .to(0.3, { opacity: 0 })
+            .call(() => {
+                node.stopAllActions();
+                node.active = false;
+                node.parent = null;
+                node = null;
             })
-            .by(8, { y: -2000 })
             .start();
-    }
+    });
 }
 
 async function rabbonFall(node) {
     const time = 1 + Math.random();
     const offsetX = RandomInt(-200, 200) * time;
     await asyncTweenBy(node, time, { x: offsetX, angle: offsetX * 60 / 200 });
+    rabbonFall(node);
 }
\ No newline at end of file