You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中保存拖拽物体位置并重启恢复的实现方案咨询

Unity 拖拽物体保存位置并重启恢复的最优方案

一、手动实现(无插件,轻量高效)

这是无依赖、灵活性最高的方案,适合简单场景:

1. 实现拖拽与存储逻辑

给目标物体添加对应Collider(3D用Mesh/Box Collider,2D用Box Collider 2D),挂载以下脚本:

using UnityEngine;
using UnityEngine.EventSystems;

public class DragAndSavePosition : MonoBehaviour, IDragHandler, IPointerDownHandler
{
    private Vector3 _mouseOffset;

    // 记录鼠标按下时的物体-鼠标偏移量
    public void OnPointerDown(PointerEventData eventData)
    {
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(eventData.position);
        // 2D场景修正Z轴,避免位置偏移
        if (worldPos.z != transform.position.z)
        {
            worldPos = new Vector3(eventData.position.x, eventData.position.y, transform.position.z);
        }
        _mouseOffset = transform.position - worldPos;
    }

    // 拖拽时更新物体位置
    public void OnDrag(PointerEventData eventData)
    {
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(eventData.position);
        if (worldPos.z != transform.position.z)
        {
            worldPos = new Vector3(eventData.position.x, eventData.position.y, transform.position.z);
        }
        transform.position = worldPos + _mouseOffset;
    }

    // 场景卸载/应用退出时保存位置
    private void OnDestroy() => SaveCurrentPosition();

    // 手动触发保存(比如拖拽结束时)
    public void SaveCurrentPosition()
    {
        // 用物体唯一ID作为键前缀,避免多物体存储冲突
        string keyPrefix = $"Pos_{gameObject.GetInstanceID()}";
        PlayerPrefs.SetFloat($"{keyPrefix}_X", transform.position.x);
        PlayerPrefs.SetFloat($"{keyPrefix}_Y", transform.position.y);
        PlayerPrefs.SetFloat($"{keyPrefix}_Z", transform.position.z);
        PlayerPrefs.Save(); // 立即写入磁盘,防止意外退出丢失数据
    }

    // 启动时恢复上次位置
    private void Start()
    {
        string keyPrefix = $"Pos_{gameObject.GetInstanceID()}";
        if (PlayerPrefs.HasKey($"{keyPrefix}_X"))
        {
            float x = PlayerPrefs.GetFloat($"{keyPrefix}_X");
            float y = PlayerPrefs.GetFloat($"{keyPrefix}_Y");
            float z = PlayerPrefs.GetFloat($"{keyPrefix}_Z");
            transform.position = new Vector3(x, y, z);
        }
    }
}

2. 关键细节

  • 用GetInstanceID()作为键前缀,确保每个物体的存储键唯一
  • 同时在OnDestroy和手动触发点(如拖拽结束)调用保存,保证数据及时性
  • 必须调用PlayerPrefs.Save(),否则数据仅存于内存,重启后丢失

二、推荐插件(适合复杂场景或快速开发)

如果需要处理旋转、缩放等更多数据,或批量管理存档,推荐以下成熟插件:

1. Easy Save 3

  • 直接支持序列化Unity原生类型(Vector3、Quaternion等),无需手动拆分坐标
  • 支持PlayerPrefs、本地文件、云端等多种存储方式
  • 极简调用示例:
    // 保存位置到本地文件
    ES3.Save<Vector3>("PlayerPos", transform.position, "SaveData.es3");
    // 读取位置
    if (ES3.FileExists("SaveData.es3"))
    {
        transform.position = ES3.Load<Vector3>("PlayerPos", "SaveData.es3");
    }
    
  • 内置数据加密功能,适合需要保护存档的场景

2. Save Game Pro

  • 功能更全面,支持自动保存、存档版本控制、备份
  • 适配多平台安全存储路径,提供可视化编辑器,无需代码即可配置保存规则

三、相关设置与注意事项

  • 跨平台路径:使用文件存储时,务必用Application.persistentDataPath作为根路径,这是Unity官方推荐的跨平台可读写路径,不会被系统清理
  • 移动端权限:Android 10+默认适配Scoped Storage,无需额外配置;iOS无需特殊权限
  • 数据重置:如需清除存档,可调用PlayerPrefs.DeleteKey(keyPrefix)或插件提供的清理接口
  • 性能优化:频繁拖拽时可加入延迟保存逻辑(如拖拽结束后延迟0.5秒再保存),减少IO操作频次

内容的提问来源于stack exchange,提问作者Gelso77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 11:45:28