Сохранение параметров struct и проблемы с вычислениями

Программирование на Юнити.

Сохранение параметров struct и проблемы с вычислениями

Сообщение dima13230 04 янв 2017, 22:48

Есть структура с названием MyBounds, являющаяся модификацией стандартной структуры Bounds ( я её сделал для учёта "вращения" границ )
Синтаксис:
Используется csharp
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine.Scripting;
using UnityEngine;

[System.Serializable]
public struct MyBounds
{
    private Vector3 m_Center;
    private Vector3 m_Extents;
    private Quaternion m_Rotation;
    public MyBounds(Vector3 center, Quaternion rotation, Vector3 size)
    {
        this.m_Center = center;
        this.m_Extents = (Vector3)(size * 0.5f);
        this.m_Rotation = rotation;
    }

    public override int GetHashCode()
    {
        return (this.center.GetHashCode() ^ (this.extents.GetHashCode() << 2));
    }

    public override bool Equals(object other)
    {
        if (!(other is MyBounds))
        {
            return false;
        }
        MyBounds MyBounds = (MyBounds)other;
        return (this.center.Equals(MyBounds.center) && this.extents.Equals(MyBounds.extents) && this.rotation.Equals(MyBounds.rotation));
    }

    public Vector3 center
    {
        get
        {
            return this.m_Center;
        }
        set
        {
            this.m_Center = value;
        }
    }
    public Quaternion rotation
    {
        get
        {
            return this.m_Rotation;
        }
        set
        {
            this.m_Rotation = value;
        }
    }
    public Vector3 size
    {
        get
        {
            return ((Vector3)(this.m_Extents * 2f));
        }
        set
        {
            this.m_Extents = (Vector3)(value * 0.5f);
        }
    }
    public Vector3 extents
    {
        get
        {
            return this.m_Extents;
        }
        set
        {
            this.m_Extents = value;
        }
    }
    public Vector3 min
    {
        get
        {
            return (this.center - this.extents);
        }
        set
        {
            this.SetMinMax(value, this.max);
        }
    }
    public Vector3 max
    {
        get
        {
            return (this.center + this.extents);
        }
        set
        {
            this.SetMinMax(this.min, value);
        }
    }
    public void SetMinMax(Vector3 min, Vector3 max)
    {
        this.extents = (Vector3)((max - min) * 0.5f);
        this.center = min + this.extents;
    }

    public void Encapsulate(Vector3 point)
    {
        this.SetMinMax(Vector3.Min(this.min, point), Vector3.Max(this.max, point));
    }

    public void Encapsulate(MyBounds MyBounds)
    {
        this.Encapsulate(MyBounds.center - MyBounds.extents);
        this.Encapsulate(MyBounds.center + MyBounds.extents);
    }

    public void Expand(float amount)
    {
        amount *= 0.5f;
        this.extents += new Vector3(amount, amount, amount);
    }

    public void Expand(Vector3 amount)
    {
        this.extents += (Vector3)(amount * 0.5f);
    }

    public bool Intersects(MyBounds MyBounds)
    {
        Vector3 EulerRot = rotation.eulerAngles;
        Vector3 EulerRot2 = MyBounds.rotation.eulerAngles;
        return (((((this.min.x+EulerRot.x <= MyBounds.max.x+EulerRot2.x) && (this.max.x+EulerRot.x >= MyBounds.min.x+EulerRot2.x)) && ((this.min.y+EulerRot.y <= MyBounds.max.y+EulerRot2.y) && (this.max.y+EulerRot.y >= MyBounds.min.y+EulerRot2.y))) && (this.min.z+EulerRot.z <= MyBounds.max.z+EulerRot2.z)) && (this.max.z+EulerRot.z >= MyBounds.min.z+EulerRot2.z));
    }

    private static bool Internal_Contains(MyBounds m, Vector3 point)
    {
        return INTERNAL_CALL_Internal_Contains(ref m, ref point);
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern bool INTERNAL_CALL_Internal_Contains(ref MyBounds m, ref Vector3 point);
    public bool Contains(Vector3 point)
    {
        return Internal_Contains(this, point);
    }

    private static float Internal_SqrDistance(MyBounds m, Vector3 point)
    {
        return INTERNAL_CALL_Internal_SqrDistance(ref m, ref point);
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern float INTERNAL_CALL_Internal_SqrDistance(ref MyBounds m, ref Vector3 point);
    public float SqrDistance(Vector3 point)
    {
        return Internal_SqrDistance(this, point);
    }

    private static bool Internal_IntersectRay(ref Ray ray, ref MyBounds MyBounds, out float distance)
    {
        return INTERNAL_CALL_Internal_IntersectRay(ref ray, ref MyBounds, out distance);
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern bool INTERNAL_CALL_Internal_IntersectRay(ref Ray ray, ref MyBounds MyBounds, out float distance);
    public bool IntersectRay(Ray ray)
    {
        float num;
        return Internal_IntersectRay(ref ray, ref this, out num);
    }

    public bool IntersectRay(Ray ray, out float distance)
    {
        return Internal_IntersectRay(ref ray, ref this, out distance);
    }

    private static Vector3 Internal_GetClosestPoint(ref MyBounds MyBounds, ref Vector3 point)
    {
        Vector3 vector;
        INTERNAL_CALL_Internal_GetClosestPoint(ref MyBounds, ref point, out vector);
        return vector;
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern void INTERNAL_CALL_Internal_GetClosestPoint(ref MyBounds MyBounds, ref Vector3 point, out Vector3 value);
    public Vector3 ClosestPoint(Vector3 point)
    {
        return Internal_GetClosestPoint(ref this, ref point);
    }

    public override string ToString()
    {
        object[] args = new object[] { this.m_Center, this.m_Extents };
        return String.Format("Center: {0}, Extents: {1}", args);
    }

    public string ToString(string format)
    {
        object[] args = new object[] { this.m_Center.ToString(format), this.m_Extents.ToString(format) };
        return String.Format("Center: {0}, Extents: {1}", args);
    }

    public static bool operator ==(MyBounds lhs, MyBounds rhs)
    {
        return ((lhs.center == rhs.center) && (lhs.extents == rhs.extents));
    }

    public static bool operator !=(MyBounds lhs, MyBounds rhs)
    {
        return !(lhs == rhs);
    }
}

И два класса - BlockStats и BlockStatsEditor.
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class BlockStats : MonoBehaviour {
        public int strengthBlock;
    public float PlaceEnergyCost;
        Collider Collider;

    [SerializeField]
    public MyBounds BlockBounds;

    public bool AllowToPlace;
    public bool Placed;
    public Material BeforePlaceMaterial;
    public Material AfterPlaceMaterial;
    public bool CustomConstantRotation;

        void Start()
        {
                Collider = GetComponent<Collider>();
        if (BeforePlaceMaterial)
        GetComponent<MeshRenderer>().material = BeforePlaceMaterial;
        }

    bool updateAfterPlaced;
    void Update()
    {
        if (!CustomConstantRotation)
        {
            BlockBounds.rotation = transform.rotation;
        }
        if (!Placed)
        {
            bool intersects = false;
            Collider[] hits = Physics.OverlapBox(transform.position, BlockBounds.extents * 0.9f);
            for (int i = 0; i < hits.Length; i++)
            {
                if (hits[i].transform.GetComponent<BlockStats>())
                    if (BlockBounds.Intersects(hits[i].transform.GetComponent<BlockStats>().BlockBounds) && hits[i].transform != transform)
                        intersects = true;
            }
            if (intersects)
            {
                AllowToPlace = false;
            }
            else
            {
                AllowToPlace = true;
            }
            if (!AllowToPlace)
            {
                GetComponent<MeshRenderer>().material.color = new Color(1, 0, 0, 0.3f);
            }
            else
            {
                GetComponent<MeshRenderer>().material.color = new Color(0, 1, 0, 0.3f);
            }
        }
        if (Placed)
        {
            if (!updateAfterPlaced)
            {
                GetComponent<MeshRenderer>().material = AfterPlaceMaterial;
                GetComponent<Collider>().isTrigger = false;
                gameObject.AddComponent<Rigidbody>();
                updateAfterPlaced = true;
            }
        }
    }

    void OnTriggerStay(Collider col)
    {
        if (!Placed)
        {
            AllowToPlace = false;
        }
    }

    void OnTriggerExit(Collider col)
    {
        if (!Placed)
        {
            AllowToPlace = true;
        }
    }

}

Синтаксис:
Используется csharp
#if UNITY_EDITOR
using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(BlockStats))]
public class BlockStatsEditor : Editor {

        // Use this for initialization
        void Start () {
       
        }
       
        // Update is called once per frame
        void Update () {
       
        }

    public override void OnInspectorGUI()
    {
        BlockStats blockStats = (BlockStats)target;
        EditorGUILayout.BeginVertical(new GUIStyle("box"));
        EditorGUILayout.LabelField("Block Bounds");
        blockStats.BlockBounds.center = EditorGUILayout.Vector3Field("Center", blockStats.BlockBounds.center);
        blockStats.BlockBounds.extents = EditorGUILayout.Vector3Field("Extents (half-size of real scale)", blockStats.BlockBounds.extents);
        blockStats.CustomConstantRotation = EditorGUILayout.Toggle("Uses custom constant rotation",blockStats.CustomConstantRotation);
        if (blockStats.CustomConstantRotation)
        {
            blockStats.BlockBounds.rotation = Quaternion.Euler(EditorGUILayout.Vector3Field("Rotation (in Euler angles)", blockStats.BlockBounds.rotation.eulerAngles));
        }
        EditorGUILayout.EndVertical();
        blockStats.BeforePlaceMaterial = (Material)EditorGUILayout.ObjectField("Before place material",blockStats.BeforePlaceMaterial, typeof(Material));
        blockStats.AfterPlaceMaterial = (Material)EditorGUILayout.ObjectField("After place material",blockStats.AfterPlaceMaterial, typeof(Material));
        blockStats.PlaceEnergyCost = EditorGUILayout.FloatField("Place energy cost", blockStats.PlaceEnergyCost);
    }
}
#endif

При заходе в игру параметры struct не сохраняются, способы "System.Serializable" и "SerializeField" не помогают. Что делать?

И каким образом вычислить размер границ с учётом их поворота? ( то есть, повёрнутые границы )
Синтаксис:
Используется csharp
Vector3 bObjectPos;
    RaycastHit hit;
    BlockStats bls;

    private void BuildUpdate()
    {
        if (buildModeActive)
        {
            if (SelectedBuildObject.GetComponent<BlockStats>())
            {
                if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, 20) && hit.transform.tag == "Buildable" | hit.transform.GetComponentInParent<TerrainVolume>())
                {
                    if (!buildObject)
                    {
                        BlockStats bls = SelectedBuildObject.GetComponent<BlockStats>();
                        Vector3 EulerBlockRot = bls.BlockBounds.rotation.eulerAngles;
                        if (!BuildCenterMode || hit.transform.GetComponentInParent<TerrainVolume>())
                        {
                            InstantStepCell();
                        }
                        else
                        {
                            bObjectPos = hit.collider.transform.position;

                            if (hit.normal.x > 0) { bObjectPos.x = hit.collider.transform.position.x + hit.collider.bounds.extents.x + bls.BlockBounds.extents.x; }
                            else if (hit.normal.x < 0) { bObjectPos.x = hit.collider.transform.position.x - hit.collider.bounds.extents.x - bls.BlockBounds.extents.x; }
                            else if (hit.normal.y > 0) { bObjectPos.y = hit.collider.transform.position.y + hit.collider.bounds.extents.y + bls.BlockBounds.extents.y; }
                            else if (hit.normal.y < 0) { bObjectPos.y = hit.collider.transform.position.y - hit.collider.bounds.extents.y - bls.BlockBounds.extents.y; }
                            else if (hit.normal.z > 0) { bObjectPos.z = hit.collider.transform.position.z + hit.collider.bounds.extents.z + bls.BlockBounds.extents.z; }
                            else if (hit.normal.z < 0) { bObjectPos.z = hit.collider.transform.position.z - hit.collider.bounds.extents.z - bls.BlockBounds.extents.z; }
                        }
                        buildObject = (GameObject)Instantiate(SelectedBuildObject, bObjectPos, new Quaternion());
                        buildObject.transform.rotation = hit.transform.rotation;
                        buildObject.layer = 2;
                    }
                    else
                    {
                        bObjectPos = hit.point;
                        bls = SelectedBuildObject.GetComponent<BlockStats>();
                        Vector3 EulerBlockRot = SelectedBuildObject.transform.rotation.eulerAngles;
                        if (!BuildCenterMode || hit.transform.GetComponentInParent<TerrainVolume>())
                        {
                            InstantStepCell();
                        }
                        else
                        {
                            bObjectPos = hit.collider.transform.position;

                            if (hit.normal.x > 0) { bObjectPos.x = hit.collider.transform.position.x + hit.collider.bounds.extents.x + bls.BlockBounds.extents.x; }
                            else if (hit.normal.x < 0) { bObjectPos.x = hit.collider.transform.position.x - hit.collider.bounds.extents.x - bls.BlockBounds.extents.x; }
                            else if (hit.normal.y > 0) { bObjectPos.y = hit.collider.transform.position.y + hit.collider.bounds.extents.y + bls.BlockBounds.extents.y; }
                            else if (hit.normal.y < 0) { bObjectPos.y = hit.collider.transform.position.y - hit.collider.bounds.extents.y - bls.BlockBounds.extents.y; }
                            else if (hit.normal.z > 0) { bObjectPos.z = hit.collider.transform.position.z + hit.collider.bounds.extents.z + bls.BlockBounds.extents.z; }
                            else if (hit.normal.z < 0) { bObjectPos.z = hit.collider.transform.position.z - hit.collider.bounds.extents.z - bls.BlockBounds.extents.z; }
                        }
                        buildObject.transform.position = bObjectPos;
                        buildObject.transform.rotation = hit.transform.rotation;
                    }
                    if (Input.GetMouseButtonDown(0))
                    {
                        if (buildObject.GetComponent<BlockStats>().AllowToPlace)
                        {
                            buildObject.GetComponent<BlockStats>().Placed = true;
                            if (hit.transform.GetComponentInParent<Grid>())
                            {
                                buildObject.transform.parent = hit.transform.GetComponentInParent<Grid>().transform;
                                hit.transform.GetComponentInParent<Grid>().BuildPrefabs.Add(buildObject.GetComponent<BlockStats>());
                            }
                            else
                            {
                                GameObject GridObject = new GameObject("New Grid");
                                GridObject.AddComponent<Grid>().GridName = "New Grid";
                                GridObject.GetComponent<Grid>().BuildPrefabs.Add(buildObject.GetComponent<BlockStats>());
                                buildObject.transform.parent = GridObject.transform;
                            }
                            buildObject.layer = 0;
                            buildObject = null;
                        }
                    }
                }
                else
                {
                    if (buildObject) { Destroy(buildObject); buildObject = null; }
                }
            }
            else
            {
                if (buildObject)
                {
                    Destroy(buildObject); buildObject = null;
                }
            }
        }
        else
        {
            if (buildObject)
            {
                Destroy(buildObject);
                buildObject = null;
            }
        }
    }

    void InstantStepCell()
    {
        if (bls != null)
        {
            if (!hit.transform.GetComponentInParent<TerrainVolume>())
            {
                if (hit.transform.GetComponent<BlockStats>())
                {
                    bObjectPos = hit.point;
                    //если устанавливаем на верхнюю сторону, то прибавляем размеры установленного и устанавливаемого объекта
                    if (hit.normal.y > 0)
                    {
                        bObjectPos.y = hit.collider.transform.position.y + hit.transform.GetComponent<BlockStats>().BlockBounds.extents.y + bls.BlockBounds.extents.y;
                        bObjectPos.x = StepCell(bObjectPos.x);
                        bObjectPos.z = StepCell(bObjectPos.z);
                    }   //если на нижнюю то отнимаем размеры установленного и устанавливаемого объекта по Y
                    else if (hit.normal.y < 0)
                    {
                        bObjectPos.y = hit.collider.transform.position.y - hit.transform.GetComponent<BlockStats>().BlockBounds.extents.y - bls.BlockBounds.extents.y;
                        bObjectPos.x = StepCell(bObjectPos.x);
                        bObjectPos.z = StepCell(bObjectPos.z);
                    }
                    else if (hit.normal.x > 0)
                    {
                        bObjectPos.x = hit.collider.transform.position.x + hit.transform.GetComponent<BlockStats>().BlockBounds.extents.x + bls.BlockBounds.extents.x;
                        bObjectPos.y = StepCell(bObjectPos.y);
                        bObjectPos.z = StepCell(bObjectPos.z);
                    }
                    else if (hit.normal.x < 0)
                    {
                        bObjectPos.x = hit.collider.transform.position.x - hit.transform.GetComponent<BlockStats>().BlockBounds.extents.x - bls.BlockBounds.extents.x;
                        bObjectPos.y = StepCell(bObjectPos.y);
                        bObjectPos.z = StepCell(bObjectPos.z);
                    }
                    else if (hit.normal.z > 0)
                    {
                        bObjectPos.z = hit.collider.transform.position.z + hit.transform.GetComponent<BlockStats>().BlockBounds.extents.z + bls.BlockBounds.extents.z;
                        bObjectPos.y = StepCell(bObjectPos.y);
                        bObjectPos.x = StepCell(bObjectPos.x);
                    }
                    else if (hit.normal.z < 0)
                    {
                        bObjectPos.z = hit.collider.transform.position.z - hit.transform.GetComponent<BlockStats>().BlockBounds.extents.z - bls.BlockBounds.extents.z;
                        bObjectPos.y = StepCell(bObjectPos.y);
                        bObjectPos.x = StepCell(bObjectPos.x);
                    }
                }
            }
            else
            {
                bObjectPos = hit.point;
                //если устанавливаем на верхнюю сторону, то прибавляем размеры установленного и устанавливаемого объекта
                if (hit.normal.y > 0)
                {
                    Debug.Log(bls != null);
                    Debug.Log(bls.BlockBounds != null);
                    bObjectPos.y = hit.point.y + bls.BlockBounds.extents.y;
                    bObjectPos.x = StepCell(bObjectPos.x);
                    bObjectPos.z = StepCell(bObjectPos.z);
                }   //если на нижнюю то отнимаем размеры установленного и устанавливаемого объекта по Y
                else if (hit.normal.y < 0)
                {
                    bObjectPos.y = hit.point.y - bls.BlockBounds.extents.y;
                    bObjectPos.x = StepCell(bObjectPos.x);
                    bObjectPos.z = StepCell(bObjectPos.z);
                }
                else if (hit.normal.x > 0)
                {
                    bObjectPos.x = hit.point.x + bls.BlockBounds.extents.x;
                    bObjectPos.y = StepCell(bObjectPos.y);
                    bObjectPos.z = StepCell(bObjectPos.z);
                }
                else if (hit.normal.x < 0)
                {
                    bObjectPos.x = hit.point.x - bls.BlockBounds.extents.x;
                    bObjectPos.y = StepCell(bObjectPos.y);
                    bObjectPos.z = StepCell(bObjectPos.z);
                }
                else if (hit.normal.z > 0)
                {
                    bObjectPos.z = hit.point.z + bls.BlockBounds.extents.z;
                    bObjectPos.y = StepCell(bObjectPos.y);
                    bObjectPos.x = StepCell(bObjectPos.x);
                }
                else if (hit.normal.z < 0)
                {
                    bObjectPos.z = hit.point.z - bls.BlockBounds.extents.z;
                    bObjectPos.y = StepCell(bObjectPos.y);
                    bObjectPos.x = StepCell(bObjectPos.x);
                }
            }
        }
    }

    float StepCell(float coord)
    {
        coord = (Mathf.Round(coord / 0.125f)) * 0.125f;
        return coord;
    }

Вычислить размер границ с их поворотом я пытался с помощью сложения векторов extents и rotation.eulerAngles ( как, собственно, видно из кода ), но это не даёт нужных мне результатов.
P.S под границами я имею ввиду структуру Bounds, а конкретнее, мою структуру MyBounds.
P.P.S и не судите строго за говнокод, в дальнейшем я всё это исправлю :)
dima13230
UNец
 
Сообщения: 16
Зарегистрирован: 09 янв 2015, 01:39

Re: Сохранение параметров struct и проблемы с вычислениями

Сообщение Cr0c 05 янв 2017, 12:19

Синтаксис:
Используется csharp
Vector3 extentNew = rotation * (m_Extents - m_Center) + m_Center ;
 

Как-то так считается extents при повороте.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 2240
Зарегистрирован: 19 июн 2015, 13:50

Re: Сохранение параметров struct и проблемы с вычислениями

Сообщение jetyb 12 янв 2017, 08:15

1. Сделать сохраняемые поля структуры public.
2. Что значит "размер границ с поворотом"?
jetyb
Адепт
 
Сообщения: 1198
Зарегистрирован: 31 окт 2011, 17:21


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 4