?Why getting NaN in the editor on the right side of the slider value of the GapRange in the mono script?

huangapple go评论62阅读模式
英文:

?Why getting NaN in the editor on the right side of the slider value of the GapRange in the mono script?

问题

这是您要翻译的代码部分:

a bit long but the scripts are connected.

propertyattribute

using UnityEngine;

public class GapRangeAttribute : PropertyAttribute
{
    public float minRange;
    public float maxRange;
    public float sensitivity;

    public GapRangeAttribute(float minRange, float maxRange, float sensitivity)
    {
        this.minRange = minRange;
        this.maxRange = maxRange;
        this.sensitivity = sensitivity;
    }
}

propertydrawer

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
    float minRange;
    float maxRange;
    float sensitivity;

    public GapRangeDrawer(float minRange, float maxRange, float sensitivity)
    {
        this.minRange = minRange;
        this.maxRange = maxRange;
        this.sensitivity = sensitivity;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (property.propertyType == SerializedPropertyType.Float)
        {
            EditorGUI.BeginProperty(position, label, property);
            EditorGUI.Slider(position, property, minRange, maxRange, label);
            property.floatValue = RoundValue(property.floatValue);
            EditorGUI.EndProperty();
        }
        else
        {
            EditorGUI.LabelField(position, label.text, "Use [GapRangeDrawer] with float values only!");
        }
    }

    private float RoundValue(float value)
    {
        return Mathf.Round(value / sensitivity) * sensitivity;
    }
}

the mono script where i'm using the GapRange attribute and the gap variable.

using UnityEditor;
using UnityEngine;

public class CubeSpawner : MonoBehaviour
{
    public GameObject cubePrefab;
    public LayerMask terrainLayer;
    [GapRange(0, 100, 0.1f)]
    public float gap = 0f;
    public float cameraMoveSpeed = 5f;
    public float zoomSpeed = 5f;
    public float rotationSpeed = 10f;

    private Vector3 lastCubePosition;
    private bool isDragging = false;

    private void Update()
    {
        HandleCameraMovement();
        HandleCameraZoom();
        HandleCameraRotation();

        Vector3 mousePosition = Input.mousePosition;

        HandleRuntimeInput(mousePosition);
    }

    private void HandleRuntimeInput(Vector3 mousePosition)
    {
        if (Input.GetMouseButtonDown(0))
        {
            isDragging = true;
            Ray ray = Camera.main.ScreenPointToRay(mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity, terrainLayer))
            {
                lastCubePosition = hitInfo.point;
                GenerateCube(lastCubePosition);
            }
        }
        else if (Input.GetMouseButtonUp(0))
        {
            isDragging = false;
        }
        else if (isDragging && gap > 0f)
        {
            Ray ray = Camera.main.ScreenPointToRay(mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity, terrainLayer))
            {
                if (Vector3.Distance(hitInfo.point, lastCubePosition) >= gap)
                {
                    GenerateCubesBetween(lastCubePosition, hitInfo.point);
                    lastCubePosition = hitInfo.point;
                }
            }
        }
    }

    private void GenerateCube(Vector3 position)
    {
        float terrainHeight = Terrain.activeTerrain.SampleHeight(position);
        Vector3 cubePosition = new Vector3(position.x, terrainHeight, position.z);
        Instantiate(cubePrefab, cubePosition, Quaternion.identity);
    }

    private void GenerateCubesBetween(Vector3 start, Vector3 end)
    {
        float distance = Vector3.Distance(start, end);
        int numCubes = Mathf.RoundToInt(distance / gap);

        Vector3 direction = (end - start).normalized;
        float stepSize = distance / numCubes;

        for (int i = 0; i < numCubes; i++)
        {
            Vector3 position = start + direction * (i * stepSize);
            GenerateCube(position);
        }
    }

    private void HandleCameraMovement()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        Vector3 moveDirection = new Vector3(horizontal, 0f, vertical);
        moveDirection.Normalize();

        transform.Translate(moveDirection * cameraMoveSpeed * Time.deltaTime, Space.World);
    }

    private void HandleCameraZoom()
    {
        float zoom = Input.GetAxis("Mouse ScrollWheel");

        Vector3 zoomDirection = new Vector3(0f, 0f, zoom * zoomSpeed);
        transform.Translate(zoomDirection, Space.Self);
    }

    private void HandleCameraRotation()
    {
        if (Input.GetMouseButton(1))
        {
            float rotationX = Input.GetAxis("Mouse X") * rotationSpeed;
            float rotationY = Input.GetAxis("Mouse Y") * rotationSpeed;

            transform.Rotate(Vector3.up, rotationX, Space.World);
            transform.Rotate(Vector3.right, -rotationY, Space.Self);
        }
    }
}

propertydrawer脚本经过更改如下:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
    public float MinRange { get; set; }
    public float MaxRange { get; set; }
    public float Sensitivity { get; set; }

    public GapRangeDrawer()
    {
        MinRange = 1f;
        MaxRange = 100f;
        Sensitivity = 0.1f;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (property.propertyType == SerializedPropertyType.Float)
        {
            EditorGUI.BeginProperty(position, label, property);
            EditorGUI.Slider(position, property, MinRange, MaxRange, label);
            //property.floatValue = RoundValue(property.floatValue);
            EditorGUI.EndProperty();
        }
        else
        {
            EditorGUI.LabelField(position, label.text, "Use [GapRangeDrawer] with float values only!");
        }
    }

    private float RoundValue(float value)
    {
        return Mathf.Round(value / Sensitivity) * Sensitivity;
    }
}
英文:

a bit long but the scripts are connected.

propertyattribute

using UnityEngine;
public class GapRangeAttribute : PropertyAttribute
{
public float minRange;
public float maxRange;
public float sensitivity;
public GapRangeAttribute(float minRange, float maxRange, float sensitivity)
{
this.minRange = minRange;
this.maxRange = maxRange;
this.sensitivity = sensitivity;
}
}

propertydrawer

using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
float minRange;
float maxRange;
float sensitivity;
public GapRangeDrawer(float minRange, float maxRange, float sensitivity)
{
this.minRange = minRange;
this.maxRange = maxRange;
this.sensitivity = sensitivity;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.Slider(position, property, minRange, maxRange, label);
property.floatValue = RoundValue(property.floatValue);
EditorGUI.EndProperty();
}
else
{
EditorGUI.LabelField(position, label.text, &quot;Use [GapRangeDrawer] with float values only!&quot;);
}
}
private float RoundValue(float value)
{
return Mathf.Round(value / sensitivity) * sensitivity;
}
}

the mono script where i'm using the GapRange attribute and the gap variable.

using UnityEditor;
using UnityEngine;
public class CubeSpawner : MonoBehaviour
{
public GameObject cubePrefab;
public LayerMask terrainLayer;
[GapRange(0, 100, 0.1f)]
public float gap = 0f;
public float cameraMoveSpeed = 5f;
public float zoomSpeed = 5f;
public float rotationSpeed = 10f;
private Vector3 lastCubePosition;
private bool isDragging = false;
private void Update()
{
HandleCameraMovement();
HandleCameraZoom();
HandleCameraRotation();
Vector3 mousePosition = Input.mousePosition;
HandleRuntimeInput(mousePosition);
}
private void HandleRuntimeInput(Vector3 mousePosition)
{
if (Input.GetMouseButtonDown(0))
{
isDragging = true;
Ray ray = Camera.main.ScreenPointToRay(mousePosition);
if (Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity, terrainLayer))
{
lastCubePosition = hitInfo.point;
GenerateCube(lastCubePosition);
}
}
else if (Input.GetMouseButtonUp(0))
{
isDragging = false;
}
else if (isDragging &amp;&amp; gap &gt; 0f)
{
Ray ray = Camera.main.ScreenPointToRay(mousePosition);
if (Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity, terrainLayer))
{
if (Vector3.Distance(hitInfo.point, lastCubePosition) &gt;= gap)
{
GenerateCubesBetween(lastCubePosition, hitInfo.point);
lastCubePosition = hitInfo.point;
}
}
}
}
private void GenerateCube(Vector3 position)
{
float terrainHeight = Terrain.activeTerrain.SampleHeight(position);
Vector3 cubePosition = new Vector3(position.x, terrainHeight, position.z);
Instantiate(cubePrefab, cubePosition, Quaternion.identity);
}
private void GenerateCubesBetween(Vector3 start, Vector3 end)
{
float distance = Vector3.Distance(start, end);
int numCubes = Mathf.RoundToInt(distance / gap);
Vector3 direction = (end - start).normalized;
float stepSize = distance / numCubes;
for (int i = 0; i &lt; numCubes; i++)
{
Vector3 position = start + direction * (i * stepSize);
GenerateCube(position);
}
}
private void HandleCameraMovement()
{
float horizontal = Input.GetAxis(&quot;Horizontal&quot;);
float vertical = Input.GetAxis(&quot;Vertical&quot;);
Vector3 moveDirection = new Vector3(horizontal, 0f, vertical);
moveDirection.Normalize();
transform.Translate(moveDirection * cameraMoveSpeed * Time.deltaTime, Space.World);
}
private void HandleCameraZoom()
{
float zoom = Input.GetAxis(&quot;Mouse ScrollWheel&quot;);
Vector3 zoomDirection = new Vector3(0f, 0f, zoom * zoomSpeed);
transform.Translate(zoomDirection, Space.Self);
}
private void HandleCameraRotation()
{
if (Input.GetMouseButton(1))
{
float rotationX = Input.GetAxis(&quot;Mouse X&quot;) * rotationSpeed;
float rotationY = Input.GetAxis(&quot;Mouse Y&quot;) * rotationSpeed;
transform.Rotate(Vector3.up, rotationX, Space.World);
transform.Rotate(Vector3.right, -rotationY, Space.Self);
}
}
}

what I want to do is to use the gap variable using the GapRange to add gaps between range 0,100 and the third parameter in the attribute the sensitive should set the GapRange slider movement sensitive.

It seems that the problem is in the PropertyDrawer script because the NaN in the inspector showing before running the game.

I also used a break point and saw that the value of floatValue in property.floatValue is NaN so I tried to remove that line but it didn't change much , still showing NaN in the inspector.

the propertydrawer after changes:

using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
public float MinRange { get; set; }
public float MaxRange { get; set; }
public float Sensitivity { get; set; }
public GapRangeDrawer()
{
MinRange = 1f;
MaxRange = 100f;
Sensitivity = 0.1f;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.Slider(position, property, MinRange, MaxRange, label);
//property.floatValue = RoundValue(property.floatValue);
EditorGUI.EndProperty();
}
else
{
EditorGUI.LabelField(position, label.text, &quot;Use [GapRangeDrawer] with float values only!&quot;);
}
}
private float RoundValue(float value)
{
return Mathf.Round(value / Sensitivity) * Sensitivity;
}
}

答案1

得分: 1

我认为主要原因是这个构造函数:

public GapRangeDrawer(float minRange, float maxRange, float sensitivity)
{
    this.minRange = minRange;
    this.maxRange = maxRange;
    this.sensitivity = sensitivity;
}

也可能不是这个构造函数:

public GapRangeDrawer()
{
    MinRange = 1f;
    MaxRange = 100f;
    Sensitivity = 0.1f;
}

可能根本不会被 Inspector 调用,因为它在内部创建属性绘制器实例,可能使用 PropertyDrawer 的一些内部构造函数!

所以在你的 GapRangeDrawer 中的 sensitivity / Sensitivity 将始终保持为 0!(你可以通过调试你的代码来确认这一点)。


还有可能你在检视器中看到的 NaN 只是之前某个失败的测试的结果;)

你现在的做法对我来说确实有效,但这仍然不是你应该做这种事情的方式。


一般来说,这不是你实现自定义属性绘制器的方式,也不是你访问相应属性/属性的字段的方式。参见PropertyDrawers中的示例,特别是属性绘制器的示例。

这有点取决于你想要如何做这个。

如果你想传递参数,你可以这样做:

public class GapRangeAttribute : PropertyAttribute
{
    public const float MinimalSensitivity = 0.1f;

    public float MinRange { get; }
    public float MaxRange { get; }
    public float Sensitivity { get; }

    public GapRangeAttribute(float minRange = 0f, float maxRange = 100f, float sensitivity = MinimalSensitivity)
    {
        MinRange = minRange;
        MaxRange = maxRange;
        Sensitivity = Mathf.Clamp(sensitivity, MinimalSensitivity, Mathf.Abs(maxRange - minRange));
    }
}

然后在你的绘制器中使用如下方式访问它们:

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        label = EditorGUI.BeginProperty(position, label, property);
        position = EditorGUI.PrefixLabel(position, label);

        var range = (GapRangeAttribute)attribute;

        if (property.propertyType == SerializedPropertyType.Float)
        {
            EditorGUI.Slider(position, property, range.MinRange, range.MaxRange);
            property.floatValue = RoundValue(property.floatValue, range.Sensitivity);
        }
        else
        {
            EditorGUI.HelpBox(position, "Use [GapRangeDrawer] with float values only!", MessageType.Error);
        }

        EditorGUI.EndProperty();
    }

    private static float RoundValue(float value, float sensitivity)
    {
        return Mathf.Round(value / sensitivity) * sensitivity;
    }
}

或者如果你确实想使用固定值,你可以直接在绘制器中将它们声明为 const,而不是通过构造函数奇怪地传递它们,然后这样做:

public class GapRangeAttribute : PropertyAttribute { }

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
    const float MinRange = 0f;
    const float MaxRange = 100f;
    const float Sensitivity = 0.1f;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        label = EditorGUI.BeginProperty(position, label, property);
        position = EditorGUI.PrefixLabel(position, label);

        if (property.propertyType == SerializedPropertyType.Float)
        {
            EditorGUI.Slider(position, property, MinRange, MaxRange);
            property.floatValue = RoundValue(property.floatValue);
        }
        else
        {
            EditorGUI.HelpBox(position, "Use [GapRangeDrawer] with float values only!", MessageType.Error);
        }

        EditorGUI.EndProperty();
    }

    private static float RoundValue(float value)
    {
        return Mathf.Round(value / Sensitivity) * Sensitivity;
    }
}
英文:

I think the main reason is that this constructor

public GapRangeDrawer(float minRange, float maxRange, float sensitivity)
{
this.minRange = minRange;
this.maxRange = maxRange;
this.sensitivity = sensitivity;
}

and probably not even this one

public GapRangeDrawer()
{
MinRange = 1f;
MaxRange = 100f;
Sensitivity = 0.1f;
}

might ever be called by the Inspector as it creates the property drawer instances internally and probably uses some internal constructor of PropertyDrawer!

So the sensitivity / Sensitivity within your GapRangeDrawer will always stay 0! (Something you can surely confirm yourself by Debugging your Code).


Also possible that the NaN you have right now in the Inspector is just still a result from some failed test before ?Why getting NaN in the editor on the right side of the slider value of the GapRange in the mono script?

What you have now actually works for me .. it is still not how you would do something like that.


In general this is not how you implement a custom property drawer nor how you access the according property's / attribute's fields. See PropertyDrawers for examples in particular also for attribute drawers.

It depends a bit on how exactly you want to do this.

If you want to pass in the parameters you will want to do e.g.

public class GapRangeAttribute : PropertyAttribute
{
public const float MinimalSensitivity = 0.1f;
public float MinRange { get; }
public float MaxRange { get; }
public float Sensitivity { get; }
public GapRangeAttribute(float minRange = 0f, float maxRange = 100f, float sensitivity = MinimalSensitivity)
{
MinRange = minRange;
MaxRange = maxRange;
Sensitivity = Mathf.Clamp(sensitivity, MinimalSensitivity, Mathf.Abs(maxRange - minRange));
}
}

and then in your drawer accordingly access those using

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
label = EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, label);
var range = (GapRangeAttribute)attribute;
if (property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.Slider(position, property, range.MinRange, range.MaxRange);
property.floatValue = RoundValue(property.floatValue, range.Sensitivity);
}
else
{
EditorGUI.HelpBox(position, &quot;Use [GapRangeDrawer] with float values only!&quot;, MessageType.Error);
}
EditorGUI.EndProperty();
}
private static float RoundValue(float value, float sensitivity)
{
return Mathf.Round(value / sensitivity) * sensitivity;
}
}

OR if you anyway want to go with fixed values you could make them const directly in the drawer itself instead of weirdly passing them in via constructors and do e.g.

public class GapRangeAttribute : PropertyAttribute { }

and

[CustomPropertyDrawer(typeof(GapRangeAttribute))]
public class GapRangeDrawer : PropertyDrawer
{
const float MinRange = 0f;
const float MaxRange = 100f;
const float Sensitivity = 0.1f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
label = EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, label);
if (property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.Slider(position, property, MinRange, MaxRange);
property.floatValue = RoundValue(property.floatValue);
}
else
{
EditorGUI.HelpBox(position, &quot;Use [GapRangeDrawer] with float values only!&quot;, MessageType.Error);
}
EditorGUI.EndProperty();
}
private static float RoundValue(float value)
{
return Mathf.Round(value / Sensitivity) * Sensitivity;
}
}

huangapple
  • 本文由 发表于 2023年6月30日 04:40:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定