【问题标题】:Call a function in a CustomEditor script from another script从另一个脚本调用 CustomEditor 脚本中的函数
【发布时间】:2017-11-09 10:01:02
【问题描述】:

我想使用 GetComponent。此脚本附加到任何游戏对象:

namespace CBX.Unity.Editors.Editor
{
    using System;
    using CBX.TileMapping.Unity;
    using UnityEditor;
    using UnityEngine;

    /// <summary>
    /// Provides a editor for the <see cref="TileMap"/> component
    /// </summary>
    [CustomEditor(typeof(TileMap))]
    public class TileMapEditor : Editor
    {
        /// <summary>
        /// Holds the location of the mouse hit location
        /// </summary>
        private Vector3 mouseHitPos;

        /// <summary>
        /// Lets the Editor handle an event in the scene view.
        /// </summary>
        /// 

        private void OnSceneGUI()
        {
            // if UpdateHitPosition return true we should update the scene views so that the marker will update in real time
            if (this.UpdateHitPosition())
            {
                SceneView.RepaintAll();
            }

            // Calculate the location of the marker based on the location of the mouse
            this.RecalculateMarkerPosition();

            // get a reference to the current event
            Event current = Event.current;

            // if the mouse is positioned over the layer allow drawing actions to occur
            if (this.IsMouseOnLayer())
            {
                // if mouse down or mouse drag event occurred
                if (current.type == EventType.MouseDown || current.type == EventType.MouseDrag)
                {
                    if (current.button == 1)
                    {
                        // if right mouse button is pressed then we erase blocks
                        this.Erase();
                        current.Use();
                    }
                    else if (current.button == 0)
                    {
                        // if left mouse button is pressed then we draw blocks
                        this.Draw();
                        current.Use();
                    }
                }
            }

            // draw a UI tip in scene view informing user how to draw & erase tiles
            Handles.BeginGUI();
            GUI.Label(new Rect(10, Screen.height - 90, 100, 100), "LMB: Draw");
            GUI.Label(new Rect(10, Screen.height - 105, 100, 100), "RMB: Erase");
            Handles.EndGUI();
        }

        /// <summary>
        /// When the <see cref="GameObject"/> is selected set the current tool to the view tool.
        /// </summary>
        private void OnEnable()
        {
            Tools.current = Tool.View;
            Tools.viewTool = ViewTool.FPS;
        }

        /// <summary>
        /// Draws a block at the pre-calculated mouse hit position
        /// </summary>
        private void Draw()
        {
            // get reference to the TileMap component
            var map = (TileMap)this.target;

            // Calculate the position of the mouse over the tile layer
            var tilePos = this.GetTilePositionFromMouseLocation();

            // Given the tile position check to see if a tile has already been created at that location
            var cube = GameObject.Find(string.Format("Tile_{0}_{1}", tilePos.x, tilePos.y));

            // if there is already a tile present and it is not a child of the game object we can just exit.
            if (cube != null && cube.transform.parent != map.transform)
            {
                return;
            }

            // if no game object was found we will create a cube
            if (cube == null)
            {
                cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            }

            // set the cubes position on the tile map
            var tilePositionInLocalSpace = new Vector3((tilePos.x * map.TileWidth) + (map.TileWidth / 2), (tilePos.y * map.TileHeight) + (map.TileHeight / 2));
            cube.transform.position = map.transform.position + tilePositionInLocalSpace;

            // we scale the cube to the tile size defined by the TileMap.TileWidth and TileMap.TileHeight fields 
            cube.transform.localScale = new Vector3(map.TileWidth, map.TileHeight, 1);

            // set the cubes parent to the game object for organizational purposes
            cube.transform.parent = map.transform;

            // give the cube a name that represents it's location within the tile map
            cube.name = string.Format("Tile_{0}_{1}", tilePos.x, tilePos.y);

            // give the cube a tag
            cube.tag = "GridObject";

            TerrainObjects(cube);
        }

        public GameObject TerrainObjects(GameObject gameobject)
        {
            return gameobject;
        }

        /// <summary>
        /// Erases a block at the pre-calculated mouse hit position
        /// </summary>
        private void Erase()
        {
            // get reference to the TileMap component
            var map = (TileMap)this.target;

            // Calculate the position of the mouse over the tile layer
            var tilePos = this.GetTilePositionFromMouseLocation();

            // Given the tile position check to see if a tile has already been created at that location
            var cube = GameObject.Find(string.Format("Tile_{0}_{1}", tilePos.x, tilePos.y));
            var terrainObject = GameObject.Find(string.Format("Terrain_{0}_{1}", Terrain.activeTerrain.transform.position.x + tilePos.x, Terrain.activeTerrain.transform.position.z + tilePos.y));

            // if a game object was found with the same name and it is a child we just destroy it immediately
            if (cube != null && cube.transform.parent == map.transform)
            {
                UnityEngine.Object.DestroyImmediate(cube);
            }

            if (terrainObject != null && terrainObject.transform.parent == map.transform)
            {
                DestroyImmediate(terrainObject);
            }
        }

        /// <summary>
        /// Calculates the location in tile coordinates (Column/Row) of the mouse position
        /// </summary>
        /// <returns>Returns a <see cref="Vector2"/> type representing the Column and Row where the mouse of positioned over.</returns>
        private Vector2 GetTilePositionFromMouseLocation()
        {
            // get reference to the tile map component
            var map = (TileMap)this.target;

            // calculate column and row location from mouse hit location
            var pos = new Vector3(this.mouseHitPos.x / map.TileWidth, this.mouseHitPos.y / map.TileHeight, map.transform.position.z);

            // round the numbers to the nearest whole number using 5 decimal place precision
            pos = new Vector3((int)Math.Round(pos.x, 5, MidpointRounding.ToEven), (int)Math.Round(pos.y, 5, MidpointRounding.ToEven), 0);

            // do a check to ensure that the row and column are with the bounds of the tile map
            var col = (int)pos.x;
            var row = (int)pos.y;
            if (row < 0)
            {
                row = 0;
            }

            if (row > map.Rows - 1)
            {
                row = map.Rows - 1;
            }

            if (col < 0)
            {
                col = 0;
            }

            if (col > map.Columns - 1)
            {
                col = map.Columns - 1;
            }

            // return the column and row values
            return new Vector2(col, row);
        }

        /// <summary>
        /// Returns true or false depending if the mouse is positioned over the tile map.
        /// </summary>
        /// <returns>Will return true if the mouse is positioned over the tile map.</returns>
        private bool IsMouseOnLayer()
        {
            // get reference to the tile map component
            var map = (TileMap)this.target;

            // return true or false depending if the mouse is positioned over the map
            return this.mouseHitPos.x > 0 && this.mouseHitPos.x < (map.Columns * map.TileWidth) &&
                   this.mouseHitPos.y > 0 && this.mouseHitPos.y < (map.Rows * map.TileHeight);
        }

        /// <summary>
        /// Recalculates the position of the marker based on the location of the mouse pointer.
        /// </summary>
        private void RecalculateMarkerPosition()
        {
            // get reference to the tile map component
            var map = (TileMap)this.target;

            // store the tile location (Column/Row) based on the current location of the mouse pointer
            var tilepos = this.GetTilePositionFromMouseLocation();

            // store the tile position in world space
            var pos = new Vector3(tilepos.x * map.TileWidth, tilepos.y * map.TileHeight, 0);

            // set the TileMap.MarkerPosition value
            map.MarkerPosition = map.transform.position + new Vector3(pos.x + (map.TileWidth / 2), pos.y + (map.TileHeight / 2), 0);
        }

        /// <summary>
        /// Calculates the position of the mouse over the tile map in local space coordinates.
        /// </summary>
        /// <returns>Returns true if the mouse is over the tile map.</returns>
        private bool UpdateHitPosition()
        {
            // get reference to the tile map component
            var map = (TileMap)this.target;

            // build a plane object that 
            var p = new Plane(map.transform.TransformDirection(Vector3.forward), map.transform.position);

            // build a ray type from the current mouse position
            var ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

            // stores the hit location
            var hit = new Vector3();

            // stores the distance to the hit location
            float dist;

            // cast a ray to determine what location it intersects with the plane
            if (p.Raycast(ray, out dist))
            {
                // the ray hits the plane so we calculate the hit location in world space
                hit = ray.origin + (ray.direction.normalized * dist);
            }

            // convert the hit location from world space to local space
            var value = map.transform.InverseTransformPoint(hit);

            // if the value is different then the current mouse hit location set the 
            // new mouse hit location and return true indicating a successful hit test
            if (value != this.mouseHitPos)
            {
                this.mouseHitPos = value;
                return true;
            }

            // return false if the hit test failed
            return false;
        }
    }
}

在这个脚本中我还添加了一个公共方法

public GameObject TerrainObjects(GameObject gameobject)
{
    return gameobject;
}

我想从另一个脚本中访问这个方法 TerrainObjects:

此脚本附加到游戏对象:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TerrainObjects : MonoBehaviour {

    // Use this for initialization
    void Start ()
    {
      GetComponent<tile>
    }

    // Update is called once per frame
    void Update ()
    {

    }
}

我正在尝试键入 tile 或 TileMap 或 TileMapEditor 但它不存在。 所以我不能制作这个脚本的Getcomponent。

在开始时我尝试输入:

GetComponent<tile>

但我无法访问 TileMapEditor。

有什么方法可以访问它吗? 如果它是编辑器类型的脚本,我应该附加到与 TerrainObjects 脚本相同的游戏对象吗?

我不希望 TileMapEditor 在游戏中只能在场景中工作。

【问题讨论】:

  • 我不希望 TileMapEditor 附加到游戏对象,因为它是一个编辑器组件。此外,您需要在使用 GetComponent 的地方显示您的代码,但它不起作用
  • 但是那个方法没有任何作用......
  • @RufusL 你说得对,我用 TileMapEditor 完整代码更新了这个问题。我在 TileMapEditor 的 Draw 中使用 TerrainObjects 方法。我想要做的是每次在 TileMapEditor 中创建立方体时实时将游戏对象发送到 TerrainObjects 脚本,以便我可以使用这个游戏对象。
  • 我想在 TerrainObjects 脚本中从 TerrainObjects 方法中返回的游戏对象中获取一些信息,例如位置、比例、旋转、标签、名称...。然后使用 TerrainObjects 中的游戏对象信息进行操作脚本。

标签: c# unity3d unity5


【解决方案1】:

我认为这是一个编辑器插件。 GetComponent 应该适用于从 Editor 继承的脚本。您需要使用Resources.FindObjectsOfTypeAll 找到TileMapEditor 然后调用它的函数(TerrainObjects)。

如果TileMap 有一个实例,则使用索引0 调用该函数。如果它们中有很多,则遍历它们并调用它们的函数。

TileMapEditor[] tpEditorInstance = (TileMapEditor[])Resources.FindObjectsOfTypeAll(typeof(TileMapEditor));

//Make sure it is not null
if (tpEditorInstance != null && tpEditorInstance.Length > 0)
{
    tpEditorInstance[0].TerrainObjects(gameObject);
}
else
{
    Debug.Log("TileMapEditor is Null");
}

编辑

TileMapEditor 在 TerrainObjects 脚本中不存在。

不太明白,但请记住您的TileMapEditor 脚本位于另一个名为“CBX.Unity.Editors.Editor”的命名空间中。您还必须在将访问 TileMapEditor 的任何脚本中导入该命名空间。

只需将using CBX.Unity.Editors.Editor; 添加到将访问TileMapEditor 脚本的每个脚本的顶部即可。

【讨论】:

  • TileMapEditor 在 TerrainObjects 脚本中不存在。我不能在那里添加行 TileMapEditor[] tpEditorInstance = (TileMapEditor[])Resources.FindObjectsOfTypeAll(typeof(TileMapEditor));
  • TileMap 是一个附加到游戏对象但不访问 TileMapEditor 的脚本。
  • 请再仔细阅读答案。我的回答中从未提及TerrainObjects 脚本。我只在TileMapEditor 脚本中提到了TerrainObjects 函数。这就是为什么您不应该将函数和类命名为相同的名称,因为这会让您感到困惑。您想从TileMapEditor 脚本中调用TerrainObjects 函数吗?这就是我的回答。
  • 还要检查我的关于命名空间的编辑。
【解决方案2】:

在我的例子中,在 Assets 下创建一个名为 Editor 的文件夹解决了这个问题。我看到这是一个长期不活跃的帖子,并且为编辑器模式创建一个仅脚本的目录应该是一个标准约定,但我仍然将我的解决方案留在这里以防万一有人需要它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 2011-06-01
    • 2022-08-02
    • 2011-12-09
    • 1970-01-01
    相关资源
    最近更新 更多