🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

讓 AI 用 Flutter 實現了猗窩座的破壞殺·羅針動畫,這個過程如何馴服 AI

在經歷了之前的《用 AI 做了幾個超炫酷的 Flutter 動畫》的抽象實現後,就有了想讓 AI 做點更炫酷又更具象化的東西,剛好前段時間對無限城篇裡“三哥”的破壞殺·羅針展開印象深刻,所以就決定用它試試水。

image

整個過程體驗下來,只能說,AI 是很強,但是用過的也都知道,某種程度上其實也沒有那麼強,因為你需要和它同頻,只有馴服它之後,才能真正做到你想要的效果,比如這個效果我就和 AI 前後摩擦了 50 多個版本才勉強可以接受:

image

首先,我找了一張陣法的原圖,然後交給 AI,嘗試讓它理解圖片裡的線條來實現相應的效果,可想而知,結果慘不忍睹:

image

所以一開始我得到的是這樣的東西,相信這時候已經開始勸退大多數人了,並覺得 AI 也就這樣,根本做不出我們想要的:

image

但是這對我來說是符合預期的,因為我們給出的提示詞其實太空泛了,並且 AI 也並不能真的完全靠自己理解我們給出的圖片畫面,所以我嘗試通過豐富提示詞來完成,然後在這個過程我就得到了類似下方這樣的結果:

imageimage

這時候我開始意識到 AI 真的沒能直接理解圖片裡的畫面,所以我換了個思路,嘗試通過一些輔助手段讓 AI 理解整個構圖的形成:

imageimage

在通過提示詞和構圖坐標理解後,AI 是真的開始理解圖片的構圖了,至少它是真的能通過紅圈明白自己需要做的事情,這也體現在代碼的極坐標實現上,然後我就得到了下方的效果:

image

看起來是不是還差很多?但是不怕,只要方向是對的就行,接著就是各種微調和糾錯工作,這個過程需要不停給出明確指令,並及時糾正 AI 在代碼上的錯誤:

imageimageimageimageimageimageimage

當然,這個過程難免還是存在“心態爆炸”的時候,畢竟當你發現 AI 總是喜歡特立獨行,明明你已經糾正他了,但是他還是說:“是的,你的對的,但是我還是要保持我的做法”的時候,不罵兩句是真的意難平:

image

另外,由於會話長了之後,概率出現上下文丟失,就會出現一些奇奇怪怪的問題,比如本來就生氣了,這裡還直接將需求變成使用 Nano Banana pro 給我出圖而不是調整代碼,心態炸裂

當然,在經歷多次細節調整後,終於還是畫出了我們大概希望的效果,然後就是各種實現細節的打磨,這個時候 AI 對於具體調整的理解就很到位了,並且當你用箭頭指出新花樣修改的位置時,它也能及時調整。

比如我光速告訴它,雪花分叉的末端細節應該有角度的,並且對齊枝幹,這時候它就能做出正確的修改:

imageimage

有時候 AI 改起來太慢了,或者路線已經偏了的時候,就需要人工介入,通過人工進行微調,然後讓 AI 通過你的代碼再繼續:

imageimage

最終我得到了我需要的陣圖效果,雖然還原的不是 100%,但是再稍微人工調整下,就是可用的狀態了:

image

之後就是讓陣法繞 X 軸渲染,當然 AI 在最後還是再給我來了一錘,看起來提示詞是細節是真的一點都不能省:

image

但是有時候 AI 又很貼心,因為它會發現旋轉 90 度並不合理,需要讓角度調整為 80% 來實現我們的效果:

image

同時一些實現過程中的 bug 問題,它也能夠及時理解改正,並說明原因,這個也是非常不錯的場景學習:

image

可以看到,AI 實際上是能理解我們給出的圖片的,只是它無法直接完整且具體的理解,所以需要我們給去具體詳細的步驟,甚至幫助它去結構目標效果的構成,從而幫助我們實現最終的效果,這其實也是馴服 AI 的過程。

所有妄圖在「現階段」讓 AI 一步到位完成複雜邏輯的想法,大多數時候都會以放棄收尾

解讀實現

最後,我們來解讀代碼實現,其實整個實現上就是使用了 CustomPaintAnimationControllerMatrix4,在代碼實現結構上,主要有 “多階段動畫調度”、“數學繪圖原理”、“3D 空間變換”“角色合成特效” 四個核心部分。

多階段動畫調度

在動畫實現上, AI 並沒有使用單一的動畫控制器,而是定義了四個順序執行的控制器,模擬出從無到有的“展開”過程,具體實現邏輯是:

  • 繪製階段 (_drawController, 4秒): 陣法線條從中心向外生長
  • 旋轉階段 (_rotateController, 3秒): 陣法繪製完成後開始快速旋轉
  • 傾斜倒地階段 (_tiltController, 1.5秒): 陣法從 2D 平面倒下變成 3D 地面視角,同時伴隨亮度爆發
  • 角色顯現階段 (_characterController, 1秒): 角色配合光效浮現

同時,利用 CurvedAnimationInterval 將繪製階段細分為更自然的子步驟:

  • 0% - 20%: 畫中心圓
  • 20% - 50%: 畫內部放射線
  • 50% - 75%: 畫雪花狀組件(六邊形數字)
  • 75% - 100%: 畫外部延伸線

繪圖核心:極坐標系與發光筆觸

因為我提供了陣法的圓周對稱的示例,所以整個繪製邏輯都是圍繞圓形為基礎做佈局,其中主要就是以極坐標系為主:

1. 極坐標定位 (Polar Coordinates)

陣法是圓周對稱的,為了確定 12 個方位的坐標,代碼大量使用了極坐標轉換公式:

image

在這個實現裡,極坐標是繪製整個圓形陣法(羅針)的數學核心,簡單來說,就是螢幕繪圖使用的是直角坐標系 (x, y)(向右為 x,向下為 y),而圓形陣法的設計邏輯是基於圓心、角度和距離的,極坐標的作用就是將“角度+距離”翻譯成螢幕能理解的“x+y”。

因為在平面幾何中,確定一個點的位置有兩種方式:

  • 直角坐標: 告訴你離圓心水平走多遠 (x),垂直走多遠 (y)
  • 極坐標: 告訴你往哪個方向 (角度)看,然后走多遠 (r)

對於像“破壞殺·羅針”這種由 12 個重複元素組成的圓周對稱圖形,使用極坐標是最自然和高效的方法,所以 _polarToOffset 實現了上述的算法,它的作用就類似“翻譯官”:

// center: 圓心位置 (比如螢幕正中間)
// radius: 半徑 (距離圓心多遠)
// angle:  角度 (弧度制)
Offset _polarToOffset(Offset center, double radius, double angle) {
  return Offset(
    center.dx + radius * math.cos(angle), // x = r * cos(θ)
    center.dy + radius * math.sin(angle), // y = r * sin(θ)
  );
}
  • math.cos(angle) 計算出水平方向的分量
  • math.sin(angle) 計算出垂直方向的分量
  • 加上 center.dxcenter.dy :把坐標原點從螢幕左上角移動到畫布中心

而陣法有 12 個角,圓周是 360,所以每個角間隔 360 / 12 = 30:

// i 從 0 到 11
// i * 30: 每隔30度一個
// - 90:   數學上的0度通常在"3點鐘"方向,減90度是為了讓它從"12點鐘"方向開始
// * (math.pi / 180): 計算機只認弧度,不認角度,所以要轉換
final double angle = (i * 30 - 90) * (math.pi / 180);

同時陣法不是一個正圓,而是像雪花一樣長短交替的:

  • 偶數 (0, 2, 4...) : 長軸(對應主要的六邊形)。
  • 奇數 (1, 3, 5...) : 短軸(內縮的六邊形)
final bool isLongBranch = (i % 2 == 0); // 判斷是否為長軸

// 如果是長軸,半徑用 rLongHex (大半徑)
// 如果是短軸,半徑用 rShortHex (小半徑)
final double currentHexRadius = isLongBranch ? rLongHex : rShortHex;

有了 角度 (angle)半徑 (currentHexRadius),代碼就開始調用 _polarToOffset 算出具體的螢幕坐標點,用來畫線、畫六邊形,代碼定義了幾個關鍵點(從圓心向外):

  • start: 線條起始點(圓心附近)
  • hexInnerTarget: 六邊形的內側頂點
  • hexOuter: 六邊形的外側頂點
  • endInnerTarget: 最外圈尖刺的頂點
// 舉例:計算六邊形中心的位置
Offset hexCenter = _polarToOffset(center, currentHexRadius, angle);

另外,文字也需要角度,當你畫位於“3點鐘”方向的文字“參”時,文字應該是正的,但當你畫“6點鐘”方向的文字時,如果直接畫,文字可能會歪,所以代碼在繪製六邊形和文字時,用到了 canvas.rotate,這也是基於極坐標思想的延伸:

canvas.save();
canvas.translate(hexCenter.dx, hexCenter.dy); // 1. 先把畫筆移動到六邊形的位置
canvas.rotate(angle + math.pi / 2);           // 2. 旋轉畫筆,讓它對準圓心方向
// ... 開始畫六邊形 ...
canvas.restore();

2. 12方位循環與長短區分

循環 12 次繪製雪花瓣,代碼通過 i % 2 == 0 判斷當前是長軸還是短軸,從而實現錯落有致的視覺效果(類似於雪花結構)

for (int i = 0; i < 12; i++) {
  final bool isLongBranch = (i % 2 == 0); // 偶數為長軸,奇數為短軸
  // 根據長短軸決定繪製半徑 rLongHex 或 rShortHex
}

3. 彩虹光效實現原理 (Neon Glow)

Flutter 的 Canvas 其實並沒有“發光”屬性,所以 AI 代碼通過 “雙重繪製” 模擬發光:

  • 底層(光暈層): 使用高透明度顏色 + MaskFilter.blur (高斯模糊) + 較粗的線條
  • 頂層(核心層): 使用高亮度實心顏色 + 較細的線條
// 1. 畫光暈
canvas.drawLine(p1, p2, Paint()
  ..color = glowColor.withValues(alpha: glowOpacity)
  ..strokeWidth = width * 5 * bloomWidth // 筆觸加寬
  ..maskFilter = MaskFilter.blur(BlurStyle.normal, 12 * bloomWidth)); // 高斯模糊
​
// 2. 畫高亮實線
canvas.drawLine(p1, p2, Paint()
  ..color = brightColor // 純亮色
  ..strokeWidth = width);

矩陣變換 (3D Transformation)

陣法一開始是正對著螢幕的(2D),後來倒在地上變成(3D),這是通過 Transform 組件配合 Matrix4 實現的,具體邏輯是:

  • 透視效果 (Perspective): 設置矩陣的 (3, 2) 元素(即 wz 因子),產生近大遠小的透視感。
  • X軸旋轉 (RotateX): 將平面向後倒下
Matrix4 transformMatrix = Matrix4.identity();
transformMatrix.setEntry(3, 2, 0.002); // 關鍵:開啟透視,數值越小透視越弱
​
if (_tiltController.value > 0) {
  transformMatrix.rotateX(_tiltAnim.value); // 這裡的 value 是 0 到 -80度
  // 隨著倒下,稍微縮小一點比例以適應螢幕
  double scale = 1.0 - (_tiltController.value * 0.2); 
  transformMatrix.scale(scale);
}

角色與光影合成 (Character & Compositing)

最後一步是將人物 akaza.png 放置在陣法中心,由於人物圖片可能是全身像,中心點在腰部,但陣法中心應該對齊“腳底”,所以代碼使用了 Matrix4.translationValues 進行了微調:

// 向上偏移高度的 42%,讓腳底對準陣法中心
transform: Matrix4.translationValues(0, -targetHeight * 0.42, 0),

同時為了讓 2D 圖片看起來融入發光的陣法,代碼對人物圖片做了特殊的堆疊處理:

  • 層1(背光): 複製一份圖片 -> 使用 ColorFiltered 變成純青色剪影 -> 使用 ImageFiltered 進行強高斯模糊,這創造了一個與人物輪廓完全一致的“背光”
  • 層2(本體): 原始圖片覆蓋在上方
Stack(
  children: [
    // 1. 發光層 (Blur + ColorFilter)
    ImageFiltered(
      imageFilter: ui.ImageFilter.blur(sigmaX: 20.0, sigmaY: 20.0),
      child: ColorFiltered(
        colorFilter: const ColorFilter.mode(charGlowColor, BlendMode.srcIn),
        child: Image.asset(...), // 變成發光的剪影
      ),
    ),
    // 2. 原始圖層
    Image.asset(...),
  ],
)

同時陣法在倒地之後,也加強了光暈效果,配合角色光暈,這就形成了人物和陣法光暈的融合,也增加了立體感:

image

最後,還是想說,AI 真的在變強,而且變強的速度越來越快。

代碼鏈接

github.com/CarGuo/gsy_…


原文出處:https://juejin.cn/post/7580740563893977122


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝17   💬10   ❤️5
426
🥈
我愛JS
📝2   💬8   ❤️4
91
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付