[Unity]建造放置系统BuildSystem
发布日期:2021-05-09 11:54:50 浏览次数:2 分类:技术文章

本文共 9708 字,大约阅读时间需要 32 分钟。

Build System

下载完毕,导入。

下面这个脚本,直接挂载到一个空物体,新建一个 3D物体 立方体,将其设置为 BuildGameObject变量的值(如下图所示)。新建一个 按钮button,来触发placeBool函数即可 实现放置基本的物体。

using UnityEngine;using BuildSystem;public class BuildManage : MonoBehaviour {    public Material ghostMaterial;//放置物体 时候的 材质    private Material goMaterial;    //**********************************************************************************************    [Header("Input Settings")]    [Tooltip("Key to press to enable the builder mode. This is also used by ObjectSelector")]    public KeyCode toggleKey = KeyCode.E;    [Tooltip("Key to press to place a item in the scene")]    public KeyCode placeKey = KeyCode.Mouse0;    [Tooltip("Key to press rotate (forward) the object based on snapRotaionDeg")]    public KeyCode positiveRotateKey = KeyCode.Mouse1;    [Tooltip("Key to press rotate (backward) the object based on snapRotaionDeg")]    public KeyCode negativeRotateKey = KeyCode.None;    [Header("More Settings")]    [Tooltip("Disable the remover script when placer is active. Note: remover must be next to this script")]    public bool shouldToggleRemover = true;    [Tooltip("Max distance from camera where you can place objects")]    public float maxPlaceDistance = 100f;    /****************************************************    * Editor Interface    * *************************************************/    [Tooltip("Camera used to raycast and find place position, if empty the script will try to use the main camera")]    public Camera cam;    public LayerMask movementMask;//设置 LayerMask     public GameObject buildGameObject;//建设的物体    /****************************************************    * Variables    * *************************************************/    bool isActive = true;    bool canPlace = false;    bool mouseIsNotOnUI = true;    //object rotation    float objectSnapCurrentRotaion = 0;    //object pivot    bool usingFakePivot = false;    /****************************************************    * Events    * *************************************************/    public delegate void BuildEvent();    public event BuildEvent OnGhostObjectCreation;    public event BuildEvent OnGhostObjectDestroy;    public event BuildEvent OnGhostObjectPlace;    /****************************************************        * Components & references        * *************************************************/    Transform ghostObjInstance;    Transform myTransform;        // Use this for initialization    void Start () {        if (cam == null)            cam = CameraManager.instance.nowCamera;        myTransform = transform;    }    void Update()    {        //点击鼠标左键        if (Input.GetMouseButtonDown(0) && canPlace == true)        {            PlaceGhostObject();        }    }    private void FixedUpdate()    {        //update ghost object position        if (canPlace && ghostObjInstance != null)        {            MoveGhostObject();        }    }    //由按钮触发    public void placeBool()    {        canPlace = true;        CreateGhostObject();    }        /****************************************************         * Ghost Object Creation & Movement & Place         * *************************************************/        ///         /// Create ghost object        ///         void CreateGhostObject()        {            DestroyGhostObject();           /*if (objectToPlace == null)            {                Debug.LogError("No item to instantiate! Aborting ghost creation.");                return;            }*/                  ghostObjInstance = Instantiate(buildGameObject, myTransform.position, Quaternion.identity).GetComponent
();            goMaterial =ghostObjInstance.transform.GetComponent
().material;            ghostObjInstance.transform.GetComponent
().material = ghostMaterial;            ghostObjInstance.transform.gameObject.layer = 0;//设置 新建物体 时候,的预览 幻影 物体 的层级。使其 不BUG        //reset old object rotation        //if (resetRotationAfterPlace)        //    objectSnapCurrentRotaion = 0;        //check where is the pivot, if it is not in the base create a fake one        usingFakePivot = false;                        Vector3 pivotOffsetExtra;            bool objPivotIsBase = isPivotInBase(ghostObjInstance, out pivotOffsetExtra);            //create a fake pivot if the real one is not in base            if (!objPivotIsBase)            {                ghostObjInstance = CreateBasePivot(ghostObjInstance, pivotOffsetExtra);                usingFakePivot = true;            }            if (OnGhostObjectCreation != null)            {                OnGhostObjectCreation();            }        }        ///
        /// Move the ghost object        ///         void MoveGhostObject()        {            Ray ray = cam.ScreenPointToRay(Input.mousePosition);            RaycastHit hit;            //射线只碰撞到 有碰撞体的物体 ,距离为 100 ,并且 LayerMask层级为 Floor的物体            if (Physics.Raycast(ray, out hit, maxPlaceDistance, movementMask))            {                //set object position to hit point                Vector3 pos = hit.point;                ghostObjInstance.transform.position = pos;             AlignGhostToSurface(ghostObjInstance, hit.normal);          }        }            ///
        /// Place the object in the scene        ///         void PlaceGhostObject()        {            if (ghostObjInstance != null)            {                Debug.Log("Created: " + ghostObjInstance.name);                 if (usingFakePivot) // remove fake pivot if using one                 {                     ghostObjInstance = ghostObjInstance.GetComponent
().DeletePivot();                 }                         //ghostObjInstance.transform.GetComponent
().material = goMaterial;            //place real object in scene             GameObject go = Instantiate(buildGameObject, ghostObjInstance.position, ghostObjInstance.rotation);                go.layer = 8;//设置 物体的层级                //Debug.Log("ghostObjInstance.transform.childCount:"+ ghostObjInstance.transform.childCount);                Destroy(ghostObjInstance.gameObject);                if (OnGhostObjectPlace != null)                {                    OnGhostObjectPlace();                }                //CreateGhostObject(); //create a new ghost object            }            else Debug.LogError("Unable to spawn object, ghost reference is null!");            canPlace = false;        }            ///
        /// Remove ghost object from scene        ///         void DestroyGhostObject()        {            if (ghostObjInstance != null)            {                Destroy(ghostObjInstance.gameObject);                /*if (OnGhostObjectDestroy != null)                {                    OnGhostObjectDestroy();                }*/            }        }        /****************************************************    * Pivot helpers 中心点    * *************************************************/    ///
    /// Create a pivot parent to better place the object    ///     ///
Item to use    ///
Renderer of the item    ///
Offset of the pivot    ///
    Transform CreateBasePivot(Transform item, Vector3 pivotOffset)    {        var normMesh = item.GetComponentInChildren
();        var skinMesh = item.GetComponentInChildren
();        if (normMesh == null && skinMesh == null)        {            Debug.LogError("No renderers found!");            return null;        }        GameObject pivotG = new GameObject("Temp_Ghost_Pivot_Parent"); // create parent        Transform pivotT = pivotG.transform;        pivotG.AddComponent
(); // add helper class to remove the pivot when object is spawned        //get mesh center        Vector3 meshCenter = (normMesh != null) ? normMesh.bounds.extents : skinMesh.bounds.extents;        // apply pivot delta        meshCenter.x = pivotOffset.x;        meshCenter.z = pivotOffset.z;        meshCenter.y += pivotOffset.y;        item.SetParent(pivotT); // set the current object as parent        item.localPosition = meshCenter; // move the object and leave the parent object in the pivot position        return pivotT;    }    ///
    /// Check if the object pivot is in center or not.    /// This function returns the pivot Offset (can be Vector3.zero)    ///     ///
Item to use    ///
Renderer attached to the item    ///
Offset of the pivot to be in base    ///
    bool isPivotInBase(Transform item, out Vector3 pivotOffset)    {        var normMesh = item.GetComponentInChildren
();        var skinMesh = item.GetComponentInChildren
();        if (normMesh == null && skinMesh == null)        {            Debug.LogError("No mesh renderer found!");            pivotOffset = Vector3.zero;            return false;        }        var pivotMargin = (normMesh != null) ? normMesh.bounds.extents.y * 2 / 3 : skinMesh.bounds.extents.y * 2 / 3; //set the base pivot margin.                                                                                                                       //Its' height must be lower than obj center * 2/3        Vector3 delta = item.position - ((normMesh != null) ? normMesh.bounds.center : skinMesh.bounds.center);        if (delta.magnitude >= pivotMargin && delta.y < 0) //delta.y < 0 fix issues that not centerd pivots above the object center were taken as base pivots        {            pivotOffset = Vector3.zero;            return true;        }        else        {            pivotOffset = delta; // save pivot delta to use to create a fake pivot            return false;        }    }    /****************************************************        * Ghost Object Alignament         * *************************************************/    ///
    /// Align ghost object to surface based on raycast hit normal    /// 使得 地板 layer 层级 的物体 ,创建的 时候 可以 避免相互之间 重叠    ///
Item to align    ///
Normal to use to align object    void AlignGhostToSurface(Transform itemToAlign, Vector3 hitNormal)    {        if (itemToAlign == null) return;        itemToAlign.rotation = Quaternion.FromToRotation(Vector3.up, hitNormal) * Quaternion.Euler(new Vector3(0, objectSnapCurrentRotaion, 0));    }}

问题:

1.出现 放置物体 重叠 BUG 解决办法

参考资料:

1.

2.

Unity 使用自定义资源(.asset)配置数据

3.

转载地址:https://blog.csdn.net/BuladeMian/article/details/79293408 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:[Unity][UGUI]UGUI-Extensions学习--下载安装包
下一篇:[Unity][UGUI][协程]圆环进度条读条协程延迟倒计时

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2023年09月01日 09时51分25秒