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

Unity中基于排序算法实现球体游戏对象位置交换的脚本问题

解决Unity中按名称排序GameObject并同步位置的问题

嘿,我来帮你搞定这个问题!你当前的代码确实完成了列表的排序,但只是调整了内存里的GameObject引用顺序,场景中的对象位置完全没变化——这就是核心问题所在。咱们一步步来修改,让排序后的球体真正交换位置。

核心思路

要实现视觉上的位置排序,需要做两件事:

  • 记录每个对象的目标位置(可以是它们的初始生成位置,也可以是当前排列的位置)
  • 排序完成后,把每个对象移动到对应索引的位置上

另外,你的Fill()方法每次点击按钮都会重新实例化一批球体,多次点击会导致场景里堆满重复对象,建议只在初始化时实例化一次。

修改后的完整代码

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

namespace Assets
{
    public class Gameobjects : MonoBehaviour
    {
        public Button s_YourButton;
        [SerializeField] private GameObject[] deck;
        
        // 保存实例化的对象
        private List<GameObject> instanciatedObjects;
        // 保存每个对象的初始位置(排序后会把对象放到对应索引的初始位置)
        private List<Vector3> originalPositions;

        void Start()
        {
            Button btn = s_YourButton.GetComponent<Button>();
            btn.onClick.AddListener(TaskOnClick);
            
            // 初始化时只实例化一次对象,避免重复生成
            Fill();
        }

        void TaskOnClick()
        {
            // 按名称排序对象列表
            var sortedObjects = instanciatedObjects.OrderBy(sphere => sphere.name).ToList();
            
            // 遍历排序后的列表,把每个对象移动到对应索引的初始位置
            for (int i = 0; i < sortedObjects.Count; i++)
            {
                sortedObjects[i].transform.position = originalPositions[i];
            }
            
            // 可选:更新原列表为排序后的结果(如果后续需要用到排序后的列表)
            instanciatedObjects = sortedObjects;
        }

        public void Fill()
        {
            instanciatedObjects = new List<GameObject>();
            originalPositions = new List<Vector3>();
            
            for (int i = 0; i < deck.Length; i++)
            {
                var newSphere = Instantiate(deck[i]);
                instanciatedObjects.Add(newSphere);
                // 记录每个球体生成时的初始位置
                originalPositions.Add(newSphere.transform.position);
            }
        }
    }
}

代码改动说明

  • 添加了originalPositions列表,用来存储每个球体实例化时的初始位置,作为排序后的目标位置
  • 把Fill()的调用移到Start()里,避免每次点击按钮都生成新的球体
  • 在TaskOnClick()中,排序完成后遍历列表,将每个球体的位置设置为对应索引的初始位置,这样排序后的列表顺序就对应了场景中的位置顺序

进阶优化思路

如果想要更流畅的视觉效果(比如球体平滑移动到目标位置,而不是瞬间跳转),可以用协程实现动画过渡:

IEnumerator MoveToPosition(GameObject obj, Vector3 targetPos, float duration = 0.5f)
{
    Vector3 startPos = obj.transform.position;
    float elapsedTime = 0;
    
    while (elapsedTime < duration)
    {
        obj.transform.position = Vector3.Lerp(startPos, targetPos, elapsedTime / duration);
        elapsedTime += Time.deltaTime;
        yield return null;
    }
    
    obj.transform.position = targetPos;
}

然后在TaskOnClick()里替换位置设置的代码为:

for (int i = 0; i < sortedObjects.Count; i++)
{
    StartCoroutine(MoveToPosition(sortedObjects[i], originalPositions[i]));
}

这样点击排序按钮后,球体会平滑地移动到排序后的位置,体验更好~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:27:55