(3/18)重学Standford_iOS7开发_Objective-C_课程笔记
第三课:
本节课主要是游戏实现的demo,因此我将把课程中简单的几个编程技巧提取出来,重点介绍如何自己实现作业中的要求。
纸牌游戏实现:
①游戏的进行是模型的一部分(理解什么是模型:Model = What your application is (but not how it is displayed) )UI无关。
②编程技巧:创建一个新类时首先考虑公共部分(API),即别人如何使用这个类,再考虑其细节实现,以此来驱动整个设计。
③关于属性中使用NSInteger,NSUInteger,int,unsigned int只存在风格问题,只需要保持风格统一。
关于 NSInteger 与 NSUInteger 的官方定义:
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
④关于属性只读问题:公有API中可以设置属性为只读,实现代码中可以再次声明属性为可读写。属性声明时除非指定,否则默认为读写属性。
例如:
@interface example : NSObject @property (nonatomic,readonly) Objectype number; @end
@interface example() @property (nonatomic,readwrite) Objectype number; @end @implementation NUNetWork @end
⑤IBOutletConllection:多输出口,必须为strong,因为NSArray储存输出口,UI由视图指针指向,而NSArray必须指定为strong才能保持在堆中。
如:@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
IBOutletCollection(UIButton)类似于IBOutlet或IBAction,编译器会忽略。
NSArray中的UI顺序未知(不可视为拖入的顺序)
⑥作业
a.在模拟器上运行课程当前最后版本的Matchismo
b.添加一个button实现重新开始游戏功能(包括UI重置,牌堆重置,分数重置等)
c.使用UISwitch或者UISegmentedControl 实现两个card匹配与三个card匹配游戏模式之间的转换。(注意三个card匹配成功或失败的得分要比两个card更显著,在三card匹配中两个纸牌不会产生匹配结果)(可以考虑n张牌匹配)
d.游戏开始后,c中控制游戏的功能失效直到游戏结束或重新开始。
e.加入lable提示游戏进行状态(如:“Matched J♥ J♠ for 4 points.” 或“6♦ J♣ don’t match! 2 point penalty!” 或“8♦”表示只选择一张牌还没有进行匹配等)(不要违反MVC规则)
f.将纸牌数量由12扩展到30(40*60)
g.不要改变之前的代码,可以增加公有或私有API
作业解答:
最终实现效果如下图所示
(纸牌按钮字体大小设置为system 15,否则原有字体不能完整显示)
实现过程:
1、加入如下输出口:
@property (weak, nonatomic) IBOutlet UIButton *restartButton; @property (weak, nonatomic) IBOutlet UISegmentedControl *gameModelSelectSegmented; @property (weak, nonatomic) IBOutlet UILabel *gameModelLable; @property (weak, nonatomic) IBOutlet UITextField *matchModelTextFiled; @property (weak, nonatomic) IBOutlet UILabel *gameStateLable;
2、重新开始游戏功能实现
考虑到重新启动游戏后还未确定游戏模式,因此必须重写不包含game属性的初始化(game的setter会自动初始化game)
- (IBAction)touchRestartButton {
//恢复默认值
self.gameModelSelectSegmented.enabled = YES;
self.matchModelTextFiled.enabled = YES;
self.matchModelTextFiled.enabled = YES;
self.gameModelSelectSegmented.selectedSegmentIndex = ;
self.selfDefiningModel = ;
self.gameModelLable.text = [NSString stringWithFormat:@"game model:%d",_selfDefiningModel];
self.matchModelTextFiled.text = nil; self.game = nil;
[self updateUIWithNotCreateGame];
} - (void) updateUIWithNotCreateGame
{
for (UIButton *cardButton in self.cardButtons)
{
[cardButton setTitle:@"" forState:UIControlStateNormal];
[cardButton setBackgroundImage:[UIImage imageNamed:@"cardBack"] forState:UIControlStateNormal];
cardButton.enabled = YES;
} self.gameStateLable.text = @"State";
self.scoreLable.text = @"Score:0";
}
3、多种游戏模式及游戏状态输出的实现
//Viewcontroller加入用户自定义游戏模式
@property (nonatomic) NSUInteger selfDefiningModel;
选择器初始化(此处放在了viewDidLoad方法,有点超范围,其中选择器的target-action即为MVC中的view同controller通信的一种方法,selfDefiningModel为用户可自行设定的游戏模式,初始值为2)
还可以使用UISwitch,本文为了实现多纸牌匹配因此采用了UISegmentedControll,感兴趣的朋友可以试试UISwitch实现。
[self.gameModelSelectSegmented addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];//target-action _selfDefiningModel = ;//default model
选择器响应方法(action)
- (void) segmentAction:(UISegmentedControl *)Seg
{
if (self.gameModelSelectSegmented.selectedSegmentIndex == )//此时为自定义输入
{
[self assertSelfDefiningModel:self.matchModelTextFiled.text];//检测用户输入
}
else
{
self.selfDefiningModel = self.gameModelSelectSegmented.selectedSegmentIndex + ;//SegmengtdControll选择器选项栏从0开始计数
} self.gameModelLable.text = [NSString stringWithFormat:@"game model:%d",self.selfDefiningModel];
}
自定义输入检测,设置为数字键盘,只检测输入范围(由于用户输入的任意性,需要考虑到各种可能的输入情况,本文为了简便,采用了数字键盘,因此只需检测数字输入的合理性即可)
- (void) assertSelfDefiningModel:(NSString *)text
{
if ([self.matchModelTextFiled.text integerValue] < )
{
[[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"game model at least 2" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show];//匹配模式至少为2
self.matchModelTextFiled.text = @"";
self.gameModelSelectSegmented.selectedSegmentIndex = ;
}
else if ([self.matchModelTextFiled.text integerValue] > )
{
[[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"beyond card max number" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show];//匹配纸牌模式不能超过界面最大纸牌数量
self.matchModelTextFiled.text = @"";
self.gameModelSelectSegmented.selectedSegmentIndex = ;
}
else
{
self.selfDefiningModel = [self.matchModelTextFiled.text integerValue];//自定义输入正确时保存输入结果
}
}
UITextFiled委托(即MVC中View与Controller的另一种通讯方式,略超范围,不理解没有关系,暂不做要求),目的实现点击键盘的return按钮收起键盘
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
4、Model部分的实现
PlayingCard重写match:方法
重写前(只实现了两张牌的匹配):
- (int)match:(NSArray *)otherCards
{
int score = ; // two card match
if ([otherCards count] == )
{
PlayingCard *otherCard = [otherCards firstObject];
if ([self.suit isEqualToString:otherCard.suit])
{
score = ;
}
else if (self.rank == otherCard.rank)
{
score = ;
}
}
return score;
}
重写后(适用于多纸牌匹配): 此处我简单的实现了如下规则:任意两张牌含有相同的属性即认为此牌与数组中的牌匹配,读者可以尝试更复杂的规则,如所有的牌数字相等或者花色相等才能视为匹配等)
- (int)match:(NSArray *)otherCards
{
int score = ; // n card match ( at least two card have same element,we think they are matched )
for (PlayingCard *otherCard in otherCards)
{
if ([self.suit isEqualToString:otherCard.suit])
{
score += ;
}
else if (self.rank == otherCard.rank)
{
score += ;
}
} return score;
}
game公有API加入游戏模式及状态属性
@property (nonatomic) NSUInteger gameModel;// >=2
@property (nonatomic,readonly) NSString *gameState;
实现文件更改权限
@property (nonatomic,readwrite) NSString *gameState;
重写选择纸牌方法逻辑:
此次作业最难的部分,整个游戏的逻辑核心。首先保持两张纸牌匹配的框架不变,引入新的数组变量otherCards保存需要匹配的纸牌,先用for循环遍历检测纸牌状态,若符合要求则加入otherCards,遍历完毕再检测数组大小是否达到游戏模式要求(注意n张牌匹配数组大小应为n-1,想想为什么?:)),若不符合则返回,若符合则开始进行匹配。数组大小小于游戏模式要求时,此处应注意纸牌状态的保存位置与两张牌匹配时不同,下方代码注释有详细说明。匹配时的计分逻辑:在原有基础上乘以游戏模式数量,当匹配规则越难时匹配成功得分越高。并在匹配过程中保存游戏状态到gameState。
- (void) chooseCardAtIndex:(NSUInteger)index
{
Card *card = [self cardAtIndex:index];
if (!card.isMacthed)
{
if (card.isChosen)
{
card.chosen = NO;
}
else
{
// match against other chosen cards NSMutableArray *otherCards = [NSMutableArray arrayWithCapacity:self.gameModel];
for (Card *otherCard in self.cards)
{
if (otherCard.isChosen && !otherCard.isMacthed)
{
[otherCards addObject:otherCard];
}
} //不能放于for循环之前,否则会将本次被选择的牌加入cards,不能放于下面的if之后,否则当if成立时返回,没有将本次翻牌的cost记录,且不能翻牌
self.score -= COST_TO_CHOOSE * self.gameModel;
card.chosen = YES; if ([otherCards count] < self.gameModel - )
{
self.gameState = [NSString stringWithFormat:@"State:%@",card.contents];
return;
}
else
{
int matchScore = [card match:otherCards]; if (matchScore)
{
NSMutableString *state = [NSMutableString stringWithFormat:@"State:%@ matched",card.contents];
self.score += matchScore * MATCH_BOUNDS * self.gameModel;
for (Card *otherCard in otherCards)
{
[state appendFormat:@" %@",otherCard.contents];
otherCard.matched = YES;
}
[state appendFormat:@". Get %d score!",matchScore * MATCH_BOUNDS * self.gameModel];
card.matched = YES; self.gameState = state;
}
else
{
NSMutableString *state = [NSMutableString stringWithFormat:@"State:%@ with",card.contents];
self.score -= MISMATCH_PENALTY * self.gameModel;
for (Card *otherCard in otherCards)
{
[state appendFormat:@" %@",otherCard.contents];
otherCard.chosen = NO;
}
[state appendFormat:@" not matched! %d point penalty!",MISMATCH_PENALTY * self.gameModel]; self.gameState = state;
}
}
}
}
}
作业总结:虽然完成了作业的要求,但还有许多地方需要改进。如输入情况检测的30阈值为特定的数字,可以考虑改为[cardButtons count],游戏的计分逻辑不够完善,在游戏匹配模式较大的情况下(貌似到5张牌匹配就出现了:p)容易出现极端的得分情况,大家可以下载源代码玩玩试试。游戏状态的Lable字数过多时的显示问题。restart按钮的逻辑有没有更好的实现方法,本文为了防止restart中的updateUI方法在game置为nil后马上重新初始化nil(此时selfDefiningModel为初始值2)特意重写了一个更新UI的方法,有没有更轻便的方法(如更符合MVC一点)?这些问题都是抛砖引玉,我并没有细想,希望大家积极思考交流,如有不对欢迎指正:)
作业源码地址:https://github.com/NSLogMeng/Stanford_iOS7_Study_Machismo/commit/39819086ac1c0b7a38679b75307b1cf0a687a190(今后同一个项目每次作业我会把当次完成的commit链接发给大家)
------------------------------------------------我是后来补充的-----------------------------------------
刚刚在真机上玩发现个严重的问题。。。。数字键盘没有return键啊,数字键盘没有return键啊,数字键盘没有return键啊!!!模拟器直接在电脑的键盘上输入的啊,根本没有意识到_(:3 」∠)_
怒改之,添加了view响应事件,隐藏键盘,不过这部分源码就不贴了,只是简单地加了个方法,此部分已经严重超纲了。不过感兴趣大家可以看看,github已经更新了。
-----------------------------------------------------end-----------------------------------------------
课程视频地址:网易公开课:http://open.163.com/movie/2014/1/H/U/M9H7S9F1H_M9H7VNFHU.html
或者iTunes U搜索standford课程
(3/18)重学Standford_iOS7开发_Objective-C_课程笔记的更多相关文章
- (1/18)重学Standford_iOS7开发_iOS概述_课程笔记
写在前面:上次学习课程对iOS还是一知半解,由于缺乏实践,看公开课的视频有时不能很好地领会知识.带着问题去学习永远是最好的方法,接触一段时间iOS开发以后再来看斯坦福iOS公开课,又会有许多新的发现, ...
- (8/18)重学Standford_iOS7开发_协议、block、动画_课程笔记
第八课: 1.协议 另一种安全处理id类型的方式如:id <MyProtocol> obj a.声明 //协议一般放于.h文件中或者在类的.h文件中 @protocol Foo <X ...
- (7/18)重学Standford_iOS7开发_视图、绘制、手势识别_课程笔记
第七课: 1.View 一般来说,视图是一个构造块,代表屏幕上一块矩形区域,定义了一个坐标空间,并在其中绘制及添加触控事件等. ①视图的层级关系 一个视图只能有一个父视图,可以有多个子视图 - ( - ...
- (6/18)重学Standford_iOS7开发_控制器多态性、导航控制器、选项卡栏控制器_课程笔记
终于有时间跟新了,两周时间复(yu)习(xi)了5门考试累觉不爱...... ------------------------------------------------------------- ...
- (4/18)重学Standford_iOS7开发_框架和带属性字符串_课程笔记
第四课(干货课): (最近要复习考试,有点略跟不上节奏,这节课的内容还是比较重要的,仔细理解掌握对今后的编程会有很大影响) 本节课主要涉及到Foundation和UIKit框架,基本都是概念与API知 ...
- (9/18)重学Standford_iOS7开发_动画、自动布局_课程笔记
最近开始实习,没多少时间更新了=_= 第九课: 1.上节课demo:Dropit完整实现 https://github.com/NSLogMeng/Stanford_iOS7_Study/commit ...
- (5/18)重学Standford_iOS7开发_视图控制器生命周期_课程笔记
第五课: 1.UITextView @property (nonatomic, readonly) NSTextStorage *textStorage;//注意为只读属性,因此不能直接更改内容,NS ...
- (2/18)重学Standford_iOS7开发_Xcode_课程笔记
第二课: 1.惰性初始化 -(ObjectType *)example { f(!_example) example =[[ObjectType alloc] init]; return _examp ...
- 重学 Java 设计模式:实战外观模式「基于SpringBoot开发门面模式中间件,统一控制接口白名单场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你感受到的容易,一定有人为你承担不容易 这句话更像是描述生活的,许许多多的磕磕绊绊总 ...
随机推荐
- 学习PHP爬虫--《Webbots、Spiders和Screen Scrapers:技术解析与应用实践(原书第2版)》
<Webbots.Spiders和Screen Scrapers:技术解析与应用实践(原书第2版)> 译者序 前言 第一部分 基础概念和技术 第1章 本书主要内容3 1.1 发现互联网的真 ...
- Mysql 与 php动态网站开发 入门教程
这个系列的教程由表单开始写,因为表单可以把数据库和web 之间的交互表现得很明显.提交表单 ,数据库记录注册信息. 本教程属于基础教程.大神请略过. 对于php和mysql之间的稳固性很 ...
- WIFI破解总结
寒假回家了,由于家里没有宽带,而周围又有好多WIFI所以尝试了破解人家的WIFI,嘻嘻. 1.准备u盘一个,格式化 2.用制作工具,将cdlinux系统的镜像安装进u盘 3.用u盘启动电脑,进入cdl ...
- IOS 多线程之GCD
参考:http://www.cnblogs.com/wendingding/p/3806821.html <<Objective-C基础教程>> 第二版 一 简介 GCD 全称 ...
- after I see Little Dorrit
也许是我太追名逐利,所以我不肯承认自己花费了大把的时间看电影,通过写博客好像自己从中感悟到了什么,好像看电影也是一种学习的方式. 也许是我平静自内心的方式,我太忙于玩或者学习,甚至没有机会非常沉静 一 ...
- Android Camera 预览图像被拉伸变形的解决方法【转】
问题描述: 预览图像被拉伸变形 问题原因: 由于预览图像大小跟SurfaceView 大小不一致引起 解决方法: 获取系统支持的所有预览尺寸[getSupportedPictureSizes],然后再 ...
- DM8168 环境搭建(2) ------ 虐心之旅
续上 ... ... ... (5)安装minicom minicom类似于windows下的超级终端,用于与串口设备通信 参考命令:sudo apt-get install minicom ...
- leetcode第六题 ZigZag Conversion (java)
ZigZag Conversion The string "PAYPALISHIRING" is written in a zigzag pattern on a given nu ...
- Jquery效果代码--(二)
//jQuery 效果- 隐藏和显示.通过 jQuery,您可以使用 hide() 和 show() 方法来隐藏和显示 HTML 元素: //掩藏效果演示: $(document).ready(fun ...
- SPRING IN ACTION 第4版笔记-第三章ADVANCING WIRING-005-Bean的作用域@Scope、ProxyMode
一. Spring的bean默认是单例的 But sometimes you may find yourself working with a mutable class that does main ...