我看到网上好像有挺多做这个的,我就稍微加个功能,物体只能摆放在对应的层级上面,直接上图:
左边是小车子,只能放到左边的Terrain层级上面,右边是类似公交车的车型,只能放到Plane层级上面。
层级设置:
整个功能的实现只需要一个脚本,我直接上代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SelectScript : MonoBehaviour
{
private GameObject _Obj = null;
private GameObject _slectedObj;
private string perfabePath = "Models/FBX/"; //我的perfab资源路径
private string objName;
private int count;
private float _YOffset;
public int rotateAngle = 3;
private Dictionary<string, string> tagLayer;
GameObject fatherNode;
//下面这几个变量是移动物体的时候需要用到的,在这里声明是为了不会每帧都声明,节省性能
Vector3 Gpoint;
Vector3 screenPosition;
Ray ray;
RaycastHit hitInfo;
public void Selected()
{
CreatePrefab();
}
void Start()
{
tagLayer = new Dictionary<string, string>(); //物体的tag对应到放置的Layer层
tagLayer.Add("TerrainObj", "Terrain");
tagLayer.Add("PlaneObj", "Plane");
}
void Update()
{
if(_Obj != null)
{
MoveCurrentObj();
}
}
/// <summary>
/// 从UI界面创建对象
/// </summary>
void CreatePrefab()
{
_slectedObj = UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject;
objName = _slectedObj.GetComponent<Image>().sprite.name;
_Obj = Instantiate(Resources.Load(perfabePath + objName, typeof(GameObject))) as GameObject;
_Obj.name = count + objName;
_YOffset = _Obj.GetComponent<MeshFilter>().sharedMesh.bounds.size.y / 2f; //根据物体的mesh边界确定偏移
switch (tagLayer[_Obj.tag])
{
case "Terrain":
fatherNode = GameObject.Find("TerrainNode");
break;
case "Plane":
fatherNode = GameObject.Find("PlaneNode");
break;
default:
break;
}
_Obj.transform.parent = fatherNode.transform;
count++;
}
/// <summary>
///让当前对象跟随鼠标移动
/// </summary>
void MoveCurrentObj()
{
screenPosition = Input.mousePosition; //得到鼠标在屏幕的位置
ray = Camera.main.ScreenPointToRay(screenPosition); //从鼠标位置发出射线
if (_Obj)
{
if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, LayerMask.GetMask(tagLayer[_Obj.tag])))
{
Gpoint = hitInfo.point;
_Obj.transform.position = Gpoint + new Vector3(0, _YOffset + 0.1f, 0); //在Y轴有个偏移,不会贴着layer表面,也可以不要这个偏移
if (Input.GetKeyDown(KeyCode.Escape)) //在移动物体还没放下之前可以按键盘ESC键删除
{
Destroy(_Obj);
_Obj = null;
Debug.Log("撤销!");
}
if (Input.mouseScrollDelta.y != 0) //滑动滚轮旋转物体
{
if (Input.mouseScrollDelta.y > 0)
{
_Obj.transform.Rotate(0, rotateAngle, 0);
}
else
{
_Obj.transform.Rotate(0, -rotateAngle, 0);
}
}
if (Input.GetMouseButtonDown(0)) //点击放置物体
{
_Obj = null;
}
}
}
}
}
细心的朋友会发现,我给每个物体都起了一个名字,就是count+预制体的名字,然后再去场景中找一个对应的空物体当成父物体,这样是为了以后对功能做扩展,有个名字,就相当于该物体在场景中有了唯一的标识,后面会很方便。还有一个需要注