dota2rpg panorama ui的可拖动控件的实现

本文通过解析 dota_addons/ui_example里面的inventory_item控件来说明如何在dota2rpg的UI中制作一个可拖动的控件。

一、可拖动控件的注册和回调的声明

在dota2中,任何的panel都可以变为可拖动的元素,需要在定义这个panel的时候,将这个panel的draggabletag设置为true。即:

<Panel draggable="true" />

这个panel就可以变为可拖动的panel。

他们就可以通过$.RegisterEventHandler( 'DragEnter', panel, OnDragEnter );这类语句来绑定他们的拖动回调函数。
这些的事件包括:

$.RegisterEventHandler( 'DragEnter', panel, OnDragEnter );
$.RegisterEventHandler( 'DragDrop', panel, OnDragDrop );
$.RegisterEventHandler( 'DragLeave', panel, OnDragLeave );
$.RegisterEventHandler( 'DragStart', panel, OnDragStart );
$.RegisterEventHandler( 'DragEnd', panel, OnDragEnd);

当然,这也不代表你一定需要定义这么多东西,如果你只需要响应DragStart和DragEnd,那么根据你的实际需要去写即可。

二、拖动回调函数

拖动具体需要哪些函数需要根据制作的实际需要去写。在dota2的可拖动的物品中,需要的函数包括:

OnDragStart:当拖动开始的时候->需要隐藏物品的提示,创建拖动的图像,然后给拖动开始的格子添加一个是从这里开始拖动的显示效果。
OnDragLeave:当拖动着panel的鼠标移动离开panel的时候(这个离开可能是初始格子也可以是中途某个经过的格子)->取消这个格子的高亮状态
DragEnter: 当拖动着的panel鼠标移动到panel上方的时候->高亮这个格子来表示你想要拖动东西到这个格子里;
OnDragDrop:当拖动着panel的鼠标移动到panel上方并松开的时候->你想要交换拖动的原始格子和目标格子中的物品(目标格子可能为空);
OnDragEnd:当拖动着panel的鼠标松开的时候-> 无论是拖动到另一个格子上还是拖动到地上了,都会调用这个回调,因此需要在OnDragDrop里面对拖动到另一个格子里的事件做出响应。

具体的回调函数如下:

function OnDragStart( panelId, dragCallbacks )
{
    // m_Item是在全局里保存的当前物品的id,如果不存在则不开始拖动
    if ( m_Item == -1 )
    {
        return true;
    }

    // 获取物品名称
    var itemName = Abilities.GetAbilityName( m_Item );

    // 隐藏正在显示的物品提示
    ItemHideTooltip();

    // 创建用来拖动的那个panel,也就是被拖动的图像,他并不是原来显示在那里的那个物品图标,而是新建的
    var displayPanel = $.CreatePanel( "DOTAItemImage", $.GetContextPanel(), "dragImage" );
    // 在创建的那个panel里面保存一些数据,在其他的回调中可以用
    displayPanel.itemname = itemName; // 物品名称
    displayPanel.contextEntityIndex = m_Item; // 物品序列号ID
    displayPanel.data().m_DragItem = m_Item; // 拖动的物品ID,其实这个data()并不是必要的,甚至这一步指令也不是必要的
    displayPanel.data().m_DragCompleted = false; // 拖动到底是拖动到另一个格子还是拖动到地上的标志位

    // 将用来显示的panel赋值给dragCallbacks.displayPanel就可以开始跟随鼠标移动了
    // 这两个offset定义了这个panel到底要在粘上去的位置产生多少偏移
    // 因为displayPanel的创建时在$.GetContextPanel,也就是inventory_item的xml里面创建的,因此也就不需要偏移了
    dragCallbacks.displayPanel = displayPanel;
    dragCallbacks.offsetX = 0; 
    dragCallbacks.offsetY = 0; 
    
    // 这个class会隐藏当前格子的物品图标,就给玩家感觉像是当前的格子里的物品被拖走了
    // 其实他还在原来的位置,只不过被隐藏了
    // 被拖动的是上面创建的那个displayPanel
    $.GetContextPanel().AddClass( "dragging_from" );
    return true;
}

function OnDragLeave( panelId, draggedPanel )
{
    // 获取正在拖动的物品的ID
    var draggedItem = draggedPanel.data().m_DragItem;
    // 如果正在拖动的就是当前的物品(也就是第一次离开原始的格子,那么不做响应)
    if ( draggedItem === null || draggedItem == m_Item )
        return false;

    // 如果是拖动经过了这个格子,因为OnDragEnter添加了这个class
    // 用来指示这个是当前的目标,离开的时候需要移除这个class
    $.GetContextPanel().RemoveClass( "potential_drop_target" );
    return true;
}


function OnDragEnter( a, draggedPanel )
{
    // 获取正在拖动的物品ID
    var draggedItem = draggedPanel.data().m_DragItem;

    // 如果正在拖动的就是当前的物品(也就是第一次离开原始的格子,那么不做响应)
    if ( draggedItem === null || draggedItem == m_Item )
        return true;

    // 拖动经过这个格子了,高亮他,用来指示玩家想要拖动物品到这个格子
    $.GetContextPanel().AddClass( "potential_drop_target" );
    return true;
}

// 这个是关键的回调,因为这个回调里有发送给服务器的交换物品的API
function OnDragDrop( panelId, draggedPanel )
{
    // 获取拖动的物品ID
    var draggedItem = draggedPanel.data().m_DragItem;
    
    // 如果正在拖动的就是当前的物品(也就是第一次离开原始的格子,那么不做响应)
    // 只需要标志一下m_DragCompleted给OnDragEnd使用一下,让他不要
    // 丢物品到地上
    if ( draggedItem === null )
        return true;
    draggedPanel.data().m_DragCompleted = true;
    if ( draggedItem == m_Item ) // 拿起来又放到同一个格子里面
        return true; // 返回,不做交换物品的操作

    // 告知服务器玩家想要交换物品
    var moveItemOrder =
    {
        OrderType: dotaunitorder_t.DOTA_UNIT_ORDER_MOVE_ITEM,
        TargetIndex: m_ItemSlot,
        AbilityIndex: draggedItem
    };
    Game.PrepareUnitOrders( moveItemOrder );

    return true;
}

// 拖动结束,这个里面有丢物品到地上的API
function OnDragEnd( panelId, draggedPanel )
{
    // 这个方法无论是拖动到另一个格子里,还是拖动到地上,都会响应
    // 如果调用这个之前没有先调用OnDragDrop的话,那么就告知
    // 服务器玩家想要丢东西到地上
    if ( !draggedPanel.data().m_DragCompleted )
    {
        Game.DropItemAtCursor( m_QueryUnit, m_Item );
    }

    // 移除被拖动的面板
    draggedPanel.DeleteAsync( 0 );

    // 清除拖动来源的格子,也就是调用这个的格子的dragging_from效果
    // UI里的交换物品图标,则会在服务器完成调换格子的操作之后
    // 通知客户端更新
    $.GetContextPanel().RemoveClass( "dragging_from" );
    
    return true;
}

三、其他的拖动需求分析

  1. 可拖动的窗口,例如背包窗口等,那么OnDragEnter、OnDragDrop和OnDragLeave是不需要的,应该只需要OnDragStart和OnDragEnd,此外,由于没有兄弟panel的问题,因此displayPanel可以使用窗口本体,这样你甚至连OnDragEnd都不需要写具体的内容。
  2. 卡牌游戏的卡牌,卡牌游戏的卡牌,也只需要OnDragStart和OnDragEnd,此外,卡牌在拖动过程中的响应,需要自己使用Schedule不断更新,比如更新卡牌的当前状态,指示当前卡牌目标位置等。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 本节介绍各种常见的浏览器事件。 鼠标事件 鼠标事件指与鼠标相关的事件,主要有以下一些。 click 事件,dblc...
    许先生__阅读 2,428评论 0 4
  • Windows 常用消息大全 表A-1 Windows消息分布 消息范围说 明 0 ~ WM_USER – 1系统...
    北风知我意阅读 2,040评论 0 0
  • 【产品定位】:个性化定制和推荐的短视频客户端。 【优势】 1、依托百度技术,提供更精确的内容推荐。可以通用百度账号...
    daidaiwang阅读 2,452评论 0 1
  • 故事从秋天开始 转眼又是一个秋 是最初的仓皇 是过程的迷惘 是点点滴滴 默然生长 站在十字路口 我穿着旧时的衣裳 ...
    雪小凝阅读 279评论 0 3