41.拖拽相关

41.FGUI基础-Unity中的使用必备-拖拽相关


41.1 知识点

现有知识实现拖拽

利用OnTouchBegin、OnTouchEnd、OnTouchMove事件可以完成拖拽功能

FGUI中的自由拖拽功能

获取对象设置 draggable属性为true 即可拖拽
注意:拖动只能在元件父组件内移动

TeachPanel panel = UIManager.Instance.ShowPanel<TeachPanel>("Teach");
panel.m_btnTest.draggable = true;

// 自由拖拽事件相关
// 开始拖
panel.m_btnTest.onDragStart.Add(()=> {
    print("开始拖");
});
// 拖动中
panel.m_btnTest.onDragMove.Add(() => {
    print("拖动中");
});
// 结束拖
panel.m_btnTest.onDragEnd.Add(() => {
    print("结束拖动");
});

设置拖动范围

注意,范围是舞台上的坐标 不是元件的本地坐标
传入起始位置的xy和宽高为限制矩形

// 代码示例
panel.m_btnTest.dragBounds = new Rect(500, 0, 1000, 200);

确认按钮可以被拖拽了 但是被限制在以500,0为原点的1000x200矩形中


41.2 知识点代码

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

public class Lesson41_FGUI基础_Unity中的使用必备_拖拽相关 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 现有知识实现拖拽
        //利用OnTouchBegin、OnTouchEnd、OnTouchMove事件可以完成拖拽功能
        #endregion

        #region 知识点二 FGUI中的自由拖拽功能

        //获取对象设置 draggable属性为true 即可拖拽
        //注意:拖动只能在元件父组件内移动

        TeachPanel panel = UIManager.Instance.ShowPanel<TeachPanel>("Teach");
        panel.m_btnTest.draggable = true;

        //自由拖拽事件相关
        //开始拖
        panel.m_btnTest.onDragStart.Add(()=> {
            print("开始拖");
        });
        //拖动中
        panel.m_btnTest.onDragMove.Add(() => {
            print("拖动中");
        });
        //结束拖
        panel.m_btnTest.onDragEnd.Add(() => {
            print("结束拖动");
        });

        #endregion

        #region 知识点三 设置拖动范围

        //注意,范围是舞台上的坐标 不是元件的本地坐标
        //传入起始位置的xy和宽高为限制矩形
        panel.m_btnTest.dragBounds = new Rect(500, 0, 1000, 200);

        #endregion
    }
}

41.3 练习题

在上节课的练习题基础上,请用现在所学知识,制作一个摇杆功能

创建摇杆的背景底图和摇杆装载器,设置好关联系统

创建摇杆变量和初始化位置变量,初始化赋值

public GLoader m_btnController;
//摇杆一开始所在的位置
private Vector2 initPos;

m_btnController = GetChild("btnController").asLoader;
initPos = m_btnController.position;

让摇杆能被拖拽。拖拽结束时还原位置。通过矩形判限制置不合适。在移动事件记录位移向量并限制范围。

//让摇杆小按钮能够被拖动
m_btnController.draggable = true;

//结束拖动时 让它的位置还原
m_btnController.onDragEnd.Add(() =>
{
    m_btnController.position = initPos;
});

//可以通过矩形范围来判断 但是不建议 因为摇杆往往是圆形范围
//GObject bk = this.GetChild("n31");
//m_btnController.dragBounds = new Rect(bk.x, bk.y, bk.width, bk.height);

m_btnController.onDragMove.Add(() =>
{
    //记录位移向量
    Vector2 vec = m_btnController.xy - initPos;

    //超过圆形半径 限制死范围
    if (vec.magnitude >= 100)
    {
        m_btnController.xy = initPos + vec.normalized * 100;
    }
});

41.4 练习题代码

/** This is an automatically generated class by FairyGUI. Please do not modify it. **/

using FairyGUI;
using FairyGUI.Utils;
using UnityEngine;

namespace Teach
{
    public partial class ExercisesPanel : GComponent
    {

        //在上节课的练习题基础上
        //请用现在所学知识,制作一个摇杆功能
        
        
        public Controller m_RadioGroup;
        public GRichTextField m_richTxt1;
        public GRichTextField m_richTxt2;
        public GTextInput m_inputTxt;
        public GTextField m_txtInfo;
        public GTextField m_txtName;
        public GButton m_btnFire;
        public GButton m_checkBoxMusic;
        public GButton m_radioBoxOpen;
        public GButton m_radioBoxClose;
        public GSlider m_soundSlider;
        public GButton m_btnBag;
        public GImage m_imgF;

        public GLoader m_imgA;
        public GLoader m_imgB;

        public GLoader m_btnController;

        public const string URL = "ui://wrs19joehkfz2s";

        private Player player;

        //当前选中的图片替身 C
        private GLoader tempImg;
        //当前选中的图片对象
        private GLoader nowSelImg;
        //当前进入的图片对象
        private GLoader nowInImg;

        //摇杆一开始所在的位置
        private Vector2 initPos;

        public static ExercisesPanel CreateInstance()
        {
            return (ExercisesPanel)UIPackage.CreateObject("Teach", "ExercisesPanel");
        }

        public override void ConstructFromXML(XML xml)
        {
            base.ConstructFromXML(xml);

            m_RadioGroup = GetControllerAt(0);
            m_richTxt1 = (GRichTextField)GetChildAt(0);
            m_richTxt2 = (GRichTextField)GetChildAt(1);
            m_inputTxt = (GTextInput)GetChildAt(3);
            m_txtInfo = (GTextField)GetChildAt(4);
            m_txtName = (GTextField)GetChildAt(7);
            m_btnFire = (GButton)GetChildAt(15);
            m_checkBoxMusic = (GButton)GetChildAt(16);
            m_radioBoxOpen = (GButton)GetChildAt(17);
            m_radioBoxClose = (GButton)GetChildAt(18);
            m_soundSlider = (GSlider)GetChildAt(19);
            m_btnBag = (GButton)GetChildAt(20);
            m_imgF = GetChild("imgF").asImage;
            m_imgA = GetChild("imgA").asLoader;
            m_imgB = GetChild("imgB").asLoader;
            m_btnController = GetChild("btnController").asLoader;

            initPos = m_btnController.position;

            m_richTxt1.onClickLink.Add(Exercises.ClickLinkOpenPanel);
            m_richTxt2.onClickLink.Add(Exercises.ClickLinkOpenPanel);
            

            //输入文本练习题相关
            m_inputTxt.onChanged.Add(() =>
            {
                //让文本控件的内容和输入的内容一致
                m_txtInfo.text = m_inputTxt.text;
            });

            m_btnFire.onClick.Add(() =>
            {
                player.Fire();
            });

            m_checkBoxMusic.onChanged.Add(() =>
            {
                if (m_checkBoxMusic.selected)
                    GRoot.inst.EnableSound();
                else
                    GRoot.inst.DisableSound();
            });

            Controller c = this.GetController("RadioGroup");
            c.onChanged.Add(() =>
            {
                if (c.selectedIndex == 0)
                    GRoot.inst.EnableSound();
                else
                    GRoot.inst.DisableSound();
            });

            m_soundSlider.onChanged.Add(() => {
                GRoot.inst.soundVolume = (float)m_soundSlider.value;
            });

            m_btnBag.onClick.Add(() =>
            {
                //ExercisesBagPanel bagPanel = ExercisesBagPanel.CreateInstance();
                //GRoot.inst.AddChild(bagPanel);
                //显示背包面板
                UIManager.Instance.ShowPanel<ExercisesBagPanel>("Teach");
            });

            m_imgA.onTouchBegin.Add(TouchBegin);
            m_imgA.onTouchMove.Add(TouchMove);
            m_imgA.onTouchEnd.Add(TouchEnd);
            m_imgA.onRollOver.Add(InImg);
            m_imgA.onRollOut.Add(OutImg);

            m_imgB.onTouchBegin.Add(TouchBegin);
            m_imgB.onTouchMove.Add(TouchMove);
            m_imgB.onTouchEnd.Add(TouchEnd);
            m_imgB.onRollOver.Add(InImg);
            m_imgB.onRollOut.Add(OutImg);


            //让摇杆小按钮能够被拖动
            m_btnController.draggable = true;

            //结束拖动时 让它的位置还原
            m_btnController.onDragEnd.Add(() =>
            {
                m_btnController.position = initPos;
            });

            //可以通过矩形范围来判断 但是不建议 因为摇杆往往是圆形范围
            //GObject bk = this.GetChild("n31");
            //m_btnController.dragBounds = new Rect(bk.x, bk.y, bk.width, bk.height);

            m_btnController.onDragMove.Add(() =>
            {
                //记录位移向量
                Vector2 vec = m_btnController.xy - initPos;

                //超过圆形半径 限制死范围
                if( vec.magnitude >= 100 )
                {
                    m_btnController.xy = initPos + vec.normalized * 100;
                }
            });
        }

        private void TouchBegin(EventContext eventData)
        {
            //如果希望之后的抬起 在对象外部也能够响应 那么需要添加一句代码
            eventData.CaptureTouch();

            //记录选择了谁
            nowSelImg = eventData.sender as GLoader;

            GLoader target = eventData.sender as GLoader;
            tempImg = new GLoader();
            //自动大小
            tempImg.autoSize = true;
            //设置图片路径
            tempImg.url = target.url;
            //改为半透明
            tempImg.alpha = 0.5f;
            //不能触摸 就不会挡住事件监听
            tempImg.touchable = false;
            //为了移动时和创建时 是中央和鼠标重合 那么我们可以通过锚点来改变
            tempImg.SetPivot(0.5f, 0.5f, true);

            //把物理坐标转为UI坐标
            Vector2 nowPos = GRoot.inst.GlobalToLocal(new Vector2(eventData.inputEvent.x, eventData.inputEvent.y));
            tempImg.SetPosition(nowPos.x, nowPos.y, 0);

            this.AddChild(tempImg);
        }

        private void TouchMove(EventContext eventData)
        {
            //不停的在内部设置位置即可
            Vector2 nowPos = GRoot.inst.GlobalToLocal(new Vector2(eventData.inputEvent.x, eventData.inputEvent.y));
            tempImg.SetPosition(nowPos.x, nowPos.y, 0);
        }

        private void TouchEnd()
        {
            //松手时 就是真正产生交换的位置
            if( nowInImg != null && nowSelImg != null &&
                nowInImg != nowSelImg )
            {
                //只有有选中的和需要进入交换的 就可以执行交换逻辑了
                string tmp = nowSelImg.url;
                nowSelImg.url = nowInImg.url;
                nowInImg.url = tmp;
            }

            //删除图片
            if (tempImg != null)
                tempImg.Dispose();
            tempImg = null;

            //不管你交换是否完成 都应该置空
            nowSelImg = null;
            nowInImg = null;
        }

        private void InImg(EventContext eventData)
        {
            //记录进入了谁
            nowInImg = eventData.sender as GLoader;
        }

        private void OutImg(EventContext eventData)
        {
            //记录离开了谁
            nowInImg = null;
        }

        /// <summary>
        /// 更新图片位置 
        /// </summary>
        /// <param name="inputPos">鼠标位置</param>
        public void UpdateImgPos(Vector3 inputPos)
        {
            //要把屏幕坐标(鼠标位置)转换成UI坐标 不停的赋值给跟随移动的图片
            //相对于FGUI坐标系的 物理坐标
            inputPos.y = Screen.height - inputPos.y;
            //物理坐标 转 逻辑坐标(UI坐标)
            m_imgF.position = GRoot.inst.GlobalToLocal(inputPos);
        }

        public void SetPlayer(Player player)
        {
            this.player = player;
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏