unity点击button后不松开通过拖拽显示模型松开后模型实例化

news2025/4/4 21:16:11
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(Button))] // 确保脚本挂在Button上
public class DragButtonSpawner : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
    [Header("拖拽设置")]
    [Tooltip("模型预制体路径前缀")]
    public string modelPathPrefix = "ModePrefab/"; // 模型资源路径前缀

    [Tooltip("允许放置的层级")]
    public LayerMask allowedLayers = ~0; // 默认所有层级

    [Tooltip("放置偏移量")]
    public Vector3 placementOffset = Vector3.zero; // 模型放置时的位置偏移

    private GameObject currentDraggingModel; // 当前正在拖拽的模型
    private bool isDragging = false;        // 是否正在拖拽
    private string modelName;               // 模型名称缓存

    void Awake()
    {
        // 缓存按钮名称作为模型名称
        // 移除可能的"(Clone)"后缀
      
    }

    // 按钮按下时 - 开始拖拽
    public void OnPointerDown(PointerEventData eventData)
    {
        // 异步加载模型避免卡顿
        StartCoroutine(LoadAndInitModel());
    }

    // 异步加载模型
    private IEnumerator LoadAndInitModel()
    {
        modelName = this.name.Replace("(Clone)", "").Trim();
        Debug.Log(modelName);
        ResourceRequest request = Resources.LoadAsync<GameObject>(modelPathPrefix + modelName);
        yield return request;

        Debug.Log(request.asset.name);
        if (request.asset == null)
        {
            Debug.LogError($"加载模型失败: {modelPathPrefix}{modelName}");
            yield break;
        }

        // 实例化模型但不显示
        currentDraggingModel = Instantiate(request.asset) as GameObject;
       // currentDraggingModel.name = modelName + "_Instance";
        currentDraggingModel.name = modelName;
        currentDraggingModel.SetActive(false);
        isDragging = true;
    }

    // 拖拽过程中 - 更新模型位置
    public void OnDrag(PointerEventData eventData)
    {
        if (!isDragging || currentDraggingModel == null) return;

        Ray ray = Camera.main.ScreenPointToRay(eventData.position);
        RaycastHit hit;

        // 只在指定层级上检测碰撞
        if (Physics.Raycast(ray, out hit, Mathf.Infinity, allowedLayers))
        {
            // 显示模型并更新位置(添加偏移量)
            currentDraggingModel.SetActive(true);
            currentDraggingModel.transform.position = hit.point + placementOffset;
            GameObject terrain = GameObject.Find("Terrain");
            currentDraggingModel.transform.parent = terrain.transform;
            // 使模型朝向法线方向(可选)
            currentDraggingModel.transform.rotation = Quaternion.FromToRotation(Vector3.zero, hit.normal);
        }
        else
        {
            currentDraggingModel.SetActive(false);
        }
    }

    // 按钮释放时 - 完成放置或取消
    public void OnPointerUp(PointerEventData eventData)
    {
        if (!isDragging || currentDraggingModel == null) return;

        if (currentDraggingModel.activeSelf)
        {
            FinalizePlacement();
        }
        else
        {
            CancelPlacement();
        }

        ResetDragState();
    }

    // 最终确认放置
    private void FinalizePlacement()
    {
        // 添加放置音效(可选)
        // AudioManager.PlayPlacementSound();

        // 移除临时组件或添加持久化组件
        //var tempCollider = currentDraggingModel.GetComponent<TemporaryCollider>();
        //if (tempCollider != null) Destroy(tempCollider);

        //Debug.Log($"模型 {modelName} 已放置在场景中");
    }

    // 取消放置
    private void CancelPlacement()
    {
        Destroy(currentDraggingModel);
        Debug.Log("拖拽已取消");
    }

    // 重置拖拽状态
    private void ResetDragState()
    {
        currentDraggingModel = null;
        isDragging = false;
    }

    // 当脚本禁用时确保清理
    void OnDisable()
    {
        if (isDragging && currentDraggingModel != null)
        {
            CancelPlacement();
            ResetDragState();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《AI大模型应知应会100篇》第2篇:大模型核心术语解析:参数、Token、推理与训练

第2篇&#xff1a;大模型核心术语解析&#xff1a;参数、Token、推理与训练 摘要 本文将用通俗易懂的语言拆解大模型领域的四大核心概念&#xff1a;参数、Token、训练与推理。通过案例对比、代码实战和成本计算&#xff0c;帮助读者快速掌握这些术语的底层逻辑与实际应用价值…

【28BYJ-48】STM32同时驱动4个步进电机,支持调速与正反转

资料下载&#xff1a;待更新。。。。 先驱动起来再说&#xff0c;干中学&#xff01;&#xff01;&#xff01; 1、实现功能 STM32同时驱动4个步进电机&#xff0c;支持单独调速与正反转控制 需要资源&#xff1a;16个任意IO口1ms定时器中断 目录 资料下载&#xff1a;待更…

Gradle-基础

一.安装 1. 2.配置环境变量 GRADLE_HOME D:\gradle\gradle-5.6.4 GRADLE_USER_HOME D:\gradle\localRepository 3.下载源配置 安装目录下的init.d文件夹里创建一个init.gradle文件&#xff0c;下载顺序从上到下&#xff0c;内容&#xff1…

Anolis系统下安装Jenkins

1.安装java、maven yum install -y java-17-openjdk-devel maven git wget 2.配置环境变量 1.查看java和maven所在目录 [rootlocalhost ~]# which java /usr/bin/java [rootlocalhost bin]# ll /usr/bin/java lrwxrwxrwx 1 root root 22 4月 1 17:20 /usr/bin/java ->…

LabVIEW 调用 Python 函数

此程序是 LabVIEW 调用 Python 函数实现双精度数相加的典型示例。通过 LabVIEW 搭建交互框架&#xff0c;借助 “Open Python Session” 创建 Python 代码运行环境&#xff0c;定位 Python 模块路径后调用 “Add” 函数&#xff0c;最终实现数据处理并关闭会话。整个流程展现了…

视频分析设备平台EasyCVR视频结构化AI智能分析:筑牢校园阳光考场远程监控网

一、背景分析​ 近年来&#xff0c;学校考试的舞弊现象屡禁不止&#xff0c;严重破坏考试的公平性&#xff0c;不仅损害广大考生的切身利益&#xff0c;也在社会上造成恶劣的影响。为有效制止舞弊行为&#xff0c;收集确凿的舞弊证据&#xff0c;在考场部署一套可靠的视频监控…

AWS用Glue读取S3文件上传数据到Redshift,再导出到Quicksight完整版,含VPC配置

1. 项目背景 AWS的官方文档&#xff0c;关于Glue和Vpc配置部分已经比较旧了&#xff0c;按照官方文档配置的流程始终跑不通&#xff0c;花了一番时间和波折后&#xff0c;才终于完整的跑通了。 在数据分析和商业智能&#xff08;BI&#xff09;领域&#xff0c;我们常需要将存…

Python爬虫第3节-会话、Cookies及代理的基本原理

目录 一、会话和Cookies 1.1 静态网页和动态网页 1.2 无状态HTTP 1.3 常见误区 二、代理的基本原理 2.1 基本原理 2.2 代理的作用 2.3 爬虫代理 2.4 代理分类 2.5 常见代理设置 一、会话和Cookies 大家在浏览网站过程中&#xff0c;肯定经常遇到需要登录的场景。有些…

OkHttpHttpClient

学习链接 okhttp github okhttp官方使用文档 SpringBoot 整合okHttp okhttp3用法 Java中常用的HTTP客户端库&#xff1a;OkHttp和HttpClient&#xff08;包含请求示例代码&#xff09; 深入浅出 OkHttp 源码解析及应用实践 httpcomponents-client github apache httpclie…

c++柔性数组、友元、类模版

目录 1、柔性数组&#xff1a; 2、友元函数&#xff1a; 3、静态成员 注意事项 面试题&#xff1a;c/c static的作用? C语言&#xff1a; C: 为什么可以创建出 objx 4、对象与对象之间的关系 5、类模版 1、柔性数组&#xff1a; #define _CRT_SECURE_NO_WARNINGS #…

Centos 8 安装教程(新手版)

1.需要在阿里开源镜像站下载对应的镜像&#xff0c;如下&#xff1a;https://mirrors.aliyun.com/centos/8.5.2111/isos/x86_64/ 2.打开VM虚拟机&#xff0c;创建新的虚拟机&#xff0c;选择自定义 如图所示点击进行&#xff1a; 选择下载好的镜像 选择“Linux”&#xff0c;版…

Vue2函数式组件实战:手写可调用的动态组件,适用于toast轻提示、tip提示、dialog弹窗等

Vue2函数式组件实战&#xff1a;手写可调用的动态组件 一、需求场景分析 在开发中常遇到需要动态调用的组件场景&#xff1a; 全局弹窗提示即时消息通知动态表单验证需要脱离当前DOM树的悬浮组件 传统组件调用方式的痛点&#xff1a;必须预先写入模板&#xff0c;可能还要用…

大象如何学会太空漫步?美的:科技领先、To B和全球化

中国企业正处在转型的十字路口。一边是全新的技术、全新的市场机遇&#xff1b;一边是转型要面临的沉重负累和巨大投入&#xff0c;无数中国制造、中国品牌仍在寻路&#xff0c;而有的人已经走至半途。 近日&#xff0c;美的集团交出了一份十分亮眼的2024年财报。数据显示&…

已经使用中的clickhouse更改数据目录

在更换的目录操作&#xff0c;这里更换的目录为home目录&#xff0c;原先安装的目录在/soft/clickhouse/ ,在该目录下有data目录和log目录 更改前目录 更改后目录 1、停止clickhouse服务 sudo systemctl stop clickhouse-server 2、在home目录创建clickhouse目录,在clickho…

PHP的相关配置和优化

进入etc下面 去掉注释 pid run/php-fpm.pid #指定pid文件存放位置 生成一下子配置文件 这些都是生成的fastcgi的配置文件 进入php中&#xff0c;然后复制模版&#xff0c;生成配置文件 然后编辑文件更改时区 改完之后可以生成启动脚本 这时候刷新之后&#xff0c;再启动会报…

【leetcode100】每日温度

1、题目描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 示例 1: 输…

<贪心算法>

前言&#xff1a;在主包还没有接触算法的时候&#xff0c;就常听人提起“贪心”&#xff0c;当时是layman&#xff0c;根本不知道说的是什么&#xff0c;以为很难呢&#xff0c;但去了解一下&#xff0c;发现也不过如此嘛&#xff08;bushi)&#xff0c;还以为是什么高级东西呢…

基于银河麒麟桌面服务器操作系统的 DeepSeek本地化部署方法【详细自用版】

一、3种方式使用DeepSeek 1.本地部署 服务器操作系统环境进行,具体流程如下(桌面环境步骤相同): 本例所使用银河麒麟高级服务器操作系统版本信息: (1)安装ollama 方式一:按照ollama官网的下载指南,执行如下命令: curl -fsSL https://ollama.com/install.sh | sh方…

「2025最新版React+Ant Design+Router+TailwindCss全栈攻略:从零到实战,打造高颜值企业级应用

一站式掌握最新技术栈&#xff01;手把手教你配置路由、集成UI组件库、高效开发秘籍大公开 ReactAntrouteraxiosmocktailwind css等组合安装使用教程 官网&#xff1a;React Native 中文网 使用React来编写原生应用的框架 一&#xff0c;安装 npx create-react-app my-app …

Ubuntu 24.04.2 LTS 系统安装python,创建虚拟环境

在 Ubuntu 24.04.2 LTS 系统中&#xff0c;系统本身自带了 Python 3&#xff0c;不过你还是可以按照下面的步骤来安装和配置 Python 环境。 1. 检查系统自带的 Python 版本 在终端中输入以下命令查看系统自带的 Python 版本&#xff1a; python3 --version如果显示了 Python…