news 2026/7/4 7:57:14

中餐厅摆台 点击UI图片拖拽预制体到桌面并 实现预制体拖拽

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
中餐厅摆台 点击UI图片拖拽预制体到桌面并 实现预制体拖拽

1、准备桌面 和 酒杯

先在Scene窗口中调好相对位置,然后将酒杯拖拽到project目录中生成预制体。

需要给预制体增加一个脚本就是 using UnityEngine;
public class ItemHeight : MonoBehaviour
{
// 在预制体Inspector手动填好:这个物品放在桌面需要的世界Y
public float tableY = 0.869f;
}

填好酒杯的位置,因为拖拽到桌面的时候,position中的x,z都可以用鼠标的,但是高度必须用自身的。不然容易穿模,或者飞起。

在写代码前,需要给桌面一个box collisder 不然射线检测不到。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ItemDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
// 酒杯预制体
public GameObject wineGlassPrefab;
// 拖拽时跟随鼠标的临时物体
private GameObject dragTempObj;
// UI原图初始位置(固定不动)
private Vector2 uiOriginPos;

void Awake()
{
uiOriginPos = transform.position;
}

// 开始拖拽
public void OnBeginDrag(PointerEventData eventData)
{
// UI图标固定不动,恢复原始位置
transform.position = uiOriginPos;

// 生成临时3D酒杯跟随鼠标
dragTempObj = Instantiate(wineGlassPrefab);
// 临时物体关闭碰撞,避免射线干扰
Collider col = dragTempObj.GetComponent<Collider>();
if (col != null) col.enabled = false;
}

// 拖拽过程,临时酒杯跟随鼠标
public void OnDrag(PointerEventData eventData)
{
// UI始终固定原位
transform.position = uiOriginPos;

if (dragTempObj != null)
{
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
// 地面空白处也更新位置,高度抬高一点防止穿模
if (Physics.Raycast(ray, out hit, 1000))
{
dragTempObj.transform.position = hit.point + Vector3.up * 0.02f;
}
else
{
// 没碰到物体,鼠标远处显示
dragTempObj.transform.position = ray.GetPoint(5);
}
}
}

// 松开鼠标,放置正式物体
public void OnEndDrag(PointerEventData eventData)
{
// 销毁跟随鼠标的临时酒杯
if (dragTempObj != null)
{
Destroy(dragTempObj);
dragTempObj = null;
}

// 射线检测桌面,生成正式酒杯
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// 判定是桌子
if (!hit.collider.CompareTag("Table")) return;

GameObject newGlass = Instantiate(wineGlassPrefab);
// 读取预制体内部提前存好的Y值
ItemHeight heightData = newGlass.GetComponent<ItemHeight>();
float targetY = heightData.tableY;

// XZ用鼠标点击,Y直接用预制体内存好的固定数值
Vector3 placePos = new Vector3(hit.point.x, targetY, hit.point.z);
newGlass.transform.position = placePos;
newGlass.transform.SetParent(hit.transform);
}
}
}

给这个image加一个itemDrag的脚本,并把酒杯预制体拖拽进去。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ItemDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
// 酒杯预制体
public GameObject wineGlassPrefab;
// 拖拽时跟随鼠标的临时物体
private GameObject dragTempObj;
// UI原图初始位置(固定不动)
private Vector2 uiOriginPos;

void Awake()
{
uiOriginPos = transform.position;
}

// 开始拖拽
public void OnBeginDrag(PointerEventData eventData)
{
// UI图标固定不动,恢复原始位置
transform.position = uiOriginPos;

// 生成临时3D酒杯跟随鼠标
dragTempObj = Instantiate(wineGlassPrefab);
// 临时物体关闭碰撞,避免射线干扰
Collider col = dragTempObj.GetComponent<Collider>();
if (col != null) col.enabled = false;
}

// 拖拽过程,临时酒杯跟随鼠标
public void OnDrag(PointerEventData eventData)
{
// UI始终固定原位
transform.position = uiOriginPos;

if (dragTempObj != null)
{
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
// 地面空白处也更新位置,高度抬高一点防止穿模
if (Physics.Raycast(ray, out hit, 1000))
{
dragTempObj.transform.position = hit.point + Vector3.up * 0.02f;
}
else
{
// 没碰到物体,鼠标远处显示
dragTempObj.transform.position = ray.GetPoint(5);
}
}
}

// 松开鼠标,放置正式物体
public void OnEndDrag(PointerEventData eventData)
{
// 销毁跟随鼠标的临时酒杯
if (dragTempObj != null)
{
Destroy(dragTempObj);
dragTempObj = null;
}

// 射线检测桌面,生成正式酒杯
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// 判定是桌子
if (!hit.collider.CompareTag("Table")) return;

GameObject newGlass = Instantiate(wineGlassPrefab);
// 读取预制体内部提前存好的Y值
ItemHeight heightData = newGlass.GetComponent<ItemHeight>();
float targetY = heightData.tableY;

// XZ用鼠标点击,Y直接用预制体内存好的固定数值
Vector3 placePos = new Vector3(hit.point.x, targetY, hit.point.z);
newGlass.transform.position = placePos;
newGlass.transform.SetParent(hit.transform);
}
}
}

这样就实现了拖拽,如果还想拖拽已经生成的物体,需要给预制体加上下面这个脚本,并给预制体加上box collisder, 给主相机 加上 physics RayCaster

和eventSystem。

using UnityEngine;
using UnityEngine.EventSystems;

// 拖拽场景中已经生成好的桌面3D物品
public class TableObjectDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
// 鼠标点击点 和 物体坐标的偏移量,防止拖拽时物体瞬移
private Vector3 dragOffset;
// 桌子基准高度
private float tableStandardY;

// 开始拖拽:鼠标按下杯子瞬间执行
public void OnBeginDrag(PointerEventData eventData)
{
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// 记录桌子高度,全程锁定Y不变化
tableStandardY = hit.transform.position.y;
// 计算偏移,保证鼠标点杯子任意位置都能平稳拖动
dragOffset = transform.position - hit.point;
}
}

// 拖拽持续中:鼠标移动实时更新杯子位置
public void OnDrag(PointerEventData eventData)
{
Ray ray = Camera.main.ScreenPointToRay(eventData.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
// X、Z跟随鼠标,Y固定桌面高度,不会嵌入桌子、不会飘高
Vector3 newPos = new Vector3(
hit.point.x + dragOffset.x,
tableStandardY,
hit.point.z + dragOffset.z
);
transform.position = newPos;
}
}

// 拖拽结束:松开鼠标
public void OnEndDrag(PointerEventData eventData)
{
// 可选拓展:拖到桌面外自动吸附回桌面,这里留空你按需加逻辑
}
}

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 1:46:44

go ethereum之p2p

简介 p2p是以太坊节点网络层的骨架&#xff0c;夹在底层 TCP/UDP 和应用协议&#xff08;eth、snap、les&#xff09;之间&#xff0c;管三件事&#xff1a;节点发现&#xff08;谁在线&#xff09;、连接管理&#xff08;怎么连上、怎么断&#xff09;、消息多路复用&#xff…

作者头像 李华
网站建设 2026/7/1 1:45:50

第二次小学期作业

Xshell 和 Xftp 使用教程 Xshell 是一款SSH客户端&#xff0c;用于远程连接并管理Linux服务器。使用步骤&#xff1a; 安装与启动&#xff1a;下载安装Xshell并启动。新建会话&#xff1a;点击“文件” -> “新建”。填写连接信息&#xff1a;在“连接”中&#xff0c;协议选…

作者头像 李华
网站建设 2026/7/1 1:45:42

书法资源合集

萝卜练字 小学生硬笔书法课 文件大小: 44.3GB内容特色: 44.3GB高清视频逐字示范&#xff0c;小学生硬笔书法全流程训练适用人群: 小学生、家长、书法启蒙教师核心价值: 掌握正确握笔与笔画结构&#xff0c;快速提升书写工整度下载链接: https://pan.quark.cn/s/77888772fddb …

作者头像 李华
网站建设 2026/7/1 1:44:53

为什么不该用 Double 表示金额及解决方案合集 - Java(45)

比如 0.1 0.2 并不等于 0.3,而是等于 0.30000000000000004——这也一度成为程序员圈子里的经典梗。所以用浮点数表示金额这种需要精确计算的数值,是会出现精度丢失问题的。double a 0.1; double b 0.2; System.out.println(a b); // 输出: 0.30000000000000004 System.out…

作者头像 李华
网站建设 2026/7/1 1:44:42

面向切面编程和面向对象编程的区别,两者有冲突吗?

面向切面编程&#xff08;AOP&#xff09;和面向对象编程&#xff08;OOP&#xff09;是两种不同的编程范式&#xff0c;它们各自解决不同类型的问题&#xff0c;并且通常可以互补使用而不是冲突。OOP 关注的是对象和它们的交互&#xff0c;强调的是数据和行为的封装。 AOP关注…

作者头像 李华
网站建设 2026/7/1 1:44:18

乳牙蛀了不用管?避开护牙误区,科学守护孩子恒牙健康

乳牙蛀了不用管&#xff1f;避开护牙误区&#xff0c;科学守护孩子恒牙健康“孩子才几岁&#xff0c;乳牙迟早要换&#xff0c;蛀了也不用在意。” 这是儿童口腔科普中最常遇到的认知误区。很多家长觉得乳牙是 “临时牙齿”&#xff0c;不需要费心护理&#xff0c;却忽略了乳牙…

作者头像 李华