找回密码
 注册帐号

扫一扫,访问微社区

zhang273162308 Unity实用小工具或脚本——3D物体带坐标轴的拖拽

90
回复
5937
查看
[ 复制链接 ]
排名
139
昨日变化

125

主题

600

帖子

7131

积分

Rank: 9Rank: 9Rank: 9

UID
3579
好友
110
蛮牛币
5948
威望
0
注册时间
2013-9-10
在线时间
1679 小时
最后登录
2020-9-22

专栏作家活力之星游戏蛮牛QQ群会员蛮牛哥

2018-11-13 11:42:17 显示全部楼层 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
一、前言
     我们最近要做一个线路的规划编辑,并且是在三维场景中,编辑完就立马能用。立马能用还好说,有特别多的轮子可以用,在三维场景中实时编辑就有点意思了。其实功能就是类似于在Unity的编辑界面操作一个Cube的位置,当然旋转什么的我这个任务里暂时还不需要,就先简单的做了一个位置的三维拖拽。如图所示:在Unity的编辑界面对一个Cube进行拖拽,选中中心就可以进行任意拖
Cube.gif
拽,选中单个的坐标轴可以进行指定方向的拖拽。
下面是我实现的效果图,如同所示:
3DRoutePointEditor.gif
二、实现
1、任意拖拽的比较简单,主要思路是控制好鼠标按下和正在拖拽的坐标差,以及鼠标的坐标到世界坐标的转换,代码如下
[C#] 纯文本查看 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PointAxis : MonoBehaviour {

    public static Color ColorNormalX = new Color32(255, 100, 100, 255);
    public static Color ColorNormalY = new Color32(100, 255, 100, 255);
    public static Color ColorNormalZ = new Color32(100, 100, 255, 255);

    public static Color ColorBeSelectedX = Color.red;
    public static Color ColorBeSelectedY = Color.green;
    public static Color ColorBeSelectedZ = Color.blue;

    public bool IsBeSelected;
    [SerializeField]
    private PointAxis_Type curPAType;

    private MeshRenderer mr;
    private Color colorNormal;
    private Color colorBeSelected;

    private bool isMouseDrag = false;
    private Vector3 screenPosition;
    private Vector3 offset;
    private Transform parentTransform;
    private Vector3 dragBeforeGameObjPos;
    // Use this for initialization
    void Start () {

        parentTransform = transform.parent;
        mr = GetComponent<MeshRenderer>();
        switch (curPAType)
        {
            case PointAxis_Type.Axis_X:
                colorNormal = ColorNormalX;
                colorBeSelected = ColorBeSelectedX;
                break;
            case PointAxis_Type.Axis_Y:
                colorNormal = ColorNormalY;
                colorBeSelected = ColorBeSelectedY;
                break;
            case PointAxis_Type.Axis_Z:
                colorNormal = ColorNormalZ;
                colorBeSelected = ColorBeSelectedZ;
                break;
        }
      
    }
	
	// Update is called once per frame
	void Update () {

        mr.material.color = IsBeSelected ? colorBeSelected : colorNormal;
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            dragBeforeGameObjPos = parentTransform.transform.position;
            screenPosition = Camera.main.WorldToScreenPoint(dragBeforeGameObjPos);
            offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z));
            isMouseDrag = true;
        }
        if (Input.GetKey(KeyCode.Mouse0))
        {
            if (isMouseDrag && IsBeSelected)
            {
                //Debug.Log("开始拖拽了");
                Vector3 currentScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z);
                Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenSpace) + offset;
                float tempLength = Vector3.Distance(currentPosition, transform.position);
                Vector3 tempPos = Vector3.zero;
                switch (curPAType)
                {
                    case PointAxis_Type.Axis_X:
                        tempPos = Vector3.Project(currentPosition, transform.forward) + Vector3.Project(dragBeforeGameObjPos, transform.up) + Vector3.Project(dragBeforeGameObjPos, transform.right);
                        break;
                    case PointAxis_Type.Axis_Y:
                        tempPos = Vector3.Project(currentPosition, transform.up) + Vector3.Project(dragBeforeGameObjPos, transform.right) + Vector3.Project(dragBeforeGameObjPos, transform.forward);
                        break;
                    case PointAxis_Type.Axis_Z:
                        tempPos = Vector3.Project(currentPosition, transform.right) + Vector3.Project(dragBeforeGameObjPos, transform.up) + Vector3.Project(dragBeforeGameObjPos, transform.forward);
                        break;
                }
                parentTransform.transform.position = tempPos;
            }
        }
        if (Input.GetKeyUp(KeyCode.Mouse0))
        {
            isMouseDrag = false;
        }

    }
}

public enum PointAxis_Type
{
    Axis_X,Axis_Y,Axis_Z
}


2、三个坐标轴方向的拖拽,比较复杂,但是鼠标的移动计算是一样的,只是利用这个的最终位置量需要考虑一下,不能直接使用,需要考虑在每个轴方向的投影。比如X轴,那么就需要考虑这个X轴模型所代表的方向是它的Transform的前、上还是右方向,我这里的X模型的前方向是代表它在世界坐标所指向的方向,然后就将得到的鼠标拖着后的位置变化坐标投影到这个方向,但是其他方向的投影还是原来的位置坐标。代码如下:
[C#] 纯文本查看 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PointEntity : MonoBehaviour {

    public bool IsBeSelected = false;
    private bool isMouseDrag = false;
    private Vector3 screenPosition;
    private Vector3 offset;

    private Color normalColor;
    private Color beSelectedColor;
    private MeshRenderer mr;
    // Use this for initialization
    void Start () {
        mr = GetComponent<MeshRenderer>();
        normalColor = mr.material.color;
        beSelectedColor = new Color32(210, 137, 242,255);
	}
	
	// Update is called once per frame
	void Update () {

        mr.material.color = IsBeSelected ? beSelectedColor : normalColor;

        if(Input.GetKeyDown(KeyCode.Mouse0))
        {
            screenPosition = Camera.main.WorldToScreenPoint(gameObject.transform.position);
            offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z));
            isMouseDrag = true;
        }
        if(Input.GetKey(KeyCode.Mouse0))
        {
            if (isMouseDrag&&IsBeSelected)
            {
                //Debug.Log("开始拖拽了");
                Vector3 currentScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPosition.z);
                Vector3 currentPosition = Camera.main.ScreenToWorldPoint(currentScreenSpace) + offset;
                gameObject.transform.position = currentPosition;
            }
        }
        if(Input.GetKeyUp(KeyCode.Mouse0))
        {
            isMouseDrag = false;
        }
		
	}
}


3、最后在来一段选中控制操作
[C#] 纯文本查看 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ControlCam : MonoBehaviour
{
    public static ControlCam M_Instance
    {
        get
        {
            if(null==_instance)
            {
                _instance = FindObjectOfType<ControlCam>();
            }
            return _instance;
        }
    }

    public bool M_IsCanControl
    {
        get
        {
            return isCanControl;
        }
    }

    public static ControlCam _instance;
    private bool isMouseDrag = false;
    private Vector3 lastMousePos;
    [SerializeField]
    private Vector3 offset;

    private bool isCanControl = false;
    private PointAxis PA;
    private PointEntity PE;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftControl))
        {
            isCanControl = true;
        }
        if (Input.GetKeyUp(KeyCode.LeftControl))
        {
            isCanControl = false;
        }
        if (Input.GetKeyDown(KeyCode.Mouse1))
        {
            lastMousePos = Input.mousePosition;
            isMouseDrag = true;
        }
        if (Input.GetKey(KeyCode.Mouse1))
        {
            if (isMouseDrag)
            {
                offset = Input.mousePosition - lastMousePos;
                transform.RotateAround(Vector3.zero, Vector3.up, offset.x);
                transform.RotateAround(Vector3.zero, Vector3.right, offset.y);
                lastMousePos = Input.mousePosition;
            }
        }
        if (Input.GetKeyUp(KeyCode.Mouse1))
        {
            isMouseDrag = false;
        }
        if (Input.GetKeyUp(KeyCode.Mouse0))
        {
            isCanControl = false;
        }
        if (!isCanControl)
        {
            Reset_SelectedState();
            return;
        }
        Ray tempRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(tempRay, out hit, 2000))
        {
            PointEntity tempHitPE = hit.collider.GetComponent<PointEntity>();
            PointAxis tempHitPA = hit.collider.GetComponent<PointAxis>();
            if (Input.GetKeyDown(KeyCode.Mouse0))
            {
                if (null != tempHitPE)
                {
                    Reset_SelectedState();
                    PE = tempHitPE;
                    PE.IsBeSelected = true;
                }
                else if (null != tempHitPA)
                {
                    Reset_SelectedState();
                    PA = tempHitPA;
                    PA.IsBeSelected = true;
                }
            }
        }
    }

    private void Reset_SelectedState()
    {
        if (null != PE)
        {
            PE.IsBeSelected = false;
            PE = null;
        }
        if (null != PA)
        {
            PA.IsBeSelected = false;
            PA = null;
        }
    }
}


选中单个坐标轴或中心就让其高亮,每个坐标轴和中心都只能选中一个,为了避免在拖拽滑动鼠标的时候会选中其他的坐标轴或者中心,而造成混乱,这里我让鼠标按下的时候才触发选中操作。
三、总结
1、轮子有就好,没有也得学会自力更生
2、基本实现了类似Unity的编辑界面操作拖拽物体的功能,但是操作的设计上还需要有待加强
3、摄像机的旋转是为了观察在不同姿态下,坐标轴的拖拽始终是朝着它所指向的方向
游客,如果您要查看本帖隐藏内容请回复





点评

hao  发表于 2018-11-14 11:26
回复

使用道具 举报

7日久生情
2313/5000
排名
1894
昨日变化

65

主题

828

帖子

2313

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
214924
好友
9
蛮牛币
27193
威望
0
注册时间
2017-3-28
在线时间
704 小时
最后登录
2020-8-27
2018-11-13 13:30:15 显示全部楼层
666666666666666
回复 支持 反对

使用道具 举报

7日久生情
2266/5000
排名
636
昨日变化

3

主题

97

帖子

2266

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
117515
好友
0
蛮牛币
11239
威望
0
注册时间
2015-8-11
在线时间
818 小时
最后登录
2020-9-24
2018-11-13 13:49:22 显示全部楼层
66666666666
回复

使用道具 举报

5熟悉之中
895/1000
排名
3795
昨日变化

4

主题

223

帖子

895

积分

Rank: 5Rank: 5

UID
237362
好友
0
蛮牛币
5090
威望
0
注册时间
2017-8-13
在线时间
292 小时
最后登录
2020-9-24
2018-11-13 13:56:55 显示全部楼层
学习学习
回复

使用道具 举报

7日久生情
1876/5000
排名
2924
昨日变化

9

主题

171

帖子

1876

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
220670
好友
0
蛮牛币
150
威望
0
注册时间
2017-5-4
在线时间
1192 小时
最后登录
2020-9-23
2018-11-13 14:26:34 显示全部楼层
666666666666666666666666666666厉害
回复 支持 反对

使用道具 举报

6蛮牛粉丝
1400/1500
排名
3219
昨日变化

10

主题

271

帖子

1400

积分

Rank: 6Rank: 6Rank: 6

UID
193233
好友
6
蛮牛币
8358
威望
0
注册时间
2016-12-17
在线时间
645 小时
最后登录
2020-9-19
2018-11-13 15:24:41 显示全部楼层
学习一下
回复

使用道具 举报

7日久生情
2630/5000
排名
1826
昨日变化

14

主题

395

帖子

2630

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
217870
好友
1
蛮牛币
1444
威望
0
注册时间
2017-4-15
在线时间
1491 小时
最后登录
2020-9-24
2018-11-13 16:50:00 显示全部楼层
回复

使用道具 举报

7日久生情
1781/5000
排名
1837
昨日变化

11

主题

295

帖子

1781

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
252607
好友
5
蛮牛币
13893
威望
0
注册时间
2017-11-5
在线时间
744 小时
最后登录
2020-9-23
2018-11-13 17:10:47 显示全部楼层
23333333333333333333333333
回复 支持 反对

使用道具 举报

排名
9399
昨日变化

13

主题

223

帖子

1165

积分

Rank: 9Rank: 9Rank: 9

UID
21402
好友
16
蛮牛币
107
威望
0
注册时间
2014-4-14
在线时间
648 小时
最后登录
2020-9-22

认证开发者

2018-11-13 23:34:37 显示全部楼层
还可以 ,希望组件化
回复 支持 反对

使用道具 举报

排名
9399
昨日变化

13

主题

223

帖子

1165

积分

Rank: 9Rank: 9Rank: 9

UID
21402
好友
16
蛮牛币
107
威望
0
注册时间
2014-4-14
在线时间
648 小时
最后登录
2020-9-22

认证开发者

2018-11-13 23:34:43 显示全部楼层
还可以 ,希望组件化
回复 支持 反对

使用道具 举报

7日久生情
1838/5000
排名
1485
昨日变化

0

主题

161

帖子

1838

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
18859
好友
1
蛮牛币
4493
威望
0
注册时间
2014-3-25
在线时间
825 小时
最后登录
2020-9-21
2018-11-14 08:13:14 显示全部楼层
看下下下下下。。。。。
回复

使用道具 举报

6蛮牛粉丝
1148/1500
排名
4938
昨日变化

1

主题

111

帖子

1148

积分

Rank: 6Rank: 6Rank: 6

UID
257307
好友
0
蛮牛币
1128
威望
0
注册时间
2017-12-1
在线时间
732 小时
最后登录
2020-9-24
2018-11-14 08:34:36 显示全部楼层
666666666666666666666666
回复 支持 反对

使用道具 举报

7日久生情
1720/5000
排名
1336
昨日变化

9

主题

221

帖子

1720

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
215462
好友
1
蛮牛币
4307
威望
0
注册时间
2017-3-30
在线时间
578 小时
最后登录
2020-8-17
2018-11-14 09:08:31 显示全部楼层
跟现在正在用的一个差不多,不过还是学习了
回复 支持 反对

使用道具 举报

5熟悉之中
835/1000
排名
6934
昨日变化

6

主题

167

帖子

835

积分

Rank: 5Rank: 5

UID
279482
好友
1
蛮牛币
571
威望
0
注册时间
2018-5-1
在线时间
472 小时
最后登录
2020-9-24
2018-11-14 09:09:02 显示全部楼层
回复

使用道具 举报

7日久生情
2793/5000
排名
780
昨日变化

1

主题

758

帖子

2793

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
56496
好友
0
蛮牛币
9576
威望
0
注册时间
2014-11-19
在线时间
816 小时
最后登录
2020-9-24
2018-11-14 09:12:16 显示全部楼层
感谢分享,思路很重要。。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

蛮牛教育10.1大促销!全站6折扣!