feat(math): add blueprint nodes for math library (#442)

* feat(math): add blueprint nodes for math library

- Add Vector2 blueprint nodes (Make, Break, arithmetic, Length, Normalize, Dot, Cross, Distance, Lerp, Rotate, FromAngle)
- Add Fixed32 blueprint nodes (conversions, arithmetic, math functions, comparison)
- Add FixedVector2 blueprint nodes (Make, Break, arithmetic, vector operations)
- Add Color blueprint nodes (Make, Break, conversions, color manipulation, constants)
- Add documentation with visual examples for all math blueprint nodes
- Update sidebar navigation to include math module

* fix(ci): adjust build order - blueprint before math

math package now depends on blueprint, so blueprint must be built first
This commit is contained in:
YHH
2026-01-06 10:32:02 +08:00
committed by GitHub
parent e90a42b1c9
commit bffe90b6a1
20 changed files with 3408 additions and 2 deletions

View File

@@ -247,6 +247,14 @@ export default defineConfig({
{ label: '实际示例', slug: 'modules/blueprint/examples', translations: { en: 'Examples' } },
],
},
{
label: '数学库',
translations: { en: 'Math' },
items: [
{ label: '概述', slug: 'modules/math', translations: { en: 'Overview' } },
{ label: '蓝图节点', slug: 'modules/math/blueprint-nodes', translations: { en: 'Blueprint Nodes' } },
],
},
{
label: '程序生成',
translations: { en: 'Procgen' },

View File

@@ -472,6 +472,12 @@ Control blueprint execution flow:
| `Less` | A < B | Boolean |
| `Less Or Equal` | A <= B | Boolean |
### Extended Math Nodes
> **Vector2, Fixed32, FixedVector2, Color** and other advanced math nodes are provided by the `@esengine/ecs-framework-math` module.
>
> See: [Math Blueprint Nodes](/en/modules/math/blueprint-nodes)
### Example: Clamp Value
<div class="bp-graph" style="" data-connections='[{"from":"en-rand-result","to":"en-clamp-value","type":"float"}]'>
@@ -604,6 +610,7 @@ Blueprint-defined variables automatically generate Get and Set nodes:
## Related Documentation
- [Math Blueprint Nodes](/en/modules/math/blueprint-nodes) - Vector2, Fixed32, Color and other math nodes
- [Blueprint Editor Guide](/en/modules/blueprint/editor-guide) - Learn how to use the editor
- [Custom Nodes](/en/modules/blueprint/custom-nodes) - Create custom nodes
- [Blueprint VM](/en/modules/blueprint/vm) - Runtime API

View File

@@ -0,0 +1,489 @@
---
title: "Math Blueprint Nodes"
description: "Blueprint nodes provided by the Math module - Vector2, Fixed32, FixedVector2, Color"
---
This document describes the blueprint nodes provided by the `@esengine/ecs-framework-math` module.
> **Note**: These nodes require the math module to be installed.
<script src="/js/blueprint-graph.js"></script>
## Pin Type Legend
<div class="bp-legend">
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#7ecd32" stroke-width="2"/></svg> Float</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#2196F3" stroke-width="2"/></svg> Vector2</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#9C27B0" stroke-width="2"/></svg> Fixed32</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#673AB7" stroke-width="2"/></svg> FixedVector2</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#FF9800" stroke-width="2"/></svg> Color</div>
</div>
---
## Vector2 Nodes
2D vector operations for position, velocity, and direction calculations.
### Node List
| Node | Description | Inputs | Output |
|------|-------------|--------|--------|
| `Make Vector2` | Create Vector2 from X, Y | X, Y | Vector2 |
| `Break Vector2` | Decompose Vector2 to X, Y | Vector | X, Y |
| `Vector2 +` | Vector addition | A, B | Vector2 |
| `Vector2 -` | Vector subtraction | A, B | Vector2 |
| `Vector2 *` | Vector scaling | Vector, Scalar | Vector2 |
| `Vector2 Length` | Get vector length | Vector | Float |
| `Vector2 Normalize` | Normalize to unit vector | Vector | Vector2 |
| `Vector2 Dot` | Dot product | A, B | Float |
| `Vector2 Cross` | 2D cross product | A, B | Float |
| `Vector2 Distance` | Distance between two points | A, B | Float |
| `Vector2 Lerp` | Linear interpolation | A, B, T | Vector2 |
| `Vector2 Rotate` | Rotate by angle (radians) | Vector, Angle | Vector2 |
| `Vector2 From Angle` | Create unit vector from angle | Angle | Vector2 |
### Example: Calculate Movement Direction
Direction vector from start to end point:
<div class="bp-graph" data-connections='[{"from":"v2-start","to":"v2-sub-a","type":"vector2"},{"from":"v2-end","to":"v2-sub-b","type":"vector2"},{"from":"v2-sub-result","to":"v2-norm-in","type":"vector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 130px;">
<div class="bp-node-header math" style="background: #2196F3;">Make Vector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-start"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 180px; width: 130px;">
<div class="bp-node-header math" style="background: #2196F3;">Make Vector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">100</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">50</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-end"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 220px; top: 90px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 -</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-sub-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-sub-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-sub-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 400px; top: 55px; width: 140px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 Normalize</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-norm-in"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
</div>
### Example: Circular Motion
Calculate circular position using angle and radius:
<div class="bp-graph" data-connections='[{"from":"v2-angle-out","to":"v2-scale-vec","type":"vector2"},{"from":"v2-scale-result","to":"v2-add-b","type":"vector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 40px; width: 150px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 From Angle</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Angle</span>
<span class="bp-pin-value">1.57</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-angle-out"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 230px; top: 40px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 *</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-scale-vec"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Scalar</span>
<span class="bp-pin-value">50</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-scale-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 420px; top: 40px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 +</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#2196F3" stroke-width="2"/></svg></span>
<span class="bp-pin-label">A (Center)</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-add-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Position</span>
</div>
</div>
</div>
</div>
---
## Fixed32 Nodes (Fixed-Point Numbers)
Q16.16 fixed-point number operations for lockstep networking games, ensuring cross-platform calculation consistency.
### Node List
| Node | Description | Inputs | Output |
|------|-------------|--------|--------|
| `Fixed32 From Float` | Create from float | Float | Fixed32 |
| `Fixed32 From Int` | Create from integer | Int | Fixed32 |
| `Fixed32 To Float` | Convert to float | Fixed32 | Float |
| `Fixed32 To Int` | Convert to integer | Fixed32 | Int |
| `Fixed32 +` | Addition | A, B | Fixed32 |
| `Fixed32 -` | Subtraction | A, B | Fixed32 |
| `Fixed32 *` | Multiplication | A, B | Fixed32 |
| `Fixed32 /` | Division | A, B | Fixed32 |
| `Fixed32 Abs` | Absolute value | Value | Fixed32 |
| `Fixed32 Sqrt` | Square root | Value | Fixed32 |
| `Fixed32 Floor` | Floor | Value | Fixed32 |
| `Fixed32 Ceil` | Ceiling | Value | Fixed32 |
| `Fixed32 Round` | Round | Value | Fixed32 |
| `Fixed32 Sign` | Sign (-1, 0, 1) | Value | Fixed32 |
| `Fixed32 Min` | Minimum | A, B | Fixed32 |
| `Fixed32 Max` | Maximum | A, B | Fixed32 |
| `Fixed32 Clamp` | Clamp to range | Value, Min, Max | Fixed32 |
| `Fixed32 Lerp` | Linear interpolation | A, B, T | Fixed32 |
### Example: Lockstep Movement Speed Calculation
<div class="bp-graph" data-connections='[{"from":"f32-speed","to":"f32-mul-a","type":"fixed32"},{"from":"f32-dt","to":"f32-mul-b","type":"fixed32"},{"from":"f32-mul-result","to":"f32-tofloat","type":"fixed32"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 From Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Value</span>
<span class="bp-pin-value">5.0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-speed"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Speed</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 160px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 From Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Value</span>
<span class="bp-pin-value">0.016</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-dt"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">DeltaTime</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 240px; top: 75px; width: 120px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 *</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-mul-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-mul-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-mul-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 430px; top: 75px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 To Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-tofloat"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Fixed</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">Float</span>
</div>
</div>
</div>
</div>
---
## FixedVector2 Nodes (Fixed-Point Vectors)
Fixed-point vector operations for deterministic physics calculations, suitable for lockstep networking.
### Node List
| Node | Description | Inputs | Output |
|------|-------------|--------|--------|
| `Make FixedVector2` | Create from X, Y floats | X, Y | FixedVector2 |
| `Break FixedVector2` | Decompose to X, Y floats | Vector | X, Y |
| `FixedVector2 +` | Vector addition | A, B | FixedVector2 |
| `FixedVector2 -` | Vector subtraction | A, B | FixedVector2 |
| `FixedVector2 *` | Scale by Fixed32 | Vector, Scalar | FixedVector2 |
| `FixedVector2 Negate` | Negate vector | Vector | FixedVector2 |
| `FixedVector2 Length` | Get length | Vector | Fixed32 |
| `FixedVector2 Normalize` | Normalize | Vector | FixedVector2 |
| `FixedVector2 Dot` | Dot product | A, B | Fixed32 |
| `FixedVector2 Cross` | 2D cross product | A, B | Fixed32 |
| `FixedVector2 Distance` | Distance between points | A, B | Fixed32 |
| `FixedVector2 Lerp` | Linear interpolation | A, B, T | FixedVector2 |
### Example: Deterministic Position Update
<div class="bp-graph" data-connections='[{"from":"fv2-pos","to":"fv2-add-a","type":"fixedvector2"},{"from":"fv2-vel","to":"fv2-add-b","type":"fixedvector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 150px;">
<div class="bp-node-header math" style="background: #673AB7;">Make FixedVector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">10</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">20</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="fv2-pos"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">Position</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 180px; width: 150px;">
<div class="bp-node-header math" style="background: #673AB7;">Make FixedVector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">1</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="fv2-vel"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">Velocity</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 250px; top: 90px; width: 140px;">
<div class="bp-node-header math" style="background: #673AB7;">FixedVector2 +</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="fv2-add-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="fv2-add-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">New Position</span>
</div>
</div>
</div>
</div>
---
## Color Nodes
Color creation and manipulation nodes.
### Node List
| Node | Description | Inputs | Output |
|------|-------------|--------|--------|
| `Make Color` | Create from RGBA | R, G, B, A | Color |
| `Break Color` | Decompose to RGBA | Color | R, G, B, A |
| `Color From Hex` | Create from hex string | Hex | Color |
| `Color To Hex` | Convert to hex string | Color | String |
| `Color From HSL` | Create from HSL | H, S, L | Color |
| `Color To HSL` | Convert to HSL | Color | H, S, L |
| `Color Lerp` | Color interpolation | A, B, T | Color |
| `Color Lighten` | Lighten | Color, Amount | Color |
| `Color Darken` | Darken | Color, Amount | Color |
| `Color Saturate` | Increase saturation | Color, Amount | Color |
| `Color Desaturate` | Decrease saturation | Color, Amount | Color |
| `Color Invert` | Invert | Color | Color |
| `Color Grayscale` | Convert to grayscale | Color | Color |
| `Color Luminance` | Get luminance | Color | Float |
### Color Constants
| Node | Value |
|------|-------|
| `Color White` | (1, 1, 1, 1) |
| `Color Black` | (0, 0, 0, 1) |
| `Color Red` | (1, 0, 0, 1) |
| `Color Green` | (0, 1, 0, 1) |
| `Color Blue` | (0, 0, 1, 1) |
| `Color Transparent` | (0, 0, 0, 0) |
### Example: Color Transition Animation
<div class="bp-graph" data-connections='[{"from":"color-a","to":"color-lerp-a","type":"color"},{"from":"color-b","to":"color-lerp-b","type":"color"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 120px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Red</div>
<div class="bp-node-body">
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="color-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 130px; width: 120px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Blue</div>
<div class="bp-node-body">
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="color-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 220px; top: 50px; width: 130px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Lerp</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="color-lerp-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="color-lerp-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">T</span>
<span class="bp-pin-value">0.5</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
</div>
### Example: Create Color from Hex
<div class="bp-graph" data-connections='[{"from":"hex-color","to":"break-color","type":"color"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 30px; width: 150px;">
<div class="bp-node-header math" style="background: #FF9800;">Color From Hex</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#e060e0" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Hex</span>
<span class="bp-pin-value">"#FF5722"</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="hex-color"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 250px; top: 20px; width: 130px;">
<div class="bp-node-header math" style="background: #FF9800;">Break Color</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="break-color"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">R</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">G</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
</div>
</div>
</div>
---
## Related Documentation
- [Blueprint Node Reference](/en/modules/blueprint/nodes) - Core blueprint nodes
- [Blueprint Editor Guide](/en/modules/blueprint/editor-guide) - Editor usage
- [Custom Nodes](/en/modules/blueprint/custom-nodes) - Create custom nodes

View File

@@ -0,0 +1,79 @@
---
title: "Math Library"
description: "ESEngine Math Library - Vector2, Fixed32, FixedVector2, Color and other math types"
---
The `@esengine/ecs-framework-math` module provides common math types and operations for game development.
## Core Types
| Type | Description |
|------|-------------|
| `Vector2` | 2D floating-point vector for position, velocity, direction |
| `Fixed32` | Q16.16 fixed-point number for deterministic lockstep calculations |
| `FixedVector2` | 2D fixed-point vector for deterministic physics |
| `Color` | RGBA color |
## Features
### Vector2
- Addition, subtraction, scaling
- Dot product, cross product
- Length, normalization
- Distance, interpolation
- Rotation, angle conversion
### Fixed32 Fixed-Point Numbers
Designed for lockstep networking games, ensuring cross-platform calculation consistency:
- Basic operations: add, subtract, multiply, divide
- Math functions: absolute value, square root, rounding
- Comparison, clamping, interpolation
- Constants: 0, 1, 0.5, PI, 2*PI
### Color
- RGB/RGBA creation and decomposition
- Hex string conversion
- HSL color space conversion
- Color operations: lighten, darken, saturation adjustment
- Color blending and interpolation
## Blueprint Support
The math library provides rich blueprint nodes, see:
- [Math Blueprint Nodes](/en/modules/math/blueprint-nodes)
## Installation
```bash
pnpm add @esengine/ecs-framework-math
```
## Basic Usage
```typescript
import { Vector2, Fixed32, FixedVector2, Color } from '@esengine/ecs-framework-math';
// Vector2
const pos = new Vector2(10, 20);
const dir = pos.normalized();
// Fixed32 (lockstep)
const speed = Fixed32.from(5.0);
const dt = Fixed32.from(0.016);
const distance = speed.mul(dt);
// FixedVector2
const fixedPos = FixedVector2.from(10, 20);
const fixedVel = FixedVector2.from(1, 0);
const newPos = fixedPos.add(fixedVel);
// Color
const red = Color.RED;
const blue = Color.BLUE;
const purple = Color.lerp(red, blue, 0.5);
```

View File

@@ -470,6 +470,12 @@ description: "蓝图内置 ECS 操作节点完整参考"
| `Less` | A < B | Boolean |
| `Less Or Equal` | A <= B | Boolean |
### 扩展数学节点
> **Vector2、Fixed32、FixedVector2、Color** 等高级数学节点由 `@esengine/ecs-framework-math` 模块提供。
>
> 详见:[数学库蓝图节点](/modules/math/blueprint-nodes)
### 示例:钳制数值
<div class="bp-graph" style="" data-connections='[{"from":"rand-result","to":"clamp-value","type":"float"}]'>
@@ -535,6 +541,7 @@ description: "蓝图内置 ECS 操作节点完整参考"
## 相关文档
- [数学库蓝图节点](/modules/math/blueprint-nodes) - Vector2、Fixed32、Color 等数学节点
- [蓝图编辑器指南](/modules/blueprint/editor-guide) - 学习如何使用编辑器
- [自定义节点](/modules/blueprint/custom-nodes) - 创建自定义节点
- [蓝图虚拟机](/modules/blueprint/vm) - 运行时 API

View File

@@ -0,0 +1,489 @@
---
title: "数学库蓝图节点"
description: "Math 模块提供的蓝图节点 - Vector2、Fixed32、FixedVector2、Color"
---
本文档介绍 `@esengine/ecs-framework-math` 模块提供的蓝图节点。
> **注意**:这些节点需要安装 math 模块才能使用。
<script src="/js/blueprint-graph.js"></script>
## 引脚类型说明
<div class="bp-legend">
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#7ecd32" stroke-width="2"/></svg> 浮点数 (Float)</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#2196F3" stroke-width="2"/></svg> Vector2</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#9C27B0" stroke-width="2"/></svg> Fixed32</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#673AB7" stroke-width="2"/></svg> FixedVector2</div>
<div class="bp-legend-item"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="transparent" stroke="#FF9800" stroke-width="2"/></svg> Color</div>
</div>
---
## Vector2 节点
2D 向量操作,用于位置、速度、方向计算。
### 节点列表
| 节点 | 说明 | 输入 | 输出 |
|------|------|------|------|
| `Make Vector2` | 从 X, Y 创建 Vector2 | X, Y | Vector2 |
| `Break Vector2` | 分解 Vector2 为 X, Y | Vector | X, Y |
| `Vector2 +` | 向量加法 | A, B | Vector2 |
| `Vector2 -` | 向量减法 | A, B | Vector2 |
| `Vector2 *` | 向量缩放 | Vector, Scalar | Vector2 |
| `Vector2 Length` | 获取向量长度 | Vector | Float |
| `Vector2 Normalize` | 归一化为单位向量 | Vector | Vector2 |
| `Vector2 Dot` | 点积 | A, B | Float |
| `Vector2 Cross` | 2D 叉积 | A, B | Float |
| `Vector2 Distance` | 两点距离 | A, B | Float |
| `Vector2 Lerp` | 线性插值 | A, B, T | Vector2 |
| `Vector2 Rotate` | 旋转(弧度) | Vector, Angle | Vector2 |
| `Vector2 From Angle` | 从角度创建单位向量 | Angle | Vector2 |
### 示例:计算移动方向
从起点到终点的方向向量:
<div class="bp-graph" data-connections='[{"from":"v2-start","to":"v2-sub-a","type":"vector2"},{"from":"v2-end","to":"v2-sub-b","type":"vector2"},{"from":"v2-sub-result","to":"v2-norm-in","type":"vector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 130px;">
<div class="bp-node-header math" style="background: #2196F3;">Make Vector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-start"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 180px; width: 130px;">
<div class="bp-node-header math" style="background: #2196F3;">Make Vector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">100</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">50</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-end"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 220px; top: 90px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 -</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-sub-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-sub-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-sub-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 400px; top: 55px; width: 140px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 Normalize</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-norm-in"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
</div>
### 示例:圆周运动
使用角度和半径计算圆周位置:
<div class="bp-graph" data-connections='[{"from":"v2-angle-out","to":"v2-scale-vec","type":"vector2"},{"from":"v2-scale-result","to":"v2-add-b","type":"vector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 40px; width: 150px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 From Angle</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Angle</span>
<span class="bp-pin-value">1.57</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-angle-out"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 230px; top: 40px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 *</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-scale-vec"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Vector</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Scalar</span>
<span class="bp-pin-value">50</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="v2-scale-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 420px; top: 40px; width: 120px;">
<div class="bp-node-header math" style="background: #2196F3;">Vector2 +</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#2196F3" stroke-width="2"/></svg></span>
<span class="bp-pin-label">A (Center)</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="v2-add-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#2196F3"/></svg></span>
<span class="bp-pin-label">Position</span>
</div>
</div>
</div>
</div>
---
## Fixed32 定点数节点
Q16.16 定点数运算,适用于帧同步网络游戏,保证跨平台计算一致性。
### 节点列表
| 节点 | 说明 | 输入 | 输出 |
|------|------|------|------|
| `Fixed32 From Float` | 从浮点数创建 | Float | Fixed32 |
| `Fixed32 From Int` | 从整数创建 | Int | Fixed32 |
| `Fixed32 To Float` | 转换为浮点数 | Fixed32 | Float |
| `Fixed32 To Int` | 转换为整数 | Fixed32 | Int |
| `Fixed32 +` | 加法 | A, B | Fixed32 |
| `Fixed32 -` | 减法 | A, B | Fixed32 |
| `Fixed32 *` | 乘法 | A, B | Fixed32 |
| `Fixed32 /` | 除法 | A, B | Fixed32 |
| `Fixed32 Abs` | 绝对值 | Value | Fixed32 |
| `Fixed32 Sqrt` | 平方根 | Value | Fixed32 |
| `Fixed32 Floor` | 向下取整 | Value | Fixed32 |
| `Fixed32 Ceil` | 向上取整 | Value | Fixed32 |
| `Fixed32 Round` | 四舍五入 | Value | Fixed32 |
| `Fixed32 Sign` | 符号 (-1, 0, 1) | Value | Fixed32 |
| `Fixed32 Min` | 最小值 | A, B | Fixed32 |
| `Fixed32 Max` | 最大值 | A, B | Fixed32 |
| `Fixed32 Clamp` | 钳制范围 | Value, Min, Max | Fixed32 |
| `Fixed32 Lerp` | 线性插值 | A, B, T | Fixed32 |
### 示例:帧同步移动速度计算
<div class="bp-graph" data-connections='[{"from":"f32-speed","to":"f32-mul-a","type":"fixed32"},{"from":"f32-dt","to":"f32-mul-b","type":"fixed32"},{"from":"f32-mul-result","to":"f32-tofloat","type":"fixed32"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 From Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Value</span>
<span class="bp-pin-value">5.0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-speed"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Speed</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 160px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 From Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Value</span>
<span class="bp-pin-value">0.016</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-dt"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">DeltaTime</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 240px; top: 75px; width: 120px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 *</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-mul-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-mul-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="f32-mul-result"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 430px; top: 75px; width: 150px;">
<div class="bp-node-header math" style="background: #9C27B0;">Fixed32 To Float</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="f32-tofloat"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#9C27B0"/></svg></span>
<span class="bp-pin-label">Fixed</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">Float</span>
</div>
</div>
</div>
</div>
---
## FixedVector2 定点向量节点
定点向量运算,用于确定性物理计算,适用于帧同步。
### 节点列表
| 节点 | 说明 | 输入 | 输出 |
|------|------|------|------|
| `Make FixedVector2` | 从 X, Y 浮点数创建 | X, Y | FixedVector2 |
| `Break FixedVector2` | 分解为 X, Y 浮点数 | Vector | X, Y |
| `FixedVector2 +` | 向量加法 | A, B | FixedVector2 |
| `FixedVector2 -` | 向量减法 | A, B | FixedVector2 |
| `FixedVector2 *` | 按 Fixed32 缩放 | Vector, Scalar | FixedVector2 |
| `FixedVector2 Negate` | 取反 | Vector | FixedVector2 |
| `FixedVector2 Length` | 获取长度 | Vector | Fixed32 |
| `FixedVector2 Normalize` | 归一化 | Vector | FixedVector2 |
| `FixedVector2 Dot` | 点积 | A, B | Fixed32 |
| `FixedVector2 Cross` | 2D 叉积 | A, B | Fixed32 |
| `FixedVector2 Distance` | 两点距离 | A, B | Fixed32 |
| `FixedVector2 Lerp` | 线性插值 | A, B, T | FixedVector2 |
### 示例:确定性位置更新
<div class="bp-graph" data-connections='[{"from":"fv2-pos","to":"fv2-add-a","type":"fixedvector2"},{"from":"fv2-vel","to":"fv2-add-b","type":"fixedvector2"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 150px;">
<div class="bp-node-header math" style="background: #673AB7;">Make FixedVector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">10</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">20</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="fv2-pos"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">Position</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 180px; width: 150px;">
<div class="bp-node-header math" style="background: #673AB7;">Make FixedVector2</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">X</span>
<span class="bp-pin-value">1</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Y</span>
<span class="bp-pin-value">0</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="fv2-vel"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">Velocity</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 250px; top: 90px; width: 140px;">
<div class="bp-node-header math" style="background: #673AB7;">FixedVector2 +</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="fv2-add-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="fv2-add-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#673AB7"/></svg></span>
<span class="bp-pin-label">New Position</span>
</div>
</div>
</div>
</div>
---
## Color 颜色节点
颜色创建与操作节点。
### 节点列表
| 节点 | 说明 | 输入 | 输出 |
|------|------|------|------|
| `Make Color` | 从 RGBA 创建 | R, G, B, A | Color |
| `Break Color` | 分解为 RGBA | Color | R, G, B, A |
| `Color From Hex` | 从十六进制字符串创建 | Hex | Color |
| `Color To Hex` | 转换为十六进制字符串 | Color | String |
| `Color From HSL` | 从 HSL 创建 | H, S, L | Color |
| `Color To HSL` | 转换为 HSL | Color | H, S, L |
| `Color Lerp` | 颜色插值 | A, B, T | Color |
| `Color Lighten` | 提亮 | Color, Amount | Color |
| `Color Darken` | 变暗 | Color, Amount | Color |
| `Color Saturate` | 增加饱和度 | Color, Amount | Color |
| `Color Desaturate` | 降低饱和度 | Color, Amount | Color |
| `Color Invert` | 反色 | Color | Color |
| `Color Grayscale` | 灰度化 | Color | Color |
| `Color Luminance` | 获取亮度 | Color | Float |
### 颜色常量
| 节点 | 值 |
|------|------|
| `Color White` | (1, 1, 1, 1) |
| `Color Black` | (0, 0, 0, 1) |
| `Color Red` | (1, 0, 0, 1) |
| `Color Green` | (0, 1, 0, 1) |
| `Color Blue` | (0, 0, 1, 1) |
| `Color Transparent` | (0, 0, 0, 0) |
### 示例:颜色过渡动画
<div class="bp-graph" data-connections='[{"from":"color-a","to":"color-lerp-a","type":"color"},{"from":"color-b","to":"color-lerp-b","type":"color"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 10px; width: 120px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Red</div>
<div class="bp-node-body">
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="color-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 20px; top: 130px; width: 120px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Blue</div>
<div class="bp-node-body">
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="color-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 220px; top: 50px; width: 130px;">
<div class="bp-node-header math" style="background: #FF9800;">Color Lerp</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="color-lerp-a"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="color-lerp-b"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#7ecd32" stroke-width="2"/></svg></span>
<span class="bp-pin-label">T</span>
<span class="bp-pin-value">0.5</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Result</span>
</div>
</div>
</div>
</div>
### 示例:从 Hex 创建颜色
<div class="bp-graph" data-connections='[{"from":"hex-color","to":"break-color","type":"color"}]'>
<svg class="bp-connections"></svg>
<div class="bp-node" style="position: absolute; left: 20px; top: 30px; width: 150px;">
<div class="bp-node-header math" style="background: #FF9800;">Color From Hex</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="none" stroke="#e060e0" stroke-width="2"/></svg></span>
<span class="bp-pin-label">Hex</span>
<span class="bp-pin-value">"#FF5722"</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin" data-pin="hex-color"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
</div>
</div>
<div class="bp-node" style="position: absolute; left: 250px; top: 20px; width: 130px;">
<div class="bp-node-header math" style="background: #FF9800;">Break Color</div>
<div class="bp-node-body">
<div class="bp-pin-row input">
<span class="bp-pin" data-pin="break-color"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#FF9800"/></svg></span>
<span class="bp-pin-label">Color</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">R</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">G</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">B</span>
</div>
<div class="bp-pin-row output">
<span class="bp-pin"><svg width="12" height="12"><circle cx="6" cy="6" r="4" fill="#7ecd32"/></svg></span>
<span class="bp-pin-label">A</span>
</div>
</div>
</div>
</div>
---
## 相关文档
- [蓝图节点参考](/modules/blueprint/nodes) - 核心蓝图节点
- [蓝图编辑器指南](/modules/blueprint/editor-guide) - 编辑器使用方法
- [自定义节点](/modules/blueprint/custom-nodes) - 创建自定义节点

View File

@@ -0,0 +1,79 @@
---
title: "数学库"
description: "ESEngine 数学库 - Vector2, Fixed32, FixedVector2, Color 等数学类型"
---
`@esengine/ecs-framework-math` 模块提供游戏开发常用的数学类型和运算。
## 核心类型
| 类型 | 说明 |
|------|------|
| `Vector2` | 2D 浮点向量,用于位置、速度、方向 |
| `Fixed32` | Q16.16 定点数,用于帧同步确定性计算 |
| `FixedVector2` | 2D 定点向量,用于确定性物理 |
| `Color` | RGBA 颜色 |
## 功能特性
### Vector2
- 加法、减法、缩放
- 点积、叉积
- 长度、归一化
- 距离、插值
- 旋转、角度转换
### Fixed32 定点数
专为帧同步网络游戏设计,保证跨平台计算一致性:
- 基本运算:加、减、乘、除
- 数学函数:绝对值、平方根、取整
- 比较、钳制、插值
- 常量0、1、0.5、π、2π
### Color 颜色
- RGB/RGBA 创建与分解
- Hex 十六进制转换
- HSL 色彩空间转换
- 颜色操作:提亮、变暗、饱和度调整
- 颜色混合与插值
## 蓝图支持
数学库提供了丰富的蓝图节点,详见:
- [数学库蓝图节点](/modules/math/blueprint-nodes)
## 安装
```bash
pnpm add @esengine/ecs-framework-math
```
## 基本用法
```typescript
import { Vector2, Fixed32, FixedVector2, Color } from '@esengine/ecs-framework-math';
// Vector2
const pos = new Vector2(10, 20);
const dir = pos.normalized();
// Fixed32 (帧同步)
const speed = Fixed32.from(5.0);
const dt = Fixed32.from(0.016);
const distance = speed.mul(dt);
// FixedVector2
const fixedPos = FixedVector2.from(10, 20);
const fixedVel = FixedVector2.from(1, 0);
const newPos = fixedPos.add(fixedVel);
// Color
const red = Color.RED;
const blue = Color.BLUE;
const purple = Color.lerp(red, blue, 0.5);
```

View File

@@ -296,6 +296,10 @@ nav.sidebar-content ul li a[aria-current="page"] {
.bp-conn.component { stroke: #7030c0; }
.bp-conn.array { stroke: #7030c0; }
.bp-conn.any { stroke: #707070; }
.bp-conn.vector2 { stroke: #2196F3; }
.bp-conn.fixed32 { stroke: #9C27B0; }
.bp-conn.fixedvector2 { stroke: #673AB7; }
.bp-conn.color { stroke: #FF9800; }
/* ==================== Node Container ==================== */
.bp-node {