unity 实现3D 轮转图 及其 惯性 和 对齐

1.动态生成对象实现平面圆上,弧边上规律生成

围绕圆的弧边动态生成对象

    public GameObject prefab; //对象
    public int num; //生成对象数量
    public float r; //半径
    float ang;
    void Start()
    {
        ang = 2 * Mathf.PI / num;
        //生成球
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(i * ang) * r; //位置x
            float z = Mathf.Cos(i * ang) * r; //位置z
            GameObject sphere = Instantiate(prefab); //生成对象
            sphere.transform.parent = transform; //设置父对象
            sphere.transform.localPosition = new Vector3(x, 0, z); //赋值位置
        }
    }

脚本挂载到空对象上 设置上面属性

运行后生成

 2.实现鼠标拖动进行旋转 轮转效果

方法OnDrag用于接受拖动距离 对距离进行操作计数实现物体同步鼠标滑动移动

 public GameObject prefab;
    public int num;
    public float r;
    // Start is called before the first frame update
     float ang;
    List<GameObject> list = new List<GameObject>();
    List<Transform> sort = new List<Transform>();
    void Start()
    {
        ang = 2 * Mathf.PI / num;
        //生成球
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(i * ang) * r;
            float z = Mathf.Cos(i * ang) * r;
            GameObject sphere = Instantiate(prefab);
            sphere.transform.parent = transform;
            sphere.transform.localPosition = new Vector3(x, 0, z);
            sphere.GetComponent<CyclogramItem>().cyclogram = this;
            list.Add(sphere);
            sort.Add(sphere.transform);
            
        }
    }
    float allang = 0;
    public void OnDrag(float dis)
    {
        float moveang = dis / r;
        allang -= moveang;
        for (int i = 0; i < list.Count; i++)
        {
            float x = Mathf.Sin(i * ang + allang) * r;
            float z = Mathf.Cos(i * ang + allang) * r;
            list[i].transform.localPosition = new Vector3(x, 0, z);
        }
    }

为预制体对象添加脚本 调用 OnDrag方法 , cyclogram是空物体脚本的实例

对物体坐标变成屏幕坐标,取z轴位置 同步与鼠标的位置一样 

求出距离 调用 OnDrag 实现鼠标滑动物体,物体实现轮转效果

  private void OnMouseDrag()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        Vector3 next = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));
        float dis = next.x - transform.position.x;
        cyclogram.OnDrag(dis);
       
    }

3.实现物体加上惯性,拖动结束后,物体平滑缓慢停止 停止后可以实现对齐

下面提供完整代码,附上完整注释:

DowTeen

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DT : MonoBehaviour
{
    public Action<float> action; // 动作回调,接收一个浮点数参数
    public float begin; // 动画开始的值
    public float end; // 动画结束的值
    public float time; // 动画的总时间
    float nowtime; // 动画开始的时间
    public Action complete; // 完成动画后的回调函数
    public static DT To(Action<float> action, float begin, float end, float time)
    {
        GameObject dt = new GameObject("DT");             // 创建一个新的游戏对象
        DT dowteen = dt.AddComponent<DT>();                // 在游戏对象上添加DT组件
        dowteen.action = action;                            // 设置动作回调函数
        dowteen.begin = begin;                              // 设置动画开始的值
        dowteen.end = end;                                  // 设置动画结束的值
        dowteen.time = time;                                // 设置动画的总时间
        dowteen.nowtime = Time.time;                        // 记录动画开始的时间
        return dowteen;
    }

    void Update()
    {
        if (Time.time - nowtime < time)                         // 当当前时间减去动画开始时间小于动画总时间时
        {
            float t = Time.time - nowtime;                      // 计算动画已执行的时间
            float p = t / time;                                 // 计算动画的进度(时间比例)
            float a = begin * (1 - p) + end * p;                // 根据进度计算当前值
            action(a);                                          // 执行动作回调,传入当前值
        }
        else
        {
            action(end);                                        // 动画时间已经超过总时间,直接执行动作回调,传入结束值
            if (complete != null)                                 // 如果有完成回调函数
            {
                complete();                                     // 执行完成回调
            }
            Destroy(gameObject);                               // 销毁游戏对象
        }

        if (time >= 5)
        {
            time = 3;
        }
    }

    public void OnComplete(Action complete)
    {
        this.complete = complete;                   // 设置完成回调函数
    }
}

CyclogramItem 轮转图对象item脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CyclogramItem : MonoBehaviour
{
    public Cyclogram cyclogram;
    // 当鼠标拖拽时触发的方法
    private void OnMouseDrag()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position); // 将物体的世界坐标转换为屏幕坐标
        Vector3 next = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z)); // 将鼠标位置的屏幕坐标转换为世界坐标
        float dis = next.x - transform.position.x; // 计算物体在x轴上的位移
        cyclogram.OnDrag(dis); // 将位移传递给cyclogram实例的OnDrag方法
    }

    // 当鼠标抬起时触发的方法
    private void OnMouseUp()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position); // 将物体的世界坐标转换为屏幕坐标
        Vector3 next = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z)); // 将鼠标位置的屏幕坐标转换为世界坐标
        float dis = next.x - transform.position.x; // 计算物体在x轴上的位移
        cyclogram.Inertia(dis); // 将位移传递给cyclogram实例的Inertia方法
    }


}

Cyclogram轮转图空对象代码
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cyclogram : MonoBehaviour
{
    public GameObject prefab;   // 预制体
    public int num;             // 圆数量
    public float r;             // 半径
    public float dec = 0.8f;    // 减速系数

    float ang;                  // 每个圆之间的夹角
    List<GameObject> list = new List<GameObject>();     // 圆的列表
    List<Transform> sort = new List<Transform>();        // 排序列表

    void Start()
    {
        ang = 2 * Mathf.PI / num;

        // 生成圆
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(i * ang) * r;
            float z = Mathf.Cos(i * ang) * r;

            GameObject sphere = Instantiate(prefab);   // 克隆预制体生成圆
            sphere.transform.parent = transform;       // 设置圆的父物体为当前游戏对象
            sphere.transform.localPosition = new Vector3(x, 0, z);    // 设置圆的位置
            sphere.GetComponent<CyclogramItem>().cyclogram = this;     // 获取圆上的CyclogramItem组件,并设置cyclogram属性为当前脚本的引用
            list.Add(sphere);    // 添加到圆的列表中
            sort.Add(sphere.transform);     // 添加到排序列表中
        }
    }

    float allang = 0;

    public void OnDrag(float dis)
    {
        float moveang = dis / r;
        allang -= moveang;

        // 更新圆的位置
        for (int i = 0; i < list.Count; i++)
        {
            float x = Mathf.Sin(i * ang + allang) * r;
            float z = Mathf.Cos(i * ang + allang) * r;
            list[i].transform.localPosition = new Vector3(x, 0, z);
        }
    }

    public void Inertia(float dis)
    {
        float time = Mathf.Abs(dis / dec);

        DT.To((a) =>
        {
            OnDrag(a);
        }, dis, 0, time).OnComplete(() =>
        {
            sort.Sort((a, b) =>
            {
                // 根据位置z坐标进行排序
                if (a.position.z < b.position.z)
                {
                    return -1;
                }
                else if (a.position.z == b.position.z)
                {
                    return 0;
                }
                else
                {
                    return 1;
                }
            });

            float aligning = Mathf.Asin(sort[0].localPosition.x / r);
            float aligningtime = Mathf.Abs(aligning * r / dec);

            // 将圆重新排序并对齐
            DT.To((a) =>
            {
                allang = a;
                for (int i = 0; i < list.Count; i++)
                {
                    float x = Mathf.Sin(i * ang + allang) * r;
                    float z = Mathf.Cos(i * ang + allang) * r;
                    list[i].transform.localPosition = new Vector3(x, 0, z);
                }
            }, allang, allang + aligning, aligningtime);
        });
    }

    void Update()
    {

    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Unity是一款强大的游戏开发引擎,可以用于实现各种各样的游戏功能和效果,包括在3D物体表面上挖孔。 在Unity实现3D物体表面挖孔,一种常见的方法是使用基于几何的技术。具体步骤如下: 1. 首先,需要一个3D模型,可以使用3D建模软件或者下载现有的模型资源。 2. 在Unity创建一个3D对象,将该模型导入到场景。 3. 选该模型,添加一个Collider组件,确保物体具有碰撞器。 4. 创建一个脚本文件,并将其附加到该模型上。在脚本,我们将使用鼠标点击事件来实现挖孔的功能。 5. 在脚本,使用鼠标点击事件获取鼠标点击位置的3D坐标。 6. 使用射线投射技术,从鼠标点击位置向物体内部发出射线。 7. 通过检测射线与物体碰撞点,获取碰撞点的位置和法线。 8. 根据碰撞点的位置和法线,使用几何运算将此处的物体顶点进行改变,模拟挖孔效果。 9. 更新物体的网格信息,使其重新生成表面。 10. 最后,根据需求,可以给挖孔区域增加一些特效,比如添加纹理、粒子效果等,以增强视觉效果。 通过以上步骤,我们在Unity可以实现3D物体表面挖孔的效果。这种方法能够实现比较简单的挖孔操作,但如果需要更复杂的挖孔效果,可能需要使用更高级的技术,比如基于物理引擎的仿真等。 要注意的是,实现3D物体表面挖孔需要一定的计算资源和编程技巧,因此在实现过程需要注意性能优化和代码可维护性,以确保游戏的流畅性和可扩展性。 ### 回答2: 在Unity实现3D物体表面的挖孔需要采取一定的步骤。首先,我们需要一个3D模型作为基础。可以使用Unity自带的模型创建工具(如ProBuilder)或者外部建模软件(如Blender)来创建一个具有表面挖孔功能的模型。 接下来,我们需要为模型创建一个材质,并在该材质设置透明效果。通过修改材质的属性,可以让物体的部分区域透明显示,从而实现挖孔的效果。我们可以将这一属性称之为"透明深度",其数值可根据需要进行调整。 然后,我们需要在模型的表面确定挖孔的位置。这可以通过添加一个附加的几何网格(如一个平面或小立方体)来实现。我们可以通过将这个附加的几何网格与模型进行布尔运算,从而真正地将模型的表面切割出一个洞来。 最后,在游戏运行时,我们需要实时更新模型的材质。通过使用Raycast或者其他方法,可以检测到位置在洞上方的碰撞点,并根据该碰撞点动态地更新模型的材质透明深度,以便在运行时实时显示挖孔效果。 需要注意的是,这只是一种简单的实现方式。在实际项目,还需要考虑更复杂的情况,如洞的形状、洞的大小和位置等。此外,在实现过程还需要处理碰撞检测、光照和阴影等问题,以获得更真实、更优质的显示效果。但总体而言,使用Unity进行3D物体表面挖孔是可行的,只需要按照上述步骤逐步进行操作即可。 ### 回答3: Unity是一款强大的游戏引擎,可用于创建各种类型的游戏和应用程序。要实现3D物体的表面挖孔,可以通过以下步骤在Unity完成。 首先,在Unity创建一个3D物体,比如一个立方体或球体。可以使用内置的3D对象创建功能或导入自定义模型。 然后,为了在物体表面上创建挖孔,需要在该物体上添加网格和碰撞器组件。网格组件定义了物体的形状,并允许我们对其进行操作。碰撞器组件用于处理与其他物体的交互。 接下来,可以使用Unity的建模工具或独立的3D建模软件来创建挖孔的形状。比如,可以使用圆柱体或球体创建一个挖孔模型,然后将其放置在要挖孔的物体上。 在挖孔模型完成后,将其设置为相同网格组件上的一个子网格。这可以通过Unity的层级面板和编辑器功能来完成。确保子网格正确放置在主物体上。 然后,在脚本使用布尔运算来实现物体的表面进行挖孔操作。Unity有许多脚本插件和工具可用于这个任务,比如ProBuilder和Mesh Baker。使用这些工具,可以对子网格进行布尔差异运算,以在主物体上创建挖孔效果。 最后,可以在场景调整和优化挖孔后的物体。可以根据需要对物体进行纹理映射、光照和特殊效果的添加,以使其更加真实和逼真。 通过以上步骤,就可以在Unity实现3D物体表面的挖孔效果。这种方法可以应用于各种类型的3D模型和场景,以创建更加复杂和精细的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值