跳到內容

JavaScript Layers

JavaScript 可用於多種 Layers,包括 JavaScript UtilityJavaScript ShapeJavaScript DeformerJavaScript EmitterJavaScript ModifierJavaScript Emitter,以在 Cavalry 中設定多種 Attribute 類型。

可以透過表達式寫入的主要資料類型有:

名稱attrType描述
Doubledouble帶有小數位的數字。例如 4.153
Double2double2一組兩個 double。例如 Position 103.453, 487.543
Double3double3一組三個 double。例如 Position (2.5D) 103.453, 487.543, 50.730
Intint不帶小數點的整數。例如 4
Int2int2一組兩個整數。例如 Composition Resolution 1920, 1080
Boolbool具有兩種狀態的核取方塊——10(開/關)。
Stringstring可包含字母數字字元和符號。
Colorcolor包含 RGBA 值的 Attribute。
Point DatapointDataDistributions 產生的點。參見 Using Point data
AssetassetId接受 .json.txt.csv Asset。參見 Using Assets
LayerlayerId接受任何 Layer。參見 Using Layer data

這意味著支援 JavaScript 的 Layers 可以連接到 Cavalry 中的上述任何資料類型。

連接兩個不相容的資料類型(例如表達式返回 int,但 JavaScript 連接到 string),將觸發嘗試自動轉換資料類型,但強烈建議正確匹配輸出類型,以便更好地控制浮點精度等因素。

以上所有類型也可作為輸入,並可透過指令碼中的 Attribute 名稱引用。要新增另一個 Attribute 作為變數,請點選 UI 底部的 + 按鈕並選擇相關資料類型。然後可以從具有匹配資料類型的另一個 Attribute 建立輸入連線。預設情況下,變數名稱是字母 n 後跟數字,例如 n0n1。但是,可以透過右鍵點選 Attribute 並選擇 Rename 來重新命名。

變數名稱區分大小寫,不能包含空格。

JavaScript 匯入一個 Context Module,其中包含幾個與 Duplicator 搭配使用的有用成員。

  • ctx.index - Duplicator 的 Index。
  • ctx.count - Duplicator 的 Count。
  • ctx.positionX/ ctx.positionY - Duplicator 點的位置。
  • ctx.layerId - 請求 JavaScript Layer 進行計算的 Layer 的 id。
  • ctx.attributeId - 請求 JavaScript Layer 進行計算的 Attribute 的 id。

有關使用這些值的範例,請參閱 Create > Demo Scenes > JavaScript > Position to Color 預設。

複雜資料類型(color、int2、double2)是遵循以下模式的簡單 JavaScript 物件:

let color = { r: 200, g: 100, b: 50, a: 255};let someDouble2 = { x: 200.4, y: 55.6};

為簡單起見,可以修改或返回輸入值。

使用此 Layer 編寫 JavaScript 表達式的主要規則是必須返回一個值。例如,以下表達式呼叫一個函式,該函式返回一個值:

function toCelsius(fahrenheit) { return (5/9) * (fahrenheit-32);}toCelsius(n0);

在全域級別設定變數時,請使用 var 而非 let/const。因為 JavaScript Layers 每幀執行,使用 let/const 全域宣告將在表達式第二次執行時失敗,因為變數已存在且無法重新賦值。

JavaScript 可以利用 JSON/Text/CSV Assets(CSV Asset 包括 Google Sheets 和 Microsoft Excel)。要與 JavaScript Layers 一起使用這些 Asset 類型,請點選 + 按鈕並選擇 Add Text/JSON/CSV Asset。這將建立一個新的 Attribute,它可以接收支援的 Asset 作為輸入。

  • Text Assets 將作為字串載入。
  • JSON Assets 將作為 JSON 物件字面量載入。
  • CSV Assets 將作為 JSON 物件字面量載入。
    • 頂層 Object 屬性都將與欄名匹配。
    • 每欄包含:
      • rows - 列資料陣列(數字或字串)。
      • min - 欄中的最小數值(如果欄為數字)。
      • max - 欄中的最大數值(如果欄為數字)。
// 列印連接到 Attribute 'n1' 的 CSV 的所有欄名。var columns = Object.keys(n1);for (var columnName of columns) { console.log(columnName);}
// 返回連接到 Attribute 'n1' 的 CSV/Google Sheet 中標題為 'Cavalry' 的欄的最大值。n1.Cavalry.max;// 如果欄標題包含空格,例如 'Cavalry Users'。n1["Cavalry Users"].min;
// 返回連接到 Attribute 'n1' 的 CSV/Google Sheet 中標題為 'Cavalry Users' 的欄的所有值的總和。function setSum() { let total = 0; for (let row of n1["Cavalry Users"].rows) { total += Number(row) } return total;}setSum();
// 給定一個連接到 Attribute 'n1' 的 JSON asset,輸出 "title" 鍵的值。// 將 JavaScript Utility 連接到 Text Shape 的 String。/* example.json 的內容{ "data": { "title": "My Title", "body": "This is some body text." }}*/n1.data.title

請注意,作為 Asset 使用時,僅支援 Excel 檔案的第一個標籤頁。

  1. 建立一個 JavaScript Deformer
  2. 點選其 Attribute Editor UI 底部的 + 按鈕,新增選擇 ‘Add Point Data’ 以新增新的 Dynamic Attribute。
  3. 建立一個 Duplicator
  4. 右鍵點選 Distribution Attribute 並選擇 Reveal Generator
  5. 刪除 Duplicator(保留 Grid Distribution)。
  6. 連接 gridDistribution.id→javaScriptDeformer.n1(這是在步驟 2 中新增的新 Point Data Attribute)。
  7. 將 JavaScript 輸入中的程式碼替換為以下之一:
    • console.log(n1.points[0].position.x); 或;
    • console.log(n1.points.length);
  8. 建立一個 Shape。
  9. 連接 javaScriptDeformer.id→shape.deformers。這是 JavaScript Deformer 進行計算所必需的。

將播放頭步進到下一幀以將值列印到 JavaScript Console。第一個範例將輸出第一個 pointId 的 position.x(變更 [0] 中的值以返回其他 pointId),而第二個範例將返回 Distribution 中的點數(預設 3x3 網格為 9 個)。

連接的 Layer 的類型決定了可用的物件:

  • Drawable(例如 Null、Falloff)- 將提供一個 layer 物件,包含以下 2D World Space Transform 變數:
    • position(例如 n1.layer.positionn1.layer.position.x
    • rotation(例如 n1.layer.rotationn1.layer.rotation.z
    • scale(例如 n1.layer.scalen1.layer.scale.x
  • Shape(例如 Rectangle、Duplicator)- 將提供一個 mesh 屬性(例如 n1.mesh),表示 local space 中的 mesh 層級。mesh 屬性是來自 Cavalry ModuleMesh class 的實例。

使用 Layer 動態輸入時,使用 hasInput 來確定是否連接了 Layer。例如,這可用於防止嘗試讀取不存在的 mesh 資料。

// 假設 'n1' 是一個 Layer 動態輸入。console.log(n1.hasInput);// 如果 Layer 連接到 'n1',則返回 true。

JavaScript 不區分 2D 和 2.5D Layers,因此對 2D Layers 使用 rotation.z

// Closest Point on Path 範例。// 將其貼上到 JavaScript Editor 中,然後點選 'Run Script'。// 建立一個 Null 和兩個 Shapesconst nullId = api.create("null", "Move Me!!");const ellipse1Id = api.primitive("ellipse", "Ellipse");const ellipse2Id = api.primitive("ellipse", "Path");api.setFill(ellipse2Id, false);api.setStroke(ellipse2Id, true);api.set(ellipse2Id, {"generator.radius": [350,350]});// 建立一個 JavaScript Utility。const jsUtil = api.create("javaScript");// 新增動態 Attributes 和表達式。api.addDynamic(jsUtil, "array", "layerId");api.addDynamic(jsUtil, "array", "layerId");const expression = 'function getPoint() {\n\xa0\xa0\xa0\xa0let toPt = n2.layer.position;\n\xa0\xa0\xa0\xa0let closestPoint = n1.path.findClosestPoint(toPt.x, toPt.y);\n\xa0\xa0\xa0\xa0return closestPoint.position;\n};\ngetPoint();'api.set(jsUtil, {"expression": expression});// 建立連線。api.connect(ellipse2Id, "id", jsUtil, "array.1");api.connect(nullId, "id", jsUtil, "array.2");api.connect(jsUtil, "id", ellipse1Id, "position");

JavaScript Layers 是 Cavalry 中唯一知道具體是哪個 Layer 和 Attribute 觸發計算的地方。此資訊可用於根據正在計算哪個連線來輸出不同的值。使用 ctx.layerIdctx.attributeId 屬性來存取此資訊。

// 在此範例中,假設一個 JSON Asset 連接到 JavaScript Layer 的 n1 Attribute。function getText() { if (ctx.layerId == "textShape#1") { // 如果 textShape#1 向 JavaScript 請求值,返回給定的 JSON 值 return n1["colors"]["Green"]; } else if (ctx.layerId == "textShape#2") { // 如果 textShape#2 向 JavaScript 請求值,返回不同的 JSON 值 return n1["colors"]["Yellow"]; } return "None";}getText();

表達式的錯誤將列印到 JavaScript Console

透過 Cmd/Ctrl + Return 執行表達式時,需要輸出連線才能使表達式執行。

See Scripting→ Example JavaScript Expressions→