神刀安全网

基于iOS实现的dota英雄卡尔技能系统(上)

OK,先来说说故事的起源吧。记得刚到公司的时候,我的头儿让我看了一个调试框架叫 FLEX 。。。

头儿说:“公司项目目前比较稳定,咱们这边没什么事,所以你看看这个框架,根据咱们的项目情况仿写个调试工具”

当时我的表情是这样的
基于iOS实现的dota英雄卡尔技能系统(上)
09210Bb8-3.png

不过既然头儿发话了,硬着头皮看呗。然后我就运行程序,我还没看代码,就被他的功能给吓到了。由于本文主题并不是这个,感兴趣的童鞋可以点击这里下载查看具体功能。

奇怪的是头儿把这事忘了,我鼓捣了一两天这玩意儿,什么都没看懂,就再没有后续了。

前几天我突然想起来这个东西了,又去看了看这个框架,一时兴起,就有了这个demo

那么这框架和标题有什么联系?

当然有。这个框架有个功能就是有快捷键,在键盘上按键模拟器里的程序可以响应事件 (如果你早已知道这个功能那么可以狠狠地鄙视我一下~)


关键原理

  • 首先点击键盘按键会触发到UIapplication的一个方法
  • 其次需要把按键触发的方法替换为自己的方法

看到第二点大家都知道我们需要用到swizzle,先来看一张图

基于iOS实现的dota英雄卡尔技能系统(上)
IMG_20160911_210428.jpg

。。。相信各位在看到这张图之后,都会有种感觉–wtf!额,所以在这里也请朋友们给推荐一款设计流程图软件。

好的,来看一下这张图

  1. 首先我们知道UIApplication有个私有(实例)方法 handleKeyUIEvent:,啊不是。是FLEX的作者知道这么个方法。
  2. 然后我们通过runtime给UIApplication这个类动态地添加一个方法-也就是上面那个方法的替代者iss_handleKeyUIEvent:
  3. 最后交换这两个方法的IMP,也就是说在这些工作都做完后,再次进行键盘按键操作,sel1所寻找的就是iss_handleKeyUIEvent:的IMP了,在这个方法里可以做你想做的事儿~
  • 那么我们该如何获取到键盘输入的按键是什么呢?
    • 我们可以打开xcode的苹果官方文档去搜一下 UIPhysicalKeyboardEvent(UIPhysicalKeyboardEventUIPressesEventUIEvent) 我这里的文档版本太旧 所以还是去的官网查的
基于iOS实现的dota英雄卡尔技能系统(上)
uievent.png

  • 可以看到这个类有个_modifiedInput,这个属性代表的就是本次键盘的输入,然后在按键的时候UIApplication对象可以获取到一个UIPhysicalKeyboardEvent对象,于是就可以获取到本次的按键是哪个了。需要注意的是UIPhysicalKeyboardEvent是个私有类,具体如何调用这个方法详见demo

执行起来的大概过程是这样的。。。

基于iOS实现的dota英雄卡尔技能系统(上)
IMG_20160911_233702.jpg

细心的朋友应该发现上面sel2指向了一个block的imp,这和sel2指向一个方法的imp有什么不同呢?
我试了下。好像没有什么区别,只是写法上有些区别~ 如果各位看官有不同意见还请提出来

Tips.如果采用前者是可以从block的回调中获取到本次消息的接受者以及附带的参数

基于iOS实现的dota英雄卡尔技能系统(上)
method_exchange.png

更正
此处由于替换掉了UIApplication原有的方法,导致原有方法无法执行,所以为了避免引起未知的错误,需要在执行完我们的方法再去执行原有的方法。所以使用block的imp优势就体现出来了,我们可以在block的回调中获取message的receiver和param,然后加一句((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledKeyEventSelector, event); 就可以保证原方法的正常执行了


到此第一个坎就算迈过去了,接下来开始步入正题–元素的录入

让我们先来简单搭建一下UI吧

基于iOS实现的dota英雄卡尔技能系统(上)
Simulator Screen Shot 2016年9月13日 下午11.42.15.png

嗯。三个球 一个大招 再来两个技能 最后再来一张漂亮的背景图。完美~

元素的录入

  • 元素的召唤
    这里采用的是把快捷键和快捷键执行回调进行关系映射(Mapping)存入字典中。
元素球按键 召唤元素球
q 冰球
w 雷球
e 火球
r 元素合成

这些是一开始我们就要准备好的,也就是说最好是在类加载的时候就把几个快捷键加到内存中去,方便后续的调用。

基于iOS实现的dota英雄卡尔技能系统(上)
IMG_20160914_224617.jpg

  • 元素数组的维护
    玩过卡尔的都知道,卡尔有三个球!? 没错!就是三个球。在召唤元素的过程中 球的更新是这样的。
    --->>>>     -------  😯|😯😯😯|😯   从左到右看的话,最新的加入会导致最旧的被挤出     -------

那这就很简单了,一个数组搞定。在添加最新的时候把第一个给移除掉。✌️

  • 元素球的显示
    快捷键也有了,回调也有了,元素的显示还远吗?

录入元素这些方法我都是在一个SkillsManager里处理的,所以我需要在这里面快捷键的回调中去告诉控制器更新UI界面。这里我使用的通信方式是notification,不为别的,因为我用的少,在这里练练。。

~讲了这么多,好像还没上代码,来点!
SkillsManage.m

static NSMutableArray *elements;// 维护元素的数组,合成技能的时候需要在这里获取当前元素     elements = [NSMutableArray array];     NSNotificationCenter *notifiCenter = [NSNotificationCenter defaultCenter];     [self registSimulatorShortWithKey:InvokerElementIce action:^{         // 改变button图片为ice         [notifiCenter postNotificationName:InvokerElementNotification object:self userInfo:@{@"pic" : [UIImage imageNamed:@"ice"]}]; //发送通知,将本次快捷键的对应图片传到主控制器         if (elements.count < 3) {             [elements addObject:InvokerElementIce];         }else {             [elements removeObjectAtIndex:0];             [elements addObject:InvokerElementIce];         }     } description:@"ice"];

viewController.m

- (void)notification:(NSNotification *)notification {     static long num = 0;     _currentElementIndex = num%3;      //每切一次球,更新一个button的图片显示     UIButton *button = _elementBtnArray[_currentElementIndex];     _arrowView.frame = CGRectMake(0, 0, 60, 60);     _arrowView.center = CGPointMake(CGRectGetMidX(button.frame), CGRectGetMinY(button.frame) - 64);      [button setBackgroundImage:notification.userInfo[@"pic"] forState:UIControlStateSelected];     // 强制刷新button状态 图片才能更新     if (!button.selected) {         button.selected = YES;     }else {         button.selected = NO;         button.selected = YES;     }     num++; }

这些工作做完了之后先来看看效果吧。

基于iOS实现的dota英雄卡尔技能系统(上)
invokerball.gif

好像还不错的样子~


元素的合成

先来看一下元素-技能的对应

元素组合 技能
q q q 急速冷却(y)
q q w 幽灵漫步(v)
q w w 强袭飓风(x)
q q e 寒冰之墙(g)
q e e 熔炉精灵(f)
w w w 电磁脉冲(c)
w w e 灵动迅捷(z)
w e e 混沌陨石(d)
e e e 阳炎冲击(t)
q w e 超震声波(b)

前面我们获取到了一个当前元素的数组elements,我们怎么能知道这次获取到的元素合成什么技能呢? 查字典!

- (NSDictionary *)skillList {     return @{@[@"q", @"q", @"q"] : @"y",              @[@"q", @"q", @"w"] : @"v",              @[@"q", @"w", @"w"] : @"x",              @[@"q", @"w", @"e"] : @"b",              @[@"w", @"w", @"w"] : @"c",              @[@"w", @"w", @"e"] : @"z",              @[@"w", @"e", @"e"] : @"d",              @[@"e", @"e", @"e"] : @"t",              @[@"q", @"q", @"e"] : @"g",              @[@"q", @"e", @"e"] : @"f"}; }

在这里我的思路是遍历字典的allkeys,把elements与遍历所得的数组做比较,如果数组相同(内容相同,顺序可以不同),则根据数组对应的value可以获得本次合成的技能是什么。

  • 关于数组内容比较,代码不是很多,我就全贴过来,也请大家看看有那些不足的地方还可以改进。
+ (BOOL)isArray:(NSArray *)firstArray equalToArray:(NSArray *)secondArray {     NSMutableArray *array = [NSMutableArray arrayWithArray:firstArray];     NSMutableArray *secArray = [NSMutableArray arrayWithArray:secondArray];     NSInteger num = 0;      while (secArray.count != 0) {         for (NSInteger i = 0; i < secArray.count; i++) {             NSString *tempString1 = array[num];             NSString *tempString2 = secArray[i];             if ([tempString1 isEqualToString:tempString2]) {                 [array removeObjectAtIndex:num];                 [secArray removeObjectAtIndex:i];                  break;             }else if (i == secArray.count - 1) {                 return NO;             }                     }     }     if (array.count == 0) {         return YES;     }     return NO; }

刹车

由于思乡心切,暂时写到这里,中秋之后补上下篇(也可能是在此篇上补全),祝大家中秋愉快!

欢迎到 github:invokerSkillsSystem 下载demo,喜欢的点个star资瓷一下👌。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 基于iOS实现的dota英雄卡尔技能系统(上)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址