当前位置: 首页 > news >正文

中餐厅摆台 点击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)
{
// 可选拓展:拖到桌面外自动吸附回桌面,这里留空你按需加逻辑
}
}

http://www.jsqmd.com/news/1099493/

相关文章:

  • 家庭精细化洗护怎么选?海信全家筒·棉花糖 U7S 四筒洗衣机深度体验
  • MHmarkets:把产品理解成本做扎实,更谨慎的使用者更容易感受到的清单
  • 基于STM32单片机甲醛温湿度烟雾火灾报警 空气质量检测PM2系统2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 全国大学真实生活环境一键查询工具(在线免费)
  • Spring MVC的工作流程
  • go ethereum之p2p
  • 59.可跨平台投产!标准 ST 语言 PLC 电机状态机控制完整源码
  • Keepalived简介与工作原理Keepalived是一个基于VRRP协议(虚拟路由冗余协议) 实现的高可用解
  • 买卖股票的最佳时机
  • 23 万 Star 的秘密知识库,运维和安全人员的工具箱
  • 3个步骤让Windows 11重获新生:Win11Debloat系统优化完全指南
  • 一文搞懂巴别鸟版本管理:从历史回溯到冲突解决的完整攻略
  • 基于STM32单片机老人防丢智能拐杖 盲人导航定位跌倒检测设计系统3(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 别只会堆功能!后端业务代码重构实战,告别祖传烂代码
  • App Store Connect CLI 1.5.4 官方版下载(夸克网盘+百度网盘,SHA256校验)
  • Mi-Create:小米穿戴设备表盘设计的完整技术指南与架构解析
  • 做虚拟资料,哪些内容绝对不能碰?一份版权风险排查清单
  • 大模型核心技术与企业级应用实战指南-附录
  • HTML和CSS基本知识
  • 内蒙古教培机构 AI 招生体系 GEO + 招生官网 + 知识短视频全案测评
  • 企业级数字人直播解决方案:多账号矩阵 + 全域同步推流
  • 如何用LinkSwift彻底告别网盘下载烦恼:九大平台一站式解决方案指南
  • 【云原生与DevOps】05-GitOps工作流:ArgoCD+GitHub Actions完整方案
  • 批量图片翻译视频字幕智能抠图一站式解决跨境电商难题
  • MoE模型参数量与激活机制的技术辨析
  • 免费开源:用pk3DS打造你的专属宝可梦3DS游戏世界
  • 双向链表,反转链表
  • 2026年家电原生智能品牌实用推荐
  • 61.吃透 PLC 状态机编程!带超时停机 + 料仓满报警 + 传感器防抖完整实战
  • PHP本地开发环境一键部署与API集成实践指南