Unity中实现拖拽UI实现三维物体布置的效果
主要内容[*]前言介绍
[*]Unity中简单界面搭建
[*]代码实现
[*]其他效果设置
前言介绍
主要功能:在Unity中通过点击UI按钮的图片,生成相应的三维物体。该生成物体,跟随鼠标移动。如果在指定位置,抬起鼠标左键,则在该位置生成该物体,否则销毁该物体。
思路:监听鼠标点击的UI元素,如果鼠标左键点击到三维物体对应的UI按钮元素(通过标签识别),则实例化相应的三维物体,同时让三维物体位置实时更新成鼠标转化成的三维位置,即可实现跟随鼠标操作。当鼠标左键抬起时,打开生成的三维物体的碰撞器,并在短暂延时后,销毁该物体。
在可以生成的三维物体的位置,如果实例化的三维物体销毁在生成位置,因为打开了碰撞器,则会触发生成位置的碰撞检测函数,生成进入碰撞区域的三维物体。
Unity中简单界面搭建
将所要点击的按钮标签修改为PlantName。
图示点击的生成按钮标签设置
为生成按钮对应的预制体,添加BoxCollider组件、Rigidbody组件,并如下图设置参数。
图示预制体的组件添加与参数设置
代码实现
ClickUIObject脚本(该脚本在之前文章中也出现过。主要是用于返回点击的UI元素物体。)
将ClickUIObject脚本、PlantSet脚本挂在到同一个物体上。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickUIObject : MonoBehaviour
{
public GameObject ClickObject()//判断鼠标点击的是哪个UI
{
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
if (results.Count > 0)
{
return results.gameObject;
}
else
{
return null;
}
}
}
PlantSet脚本(根据点击的物体UI名称,生成物体,并跟随鼠标移动,松开鼠标,则被销毁)
using UnityEngine;
public class PlantSet : MonoBehaviour
{
private GameObject instance;//实例化的物体
public float distance=6f;//物体距离摄像机距离
void Update()
{
if (Input.GetMouseButtonDown(0))//拖动、放置功能
{
CreateWithCusorObj(&#34;PlantName&#34;, &#34;04_PlantPlanting/&#34;);//创建跟随鼠标移动的物体
}
WithObjOperation();//若生成了物体,其坐标跟随光标移动,松开鼠标左键,开启碰撞器后,销毁该物体
}
/// <summary>
/// 创建跟随鼠标移动的物体
/// </summary>
private void CreateWithCusorObj(string tagName,string path)
{
GameObject clickGameObject = transform.GetComponent<ClickUIObject>().ClickObject();
if (clickGameObject!=null)
{
print(clickGameObject.name);
if (clickGameObject.tag == tagName)//实例化物体并设置父物体,UIButton
{
//string resourceName = clickGameObject.transform.Find(&#34;Text&#34;).GetComponent<Text>().text;//找到点击植物的名称
string resourceName = clickGameObject.name;//找到点击植物的名称
instance = (GameObject)Instantiate(Resources.Load(path + resourceName));
}
}
}
/// <summary>
/// 若生成了物体,其坐标跟随光标移动,松开鼠标左键,开启碰撞器后,销毁该物体
/// </summary>
private void WithObjOperation()
{
if (instance != null)
{
Vector3 mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance); //获取屏幕坐标
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(mousePosition); //屏幕坐标转世界坐标
instance.transform.position = mouseWorldPos;//跟随鼠标
if (Input.GetMouseButtonUp(0))//只有鼠标抬起时,启用碰撞器,防止碰撞到路径上其他选项
{
instance.transform.GetComponent<BoxCollider>().enabled = true;//开启实例化物体子物体Text的碰撞器
Destroy(instance, 0.05F);//延时销毁,发挥碰撞器作用
}
}
}
}
OnColliderPlantTest脚本(根据进入碰撞器物体名称,生成子物体)
将该脚本挂载到生成位置的物体上,即可。
using UnityEngine;
public class OnColliderPlantTest : MonoBehaviour
{
private string resourceName = &#34;&#34;;//示例化的物体名称
private string tempName = &#34;&#34;;//临时物体名称,用于判断是否改变了所要生成的物体
private bool isFirst = true;//是否第一生成物体,第一次直接生成,否则,判断时候需要重新生成不同的物体.
private void OnCollisionStay(Collision collision)
{
if (!isFirst) tempName = resourceName;//不是第一次生成,保存已经生成的植物名称
resourceName = collision.gameObject.name;//更新点击植物的名称
string instanceName = &#34;&#34;;
foreach (var c in resourceName)
{
if (c != &#39;(&#39;)//生成调用物体的名称,要求不带(clone)
{
instanceName += c;
}
else
{
break;
}
}
if (isFirst)//第一次生成,实例化物体,修改isFirst
{
CreatePlant(instanceName);
isFirst = false;
}
else
{
if (tempName != resourceName)
{
Destroy(transform.GetChild(0).gameObject);//销毁已经生成的物体
CreatePlant(instanceName);
}
}
}
private void CreatePlant(string name)//在摆放位置实例化物体
{
print(&#34;实例化:&#34; + name);
GameObject instance = (GameObject)Instantiate(Resources.Load(&#34;04_PlantPlanting/&#34; + name), transform.position, transform.rotation);
instance.transform.SetParent(transform);
}
}
其他效果设置
1、当布置的物体不合适,会有错误提示效果。
图示运行效果
思路:生成三维物体的原理跟上面代码,只是多加了正确与错误的判定。如果摆放正确,将点光源的光调成绿色,错误改为红色。在这里布置的类型有两种,一个是乔木,一个是灌木。下面脚本中,isTree为True时,为应该布置乔木,否则,布置灌木,灌木有两个物体,所以也需要进行判定一下,符合其中的一种,即为布置正确。
代码实现
using UnityEngine;
public class OnColliderPlantPratice : MonoBehaviour
{
public bool isTree;//该位置是否应该放置乔木(Tree)
public Transform mLight;//位置对应的点光源
private string resourceName = &#34;&#34;;//示例化的物体名称
private string tempName = &#34;&#34;;//临时物体名称,用于判断是否改变了所要生成的物体
private bool isFirst = true;//是否第一生成物体,第一次直接生成,否则,判断时候需要重新生成不同的物体
private void OnCollisionStay(Collision collision)
{
if (!isFirst) tempName = resourceName;//不是第一次生成,保存已经生成的植物名称
resourceName = collision.gameObject.name;//更新点击植物的名称
string instanceName = &#34;&#34;;
foreach (var c in resourceName)
{
if (c != &#39;(&#39;)//生成调用物体的名称,要求不带(clone)
{
instanceName += c;
}
else
{
break;
}
}
if (isFirst)//第一次生成,实例化物体,修改isFirst
{
CreatePlant(instanceName);
isFirst = false;
}
else
{
if (tempName != resourceName)
{
Destroy(transform.GetChild(0).gameObject);//销毁已经生成的物体
CreatePlant(instanceName);
}
}
if (!isTree)//如果应该放置灌木
{
if(resourceName== &#34;ShrubButton1(Clone)&#34; || resourceName == &#34;ShrubButton2(Clone)&#34;)
{
print(&#34;放置正确&#34;);
mLight.GetComponent<Light>().color = Color.green;
}
else
{
mLight.GetComponent<Light>().color = Color.red;
print(&#34;放置错误&#34;);
}
}
else
{
if (resourceName == &#34;TreeButton(Clone)&#34;)
{
mLight.GetComponent<Light>().color = Color.green;
print(&#34;放置正确&#34;);
}
else
{
mLight.GetComponent<Light>().color = Color.red;
print(&#34;放置错误&#34;);
}
}
}
private void CreatePlant(string name)//在摆放位置实例化物体
{
print(&#34;实例化:&#34;+name);
GameObject instance = (GameObject)Instantiate(Resources.Load(&#34;04_PlantPlanting/&#34; + name), transform.position, transform.rotation);
instance.transform.SetParent(transform);
}
}
将该脚本挂载到生成位置的物体上,设置该位置生成的物体类型,并指定需要的改变颜色的点光源物体,具体如下图所示。
图示脚本参数的设置
2、只有布置特定物体,才能在指定位置生成物体。布置正确显示绿色,错误显示红色。
图示运行效果
OnColliderArchitectPratice脚本
using System.Collections;
using UnityEngine;
public enum ArchirectType { Pavilion, Sculpture, Non };//该位置是否应该放置亭子(Pavilion)、雕塑(Sculpture)、Non
public class OnColliderArchitectPratice : MonoBehaviour
{
public Transform mLight;//位置对应的点光源
private string resourceName;
public ArchirectType archirectType;
private void OnCollisionStay(Collision collision)
{
resourceName = &#34;&#34;;
string instanceName = &#34;&#34;;
resourceName = collision.gameObject.name;//找到点击植物的名称
print(resourceName);
foreach (var c in resourceName)
{
if (c != &#39;(&#39;)//生成调用物体的名称,要求不带(clone)
{
instanceName += c;
}
else
{
break;
}
}
if (transform.childCount == 0)
{
if (archirectType == ArchirectType.Non)
{
mLight.GetComponent<Light>().color = Color.red;
print(&#34;放置错误&#34;);
StartCoroutine(ResetLight());
}
else if (archirectType == ArchirectType.Pavilion)
{
if (resourceName == &#34;PavilionButton(Clone)&#34;)
{
mLight.GetComponent<Light>().color = Color.green;
CreatePlant(instanceName);
print(&#34;放置正确&#34;);
}
else
{
mLight.GetComponent<Light>().color = Color.red;
print(&#34;放置错误&#34;);
StartCoroutine(ResetLight());
}
}
else if (archirectType == ArchirectType.Sculpture)
{
if (resourceName == &#34;SculptureButton1(Clone)&#34; || resourceName == &#34;SculptureButton2(Clone)&#34;)
{
print(&#34;放置正确&#34;);
mLight.GetComponent<Light>().color = Color.green;
CreatePlant(instanceName);
}
else
{
mLight.GetComponent<Light>().color = Color.red;
print(&#34;放置错误&#34;);
StartCoroutine(ResetLight());
}
}
}
}
private void CreatePlant(string name)//在摆放位置实例化物体
{
GameObject instance = (GameObject)Instantiate(Resources.Load(&#34;05_ArchitectSet/&#34; + name));
instance.transform.position = transform.position;
instance.transform.SetParent(transform);
}
IEnumerator ResetLight()
{
yield return new WaitForSeconds(1.5f);
mLight.GetComponent<Light>().color = new Color(1, 0.3175f, 0, 1);
}
}
将该脚本挂载到生成位置的物体上,设置该位置生成的物体类型,并指定需要的改变颜色的点光源物体,具体如下图所示。
图示脚本参数的设置
页:
[1]