3D角色——轮转效果

废话不多说,先看第一篇代码!

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class RotationChart3D : MonoBehaviour
{
    public int n;  // 使用的角色数量
    public float spacing = 1;  // 角色之间的间距
    float c;  // 圆的周长
    float r;  // 圆的半径
    float ang;  // 每个角色的角度
    float moveang;  // 移动的角度增量
    List<GameObject> list = new List<GameObject>();  // 角色对象列表
    List<Transform> sortlist = new List<Transform>();  // 排序后的角色对象列表

    void Start()
    {
        c = (1 + spacing) * n;  // 计算圆的周长
        r = c / (2 * Mathf.PI);  // 计算圆的半径
        ang = 2 * Mathf.PI / n;  // 计算每个角色的角度

        for (int i = 0; i < n; i++)
        {
            // 实例化角色对象,加载对应资源文件
            list.Add(Instantiate(Resources.Load<GameObject>("Role/" + i), transform));
            float x = Mathf.Sin(i * ang) * r;  // 根据角度计算x坐标
            float z = Mathf.Cos(i * ang) * r;  // 根据角度计算z坐标
            list[i].transform.localPosition = new Vector3(x, 0, z);  // 设置角色对象的位置
            list[i].AddComponent<PlayerMove>();  // 向角色对象添加PlayerMove组件
            sortlist.Add(list[i].transform);  // 将角色对象的transform添加到排序列表中
        }
    }

    public void Move(float dis)
    {
        moveang += dis / r;  // 根据移动距离计算角度增量
        for (int i = 0; i < list.Count; i++)
        {
            float x = Mathf.Sin(i * ang + moveang) * r;  // 根据角度和角度增量计算x坐标
            float z = Mathf.Cos(i * ang + moveang) * r;  // 根据角度和角度增量计算z坐标
            list[i].transform.localPosition = new Vector3(x, 0, z);  // 更新角色对象的位置
        }
    }

    public void Inertia(float endspeed)
    {
        float time = Mathf.Abs(endspeed) / 1;  // 计算惯性运动的时间
        DOTween.To((float a) =>
        {
            Move(a);  // 根据角度增量移动角色对象
        }, endspeed, 0, time).OnComplete(() =>
        {
            Align();  // 惯性运动结束后进行对齐操作
        });
    }

    public void Align()
    {
        sortlist.Sort((a, b) =>
        {
            if (a.localPosition.z < b.localPosition.z)  // 比较z坐标大小进行排序
            {
                return 1;
            }
            else if (a.localPosition.z == b.localPosition.z)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        });
        float alignang = Mathf.Atan(sortlist[0].localPosition.x / sortlist[0].localPosition.z);  // 计算对齐的角度
        float aligndis = alignang * r;  // 计算对齐的距离
        float time = Mathf.Abs(aligndis) / 1;  // 计算对齐的时间
        DOTween.To((float a) =>
        {
            for (int i = 0; i < list.Count; i++)
            {
                float x = Mathf.Sin(i * ang + a) * r;  // 根据角度计算x坐标
                float z = Mathf.Cos(i * ang + a) * r;  // 根据角度计算z坐标
                list[i].transform.localPosition = new Vector3(x, 0, z);  // 更新角色对象的位置
            }
        }, moveang, moveang - alignang, time);  // 动态更新位置,实现对齐效果
    }
}

 注意事项:1.这篇代码挂在空对象身上就可以

                   2.命名空间上的using DG.Tweening;这个是DoTween插件,可到网上自行下载

                   3.Resources目录下如果你有文件夹,路径一定要对

接下来看第二篇代码,这是给每一个预制体(游戏角色)挂的脚本(这里不用手动挂,在第一篇代码中实例化角色的时候会动态给角色添加脚本)。

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

public class PlayerMove : MonoBehaviour
{
    Camera cam;  // 相机对象
    Vector3 pos;  // 鼠标点击位置

    void Start()
    {
        cam = Camera.main;  // 获取主摄像机对象
    }

    private void OnMouseDown() // 鼠标点击自身
    {
        float z = cam.WorldToScreenPoint(transform.position).z;  // 将角色对象的世界位置转换为屏幕坐标,并获取z坐标
        pos = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, z));  // 将鼠标点击位置转换为世界坐标
    }

    private void OnMouseDrag() // 鼠标拖拽自身
    {
        float z = cam.WorldToScreenPoint(transform.position).z;  // 将角色对象的世界位置转换为屏幕坐标,并获取z坐标
        Vector3 pos1 = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, z));  // 将鼠标当前位置转换为世界坐标
        float dis = pos1.x - pos.x;  // 计算鼠标移动距离
        transform.parent.GetComponent<RotationChart3D>().Move(dis);  // 调用父对象(RotationChart3D)中的Move方法,传入移动距离
        pos = pos1;  // 更新鼠标位置
    }

    private void OnMouseUp() // 鼠标抬起
    {
        float z = cam.WorldToScreenPoint(transform.position).z;  // 将角色对象的世界位置转换为屏幕坐标,并获取z坐标
        Vector3 pos1 = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, z));  // 将鼠标当前位置转换为世界坐标
        float dis = pos1.x - pos.x;  // 计算鼠标移动距离
        transform.parent.GetComponent<RotationChart3D>().Inertia(dis);  // 调用父对象(RotationChart3D)中的Inertia方法,传入移动距离
        pos = pos1;  // 更新鼠标位置
    }
}

 注意事项:游戏对象如何想要触发OnMonseDown(所有鼠标在物体身上触发的效果),身上一定要有一个碰撞器组件。游戏对象的话,常用Capsule Collider 胶囊碰撞器就可以。

效果展示:

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值