(转发)Android之有效幸免按钮数1四回重复点击的章程(非看不可篇)

为了防患测试妹子也许用户频仍点击某些按钮,导致程序在短期内开始展览频仍多少交由or数据处理,那到时候就比较坑了~

 

那么什么样有效制止这种状态的爆发吧? 

UE4浓厚学习QQ群: 456247757


引言

上文谈到Actor和Component的关系,UE利用Actor的定义组成一片游戏对象森林,并采取Component组装扩张Actor的力量,让世界里有所了五花八门的Actor们,拥有了自由发挥3D世界的力量。
这就是说,那几个Actor们,到底是怎么协会起来的吧?

既然涉及了世道,我们的直觉反应是应用一个”World”对象来包容全体的Actor们。然而当游戏的虚构世界老大伟大时,那种办法就赤贫如洗了。首先,如今虽说PC的本性稳步强劲,可是依旧内部存款和储蓄器也限制了不能够弹指间加载进具有的游戏财富;其次,因为玩家的移动和可知范围有限,为了最优品质,把固然是很远的跟玩家非亲非故的对象也考虑进去也威名赫赫是不明智的。所以大家须要一种更细粒度的概念来划分世界。
不等的玩耍引擎们,看待那几个进度的角度和见解也不一致等。Cocos2dx会认为游戏世界是由Scene组成的,Scene再由七个个Layer层叠表现,然后再有贰个Director来监制整个游戏。Unity觉得世界也是由Scene组成的,然后2个Application来饰演上帝来LoadLevel,后来换来了SceneManager。别的的,有的会称为关卡(Level)或地图(map)等等。而UE中把那种拆分叫做关卡(Level),由一个或七个Level组成叁个World。
毫不认为那种分割好像很自由,只是个名字差别而已。实际上一个娱乐引擎的“世界观”关系到了一整串后续的剧情组织,玩家的治本,世界的变化,变换和损毁。游戏引擎内部的能源的加载释放也一再都以和那种分割(Level)绑定在协同的。

 

小编的想法是,判断用户点击按钮间隔时间,假诺间隔时间太短,则觉得是不行操作,不然举行相关事情处理

Level

在UE的社会风气中,我们事先曾经有了空气(C++),土壤(UObject),物件(Actor)。近来天UE又施展神力创造了一片片陆地(Level),在那片大陆上(.map文件),Actor们齐刷刷,各样地形平地而起,植被茂盛,天空雾云缭绕,圣光普照,那也是玩家们降生起先美貌冒险的地点。
图片 1
能够从ULevel的前缀U看出来Level(大陆)也确实是三番五次于UObject(土壤)的。那既然同属于Object下边包车型大巴各Actor们都享有了肯定的智能能力(帮衬蓝图脚本),Level自然也得显示出满世界的定性,所以私下认可带了贰个土地公(ALevelScriptActor),允许大家在关卡里编写脚本,能够对本关卡里的具备Actor通过名字呼之则来,关卡蓝图实际上就表示着该片大陆上的运维规则。
在Level已经有了首长之后,一起初大家都挺顺心,但日益的就发现,好像各样Level必要的功用相近都大约,都以修改一下光照,物理等片段性能。所以为了有利于起见,UE便给每三个Level也都暗许配了一个书记官(Info),他每个记录着本Level的各类条条框框属性,在UE须要的时候便负责相告。更首要的是,在Level必要有别的管理职员一起帮忙的时候,他也记录着“游戏情势”的名字来让UE可以选派。
前方大家说过,有一部分Actor是不“彰显”的(没有SceneComponent),是不能够“摆放”到Level里的,不过它依然能够在关卡里出力。个中三个家门连串正是AInfo和其之类。前日大家只简单介绍一下跟Level间接有关的壹个人书记官:AWorldSettings。
图片 2
实际上固然名字叫做WorldSettings,但实际上只是跟Level相关,作者猜恐怕是在上古时期,当时全世界唯有一块大陆,人们就觉着近年来的新大陆正是一切世界,所以给那块陆地的安装就起名为WorldSettings,后来等技能升高了,发现必须有其余大陆了,这一个名字一度用得太多反而不好改了,就只可以遗留下来了。当然也有或许是因为当Level被添加进World后,那几个Level的Settings假设是主PersisitentLevel,那它就会被视作整个World的WorldSettings。
瞩目,Actors里也保留着AWorldSettings和ALevelScriptActor的指针,所以Actors实际上确实是保存了具有Actor。

考虑:为何AWorldSettings要放进在Actors[0]的位置?而ALevelScriptActor却不用?

 

 1 void ULevel::SortActorList()
 2 {
 3     if (Actors.Num() == 0)
 4     {
 5         // No need to sort an empty list
 6         return;
 7     }
 8 
 9     TArray<AActor*> NewActors;
10     TArray<AActor*> NewNetActors;
11     NewActors.Reserve(Actors.Num());
12     NewNetActors.Reserve(Actors.Num());
13 
14     check(WorldSettings);
15 
16     // The WorldSettings tries to stay at index 0
17     NewActors.Add(WorldSettings);
18 
19     // Add non-net actors to the NewActors immediately, cache off the net actors to Append after
20     for (AActor* Actor : Actors)
21     {
22         if (Actor != nullptr && Actor != WorldSettings && !Actor->IsPendingKill())
23         {
24             if (IsNetActor(Actor))
25             {
26                 NewNetActors.Add(Actor);
27             }
28             else
29             {
30                 NewActors.Add(Actor);
31             }
32         }
33 
34     }
35     iFirstNetRelevantActor = NewActors.Num();
36 
37     NewActors.Append(MoveTemp(NewNetActors));
38 
39     // Replace with sorted list.
40     Actors = MoveTemp(NewActors);
41 
42     // Add all network actors to the owning world
43     if ( OwningWorld != nullptr )
44     {
45         // Don't use sorted optimization outside of gameplay so we can safely shuffle around actors e.g. in the Editor
46         // without there being a chance to break code using dynamic/ net relevant actor iterators.
47         if (!OwningWorld->IsGameWorld())
48         {
49             iFirstNetRelevantActor = 0;
50         }
51 
52         for ( int32 i = iFirstNetRelevantActor; i < Actors.Num(); i++ )
53         {
54             if ( Actors[ i ] != nullptr )
55             {
56                 OwningWorld->AddNetworkActor( Actors[ i ] );
57             }
58         }
59     }
60 }

 

实际上通过这一段代码可见,Actors们的排序依照是把那么些“非互连网”的Actor放在日前,而把“互联网可复制”的Actor们放在后边,然后加三个开端索引标记iFirstNetRelevantActor,也正是为互联网Actor划分了几个缓存,从而加快了互联网复制时的检查和测试速度。AWorldSettings因为都以静态的数目提供者,在玩耍运维进程中也不会转移,不须要网络复制,所以也就足以一贯位于前列,而一旦再加个规则,平昔位居第②个的话,也能同时把AWorldSettings和别的的前列Actor们再次区分开,在急需的时候也能加快判断。ALevelScriptActor因为是代表关卡蓝图,是同意指点“复制”变量函数的,所以也有恐怕被排序到后列。

寻思:既然ALevelScriptActor也连续于AActor,为啥关卡蓝图不设计能添加Component?
考察到,平日大家在创设Actor的时候,大家蓝图界面是足以创制Component的。
那为什么在关卡蓝图里,却无法这么做(没有提供该界面功用)?
自己固然在图里标出了Level中有着ModelComponents,但那其实只是针对BSP应用的二个子集。通过源码发现,其实UE自身也是在C++里往ALevelScriptActor添加UInputComponent来贯彻关卡蓝图能够响应事件。

 

 1 void ALevelScriptActor::PreInitializeComponents()
 2 {
 3     if (UInputDelegateBinding::SupportsInputDelegate(GetClass()))
 4     {
 5         // create an InputComponent object so that the level script actor can bind key events
 6         InputComponent = NewObject<UInputComponent>(this);
 7         InputComponent->RegisterComponent();
 8 
 9         UInputDelegateBinding::BindInputDelegates(GetClass(), InputComponent);
10     }
11     Super::PreInitializeComponents();
12 }

 

骨子里既然ALevelScriptActor是个Actor,那表示大家自然能够为它足够组件,实际上也真正能够如此做。比如您能够在关卡蓝图里那样干:
图片 3
而一旦您实在意识到关卡蓝图本人正是3个看不见的Actor,你就足以在上边用Actor的各样操作:
图片 4
在关卡蓝图里的self其实也是个Actor!即便一般这么干也没怎么毛用。
那么杰出考虑,为何UE要给您如此一个关卡蓝图界面呢?
图片 5
在此,作者也只可以进展一番估计,ALevelScriptActor作为三个特化的Actor,却把Components列表界面给隐藏了,表达UE其实是不愿意大家去复杂化关卡构成的。
假使说UE开放了关卡Component,那么我们在创立组件时就肯定要考虑3个难题:哪些是ActorComponent,哪些是LevelComponent,再怎么ALevelScriptActor本质是个Actor,但Level的概念还是要崛起,ALevelScriptActor的Actor本质是要藏匿的。所以用户就会多一些心智负担,恐怕混淆。而只要像那样不开放,大家的思路就都转载先创制个Actor,然后再往之上添加component,思路会比较统一清晰。
再之,从娱乐逻辑的团体上来说,Level其实更应该显示为三个Actor的容器。UE其实也是不鼓励在Level里编写太复杂的逻辑的。所以才跟着会有了后来的GameMode,Controller那3个真正的逻辑控制类(后续会再细研讨)。
之所以游戏引擎也并不是说最大化的展露一切作用给您正是最棒的,有时候采纳太多了反而不难出错。在那或多或少上,笔者觉着UE很好的涵养了自制,为大家提供了1个优质的不可磨灭的科学出错的框架,同时也对高阶用户保留了灵活性。

 

第叁将那块提取为工具类(方便接下去的调用),将来就起名为:ButtonUtils

World

到头来,到了把大陆们(Level)拼装起来的时候了。能够用SubLevel的点子:
图片 6
也支撑WorldComposition的章程自行把项目里的拥有Level都结合起来,并设置摆放地点:
图片 7
切切实实摆放的操作和技能并不是本文的关键。简单本质来说,正是二个World里有两个Level,这一个Level在什么岗位,是在一起来就加载进来,依旧Streaming运维时加载。
UE里每一种World支持3个PersisitentLevel和三个别的Level:
图片 8
Persisitent的意思是一起初就加载进World,Streaming是继续动态加载的情致。Levels里保存有全体的眼下早就加载的Level,StreamingLevels保存整个World的Levels配置列表。PersisitentLevel和CurrentLevel只是个高速引用。在编辑器里编辑的时候,CurrentLevel能够本着任何Level,但运维时CurrentLevel只好是指向PersisitentLevel。

思考:为什么要有主PersisitentLevel?
首先,World至少得有叁个Level,就好像您也得先落地在一块大陆上才足以继承谈起去探索其余新陆地。所以那块玩家出生的新大陆正是主Level了。当然了,因为大家也能够而且安顿其余Level一伊始就加载进来,其实跟PersisitentLevel是基本上等价的,但再考虑到另一题材:Levels拼接进World一起现在,各自有分别的worldsetting,这全数World的配备相应以什么人的为主?

 

AWorldSettings* UWorld::GetWorldSettings( bool bCheckStreamingPesistent, bool bChecked ) const
{
    checkSlow(IsInGameThread());
    AWorldSettings* WorldSettings = nullptr;
    if (PersistentLevel)
    {
        WorldSettings = PersistentLevel->GetWorldSettings(bChecked);

        if( bCheckStreamingPesistent )
        {
            if( StreamingLevels.Num() > 0 &&
                StreamingLevels[0] &&
                StreamingLevels[0]->IsA<ULevelStreamingPersistent>()) 
            {
                ULevel* Level = StreamingLevels[0]->GetLoadedLevel();
                if (Level != nullptr)
                {
                    WorldSettings = Level->GetWorldSettings();
                }
            }
        }
    }
    return WorldSettings;
}

 

能够看来,World的Settings也是以PersisitentLevel为主的,但这也并不以为着别的Level的Settings就全盘没有成效了,本篇也无能为力一一列出富有配置选项来验证,一言以蔽之,就是内需在任何世界范围内起成效的布署选项(比如V汉兰达的WorldToMeters,KillZ,WorldGravity其余超过半数都以)就是亟需从主PersisitentLevel的配备中领到。而一些陈设选项可以在单独Level中起效能的,比如在编辑Level时的普照品质配置就是三个个Level单独的,最近那种布局很少,但大概以往也会大增。在此地只是表圣元个为主其余为辅的Level配置种类。

合计:Levels们的Actors和World有向来关乎吗?
当别的Level被添加进当前World从此,大家能一向在WorldOutliner里看看此外Level的Actor们。
图片 9
但这并不意味着World直接引用了Level里的Actor们。TActorIteratorBase(World的Actor迭代器)内部的兑现也只是在遍历Levels来博取全体Actor。当然World为了更迅捷的操作Controllers和Pawn也都保存了引用。但Levels却共享着World的2个PhysicsScene,那也象征Levels里的Actors的大体实体其实都以在World里的,那能够驾驭,毕竟物理的撞击之类的自然如果大局的了。再说到导航,World在拼接Level的时候,也是会同时把五个Level的导航网格给“拼接”起来的。当可是今还不是尖锐细节的时候,以后只要从大局上知道World-Level-Actor的涉及。

切磋:为何要在Level里保存Actors,而不是把拥有Map的Actors配置都生成在World3个总Actors里?
那肯定也是一种达成格局,好处是把全副World看成三个总体,全体的actors都从属于world,那样就不存在Level边界,能够更完整的处理Actors的功能范围和判断难点,达成上也少了拼接导航等手续。当然坏处也是歪曲了Level边界,那样在加载进1个Level之后,之后再动态释放,就要求再重新再从完整中抽离出部分来刑释,这些筛选进度也会产生相比大的损耗。试着去领略UE的度量,应该是尽可能的把损耗平均分摊(那里是把Level加载释放的消耗尽量收缩),才不会时有发生相比较大的帧率波动,让玩家感觉到卡帧。

 

public class ButtonUtils {
  private static long lastClickTime = 0;
  private static long DIFF = 1000;
  private static int lastButtonId = -1;

  /**
   * 判断两次点击的间隔,如果小于1000,则认为是多次无效点击
   *
   * @return
   */
  public static boolean isFastDoubleClick() {
    return isFastDoubleClick(-1, DIFF);
  }

  /**
   * 判断两次点击的间隔,如果小于1000,则认为是多次无效点击
   *
   * @return
   */
  public static boolean isFastDoubleClick(int buttonId) {
    return isFastDoubleClick(buttonId, DIFF);
  }

  /**
   * 判断两次点击的间隔,如果小于diff,则认为是多次无效点击
   *
   * @param diff
   * @return
   */
  public static boolean isFastDoubleClick(int buttonId, long diff) {
    long time = System.currentTimeMillis();
    long timeD = time - lastClickTime;
    if (lastButtonId == buttonId && lastClickTime > 0 && timeD < diff) {
      Log.v("isFastDoubleClick", "短时间内按钮多次触发");
      return true;
    }
    lastClickTime = time;
    lastButtonId = buttonId;
    return false;
  }  

}

总结

Level作为Actor的容器,同时也瓜分了World,一方面援助了Level的动态加载,另一方面也同意了团组织的实时合营,我们能够而且并行编辑不一致的Level。一般而言,多少个玩家从娱乐初阶到停止,UE会创制四个GameWorld给玩家并一贯留存。玩家切换场景或关卡,也只是在那一个World中加载释放分裂的Level。既然Level拥有了主管(LevelScriptActor),玩家能够编写制定特定关卡的逻辑,那么大家能还是无法对World那种层次编写逻辑吗?答案是自然的,不过本文篇幅有限,敬请期待下篇。

下篇:GamePlayer架构(三)WorldContext,GameInstance,Engine

 

大家经过判断俩次点击时间间隔去判断当前点击操作是或不是为可行操作。那么什么样在采纳中调用呢?继续往下看。。。

UE4深刻学习QQ群: 456247757


个人原创,未经授权,谢绝转发,不然将钻探法律义务!

 

gv_isf.setOnItemClickListener(new OnItemClickListener() {

      @Override
      public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
          long arg3) {
        if (!ButtonUtils.isFastDoubleClick(R.id.gv_integralstore)) {
          //写你相关操作即可
        }

      }
    });

!ButtonUtils.isFastDoubleClick(R.id.gv_integralstore):那块是第叁。笔者的想法正是在单击事件中进行判定,看看当前的点击事件是不是为可行点击事件

好了,贰个简练又实用的预防按钮多次重复点击的工具类就解决了。。。

以上这篇Android之有效制止按钮数十次重复点击的法子(必须要看篇)正是小编分享给大家的全体内容了,希望能给我们八个参阅,也指望我们多多扶助脚本之家。

 

自家要评论热切求助加入Q群

 

 

迎接评论留言!

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图