如何在Unity Inspector中显示游戏对象的贝塞尔加速度曲线图表?
在Unity Inspector中显示自定义贝塞尔曲线预览的实现方法
核心思路
通过Unity的**自定义编辑器(Custom Editor)**扩展功能,在Inspector中绘制自定义的速度-时间曲线预览,实时响应参数修改。具体分为两步:编写存储曲线参数的运行时脚本,再编写编辑器脚本实现曲线绘制。
步骤1:编写运行时参数脚本
创建一个IceMovement脚本,存储贝塞尔曲线的控制点参数,并实现速度计算逻辑:
using UnityEngine; public class IceMovement : MonoBehaviour { // 第二控制点:(到达最大速度的时间, 最大速度) public Vector2 maxSpeedPoint = new Vector2(2f, 5f); // 第三控制点:用于调整曲线形状 public Vector2 controlPoint = new Vector2(1f, 1f); // 根据时间t计算当前速度 public float GetSpeedAtTime(float t) { t = Mathf.Clamp01(t / maxSpeedPoint.x); // 三点贝塞尔公式:P0(0,0), P1(controlPoint), P2(maxSpeedPoint) float oneMinusT = 1f - t; return 2 * oneMinusT * t * controlPoint.y + t * t * maxSpeedPoint.y; } }
步骤2:编写自定义编辑器脚本
在项目中创建Editor文件夹(必须命名为Editor,Unity才会识别为编辑器脚本),创建IceMovementEditor脚本,实现Inspector中的曲线绘制:
using UnityEditor; using UnityEngine; [CustomEditor(typeof(IceMovement))] public class IceMovementEditor : Editor { private IceMovement _movement; private Texture2D _curveTexture; private void OnEnable() { _movement = (IceMovement)target; _curveTexture = new Texture2D(400, 200); UpdateCurvePreview(); } public override void OnInspectorGUI() { // 先绘制默认的参数面板 DrawDefaultInspector(); // 添加曲线预览区域 EditorGUILayout.Space(); EditorGUILayout.LabelField("速度-时间曲线预览", EditorStyles.boldLabel); Rect previewRect = EditorGUILayout.GetControlRect(false, 200); EditorGUI.DrawPreviewTexture(previewRect, _curveTexture); // 参数修改时实时更新曲线 if (GUI.changed) { UpdateCurvePreview(); } } private void UpdateCurvePreview() { // 清空纹理为白色背景 Color[] pixels = _curveTexture.GetPixels(); System.Array.Fill(pixels, Color.white); _curveTexture.SetPixels(pixels); // 绘制坐标轴 DrawLine(new Vector2(20, _curveTexture.height - 20), new Vector2(_curveTexture.width - 20, _curveTexture.height - 20), Color.black); DrawLine(new Vector2(20, _curveTexture.height - 20), new Vector2(20, 20), Color.black); float maxTime = _movement.maxSpeedPoint.x; float maxSpeed = _movement.maxSpeedPoint.y; // 避免参数为0的异常情况 if (maxTime <= 0 || maxSpeed <= 0) { _curveTexture.Apply(); return; } // 采样绘制贝塞尔曲线 int sampleCount = 100; Vector2 prevPoint = Vector2.zero; bool isFirstPoint = true; for (int i = 0; i <= sampleCount; i++) { float t = (float)i / sampleCount * maxTime; float speed = _movement.GetSpeedAtTime(t); // 将数值转换为纹理坐标 float x = 20 + (t / maxTime) * (_curveTexture.width - 40); float y = _curveTexture.height - 20 - (speed / maxSpeed) * (_curveTexture.height - 40); Vector2 currentPoint = new Vector2(x, y); if (!isFirstPoint) { DrawLine(prevPoint, currentPoint, Color.blue); } prevPoint = currentPoint; isFirstPoint = false; } // 绘制控制点:红色为第三控制点,绿色为最大速度点 Vector2 controlTexPos = new Vector2(20 + (_movement.controlPoint.x / maxTime) * (_curveTexture.width - 40), _curveTexture.height - 20 - (_movement.controlPoint.y / maxSpeed) * (_curveTexture.height - 40)); DrawCircle(controlTexPos, 3, Color.red); Vector2 maxSpeedTexPos = new Vector2(20 + (_movement.maxSpeedPoint.x / maxTime) * (_curveTexture.width - 40), _curveTexture.height - 20 - (_movement.maxSpeedPoint.y / maxSpeed) * (_curveTexture.height - 40)); DrawCircle(maxSpeedTexPos, 3, Color.green); _curveTexture.Apply(); } // 辅助方法:绘制直线 private void DrawLine(Vector2 start, Vector2 end, Color color) { float dx = end.x - start.x; float dy = end.y - start.y; float length = Mathf.Sqrt(dx * dx + dy * dy); float step = 1f / length; for (float t = 0; t <= 1f; t += step) { int x = Mathf.RoundToInt(start.x + dx * t); int y = Mathf.RoundToInt(start.y + dy * t); if (x >= 0 && x < _curveTexture.width && y >= 0 && y < _curveTexture.height) { _curveTexture.SetPixel(x, y, color); } } } // 辅助方法:绘制圆点 private void DrawCircle(Vector2 center, float radius, Color color) { for (float angle = 0; angle < 360; angle += 5) { float rad = angle * Mathf.Deg2Rad; int x = Mathf.RoundToInt(center.x + radius * Mathf.Cos(rad)); int y = Mathf.RoundToInt(center.y + radius * Mathf.Sin(rad)); if (x >= 0 && x < _curveTexture.width && y >= 0 && y < _curveTexture.height) { _curveTexture.SetPixel(x, y, color); } } } }
使用说明
- 将
IceMovement脚本挂载到需要控制的游戏对象上。 - 在Inspector面板中,修改
maxSpeedPoint和controlPoint的数值时,下方的曲线预览会实时更新:- 绿色点代表最大速度到达点(时间-速度)
- 红色点代表第三控制点,用于调整曲线的弯曲程度
- 蓝色曲线就是实时计算的速度-时间变化曲线
额外优化建议
- 可以给参数添加
[Tooltip]属性,方便理解每个参数的作用 - 增加坐标轴刻度标注,让曲线预览更直观
- 限制参数的最小值(比如用
[Min(0.1f)]属性),避免出现除零异常
内容的提问来源于stack exchange,提问作者ambu360
相关产品推荐
相关产品推荐

