付费节点推荐
免费节点
节点使用教程
OK,先来说说故事的起源吧。记得刚到公司的时候,我的头儿让我看了一个调试框架叫 FLEX 。。。
头儿说:“公司项目目前比较稳定,咱们这边没什么事,所以你看看这个框架,根据咱们的项目情况仿写个调试工具”
当时我的表情是这样的
不过既然头儿发话了,硬着头皮看呗。然后我就运行程序,我还没看代码,就被他的功能给吓到了。由于本文主题并不是这个,感兴趣的童鞋可以点击这里下载查看具体功能。
奇怪的是头儿把这事忘了,我鼓捣了一两天这玩意儿,什么都没看懂,就再没有后续了。
前几天我突然想起来这个东西了,又去看了看这个框架,一时兴起,就有了这个demo。
那么这框架和标题有什么联系?
当然有。这个框架有个功能就是有快捷键,在键盘上按键模拟器里的程序可以响应事件 (如果你早已知道这个功能那么可以狠狠地鄙视我一下~)
关键原理
- 首先点击键盘按键会触发到UIapplication的一个方法
- 其次需要把按键触发的方法替换为自己的方法
看到第二点大家都知道我们需要用到swizzle,先来看一张图
。。。相信各位在看到这张图之后,都会有种感觉--wtf!额,所以在这里也请朋友们给推荐一款设计流程图软件。
好的,来看一下这张图
- 首先我们知道UIApplication有个私有(实例)方法
handleKeyUIEvent:
,啊不是。是FLEX的作者知道这么个方法。 - 然后我们通过runtime给UIApplication这个类动态地添加一个方法-也就是上面那个方法的替代者
iss_handleKeyUIEvent:
- 最后交换这两个方法的IMP,也就是说在这些工作都做完后,再次进行键盘按键操作,sel1所寻找的就是
iss_handleKeyUIEvent:
的IMP了,在这个方法里可以做你想做的事儿~
- 那么我们该如何获取到键盘输入的按键是什么呢?
- 我们可以打开xcode的苹果官方文档去搜一下 UIPhysicalKeyboardEvent(
UIPhysicalKeyboardEvent
:UIPressesEvent
:UIEvent
) 我这里的文档版本太旧 所以还是去的官网查的
- 我们可以打开xcode的苹果官方文档去搜一下 UIPhysicalKeyboardEvent(
- 可以看到这个类有个_modifiedInput,这个属性代表的就是本次键盘的输入,然后在按键的时候UIApplication对象可以获取到一个UIPhysicalKeyboardEvent对象,于是就可以获取到本次的按键是哪个了。需要注意的是UIPhysicalKeyboardEvent是个私有类,具体如何调用这个方法详见demo
执行起来的大概过程是这样的。。。
细心的朋友应该发现上面sel2指向了一个block的imp,这和sel2指向一个方法的imp有什么不同呢?
我试了下。好像没有什么区别,只是写法上有些区别~ 如果各位看官有不同意见还请提出来。
Tips.如果采用前者是可以从block的回调中获取到本次消息的接受者以及附带的参数
更正
此处由于替换掉了UIApplication原有的方法,导致原有方法无法执行,所以为了避免引起未知的错误,需要在执行完我们的方法再去执行原有的方法。所以使用block的imp优势就体现出来了,我们可以在block的回调中获取message的receiver和param,然后加一句((void(*)(id, SEL, id))objc_msgSend)(slf, swizzledKeyEventSelector, event);
就可以保证原方法的正常执行了
到此第一个坎就算迈过去了,接下来开始步入正题--元素的录入
让我们先来简单搭建一下UI吧
嗯。三个球 一个大招 再来两个技能 最后再来一张漂亮的背景图。完美~
元素的录入
- 元素的召唤
这里采用的是把快捷键和快捷键执行回调进行关系映射(Mapping)存入字典中。
元素球按键 | 召唤元素球 |
---|---|
q | 冰球 |
w | 雷球 |
e | 火球 |
r | 元素合成 |
这些是一开始我们就要准备好的,也就是说最好是在类加载的时候就把几个快捷键加到内存中去,方便后续的调用。
- 元素数组的维护
玩过卡尔的都知道,卡尔有三个球!? 没错!就是三个球。在召唤元素的过程中 球的更新是这样的。
--->>>>
-------
😯|😯😯😯|😯 从左到右看的话,最新的加入会导致最旧的被挤出
-------
那这就很简单了,一个数组搞定。在添加最新的时候把第一个给移除掉。✌️
- 元素球的显示
快捷键也有了,回调也有了,元素的显示还远吗?
录入元素这些方法我都是在一个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++;
}
这些工作做完了之后先来看看效果吧。
好像还不错的样子~
元素的合成
先来看一下元素-技能的对应
元素组合 | 技能 |
---|---|
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资瓷一下👌。
未经允许不得转载:Bcoder资源网 » 基于iOS实现的dota英雄卡尔技能系统(上)
评论前必须登录!
登陆 注册