(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 的官方定义:

1 #if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
2 typedef long NSInteger;
3 typedef unsigned long NSUInteger;
4 #else
5 typedef int NSInteger;
6 typedef unsigned int NSUInteger;
7 #endif 

④关于属性只读问题:公有API中可以设置属性为只读,实现代码中可以再次声明属性为可读写。属性声明时除非指定,否则默认为读写属性。

  例如:

1 @interface example : NSObject
2
3 @property (nonatomic,readonly) Objectype  number;
4
5 @end
 1 @interface example()
 2
 3 @property (nonatomic,readwrite) Objectype number;
 4
 5 @end
 6
 7
 8 @implementation NUNetWork
 9
10 @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、加入如下输出口:

1 @property (weak, nonatomic) IBOutlet UIButton *restartButton;
2
3 @property (weak, nonatomic) IBOutlet UISegmentedControl *gameModelSelectSegmented;
4
5 @property (weak, nonatomic) IBOutlet UILabel *gameModelLable;
6
7 @property (weak, nonatomic) IBOutlet UITextField *matchModelTextFiled;
8
9 @property (weak, nonatomic) IBOutlet UILabel *gameStateLable;

    2、重新开始游戏功能实现

      考虑到重新启动游戏后还未确定游戏模式,因此必须重写不包含game属性的初始化(game的setter会自动初始化game)

 1 - (IBAction)touchRestartButton
 2
 3 {
 4     //恢复默认值
 5     self.gameModelSelectSegmented.enabled = YES;
 6     self.matchModelTextFiled.enabled = YES;
 7     self.matchModelTextFiled.enabled = YES;
 8     self.gameModelSelectSegmented.selectedSegmentIndex = 0;
 9     self.selfDefiningModel = 2;
10     self.gameModelLable.text = [NSString stringWithFormat:@"game model:%d",_selfDefiningModel];
11     self.matchModelTextFiled.text = nil;
12
13     self.game = nil;
14     [self updateUIWithNotCreateGame];
15 }
16
17 - (void) updateUIWithNotCreateGame
18 {
19     for (UIButton *cardButton in self.cardButtons)
20     {
21         [cardButton setTitle:@"" forState:UIControlStateNormal];
22         [cardButton setBackgroundImage:[UIImage imageNamed:@"cardBack"] forState:UIControlStateNormal];
23         cardButton.enabled = YES;
24     }
25
26     self.gameStateLable.text = @"State";
27     self.scoreLable.text = @"Score:0";
28 }

    3、多种游戏模式及游戏状态输出的实现

      //Viewcontroller加入用户自定义游戏模式

      @property (nonatomic) NSUInteger selfDefiningModel;

      选择器初始化(此处放在了viewDidLoad方法,有点超范围,其中选择器的target-action即为MVC中的view同controller通信的一种方法,selfDefiningModel为用户可自行设定的游戏模式,初始值为2)

      还可以使用UISwitch,本文为了实现多纸牌匹配因此采用了UISegmentedControll,感兴趣的朋友可以试试UISwitch实现。

1 [self.gameModelSelectSegmented addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];//target-action
2
3 _selfDefiningModel = 2;//default model 

      选择器响应方法(action)

 1 - (void) segmentAction:(UISegmentedControl *)Seg
 2 {
 3     if  (self.gameModelSelectSegmented.selectedSegmentIndex == 2)//此时为自定义输入
 4     {
 5         [self assertSelfDefiningModel:self.matchModelTextFiled.text];//检测用户输入
 6     }
 7     else
 8     {
 9         self.selfDefiningModel = self.gameModelSelectSegmented.selectedSegmentIndex + 2;//SegmengtdControll选择器选项栏从0开始计数
10     }
11
12     self.gameModelLable.text = [NSString stringWithFormat:@"game model:%d",self.selfDefiningModel];
13 } 

      自定义输入检测,设置为数字键盘,只检测输入范围(由于用户输入的任意性,需要考虑到各种可能的输入情况,本文为了简便,采用了数字键盘,因此只需检测数字输入的合理性即可)

 1 - (void) assertSelfDefiningModel:(NSString *)text
 2 {
 3     if ([self.matchModelTextFiled.text integerValue] < 2)
 4     {
 5         [[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"game model at least 2" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show];//匹配模式至少为2
 6         self.matchModelTextFiled.text = @"";
 7         self.gameModelSelectSegmented.selectedSegmentIndex = 0;
 8     }
 9     else if ([self.matchModelTextFiled.text integerValue] > 30)
10     {
11         [[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"beyond card max number" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show];//匹配纸牌模式不能超过界面最大纸牌数量
12         self.matchModelTextFiled.text = @"";
13         self.gameModelSelectSegmented.selectedSegmentIndex = 0;
14     }
15     else
16     {
17         self.selfDefiningModel = [self.matchModelTextFiled.text integerValue];//自定义输入正确时保存输入结果
18     }
19 }

      UITextFiled委托(即MVC中View与Controller的另一种通讯方式,略超范围,不理解没有关系,暂不做要求),目的实现点击键盘的return按钮收起键盘

1 - (BOOL) textFieldShouldReturn:(UITextField *)textField
2 {
3     [textField resignFirstResponder];
4     return YES;
5 }

    4、Model部分的实现

      PlayingCard重写match:方法

        重写前(只实现了两张牌的匹配):

 1 - (int)match:(NSArray *)otherCards
 2 {
 3     int score = 0;
 4
 5     // two card match
 6     if ([otherCards count] == 1)
 7     {
 8         PlayingCard *otherCard = [otherCards firstObject];
 9         if ([self.suit isEqualToString:otherCard.suit])
10         {
11             score = 1;
12         }
13         else if (self.rank == otherCard.rank)
14         {
15             score = 4;
16         }
17     }
18     return score;
19 }

      重写后(适用于多纸牌匹配): 此处我简单的实现了如下规则:任意两张牌含有相同的属性即认为此牌与数组中的牌匹配,读者可以尝试更复杂的规则,如所有的牌数字相等或者花色相等才能视为匹配等)

 1 - (int)match:(NSArray *)otherCards
 2 {
 3     int score = 0;
 4
 5     // n card match ( at least two card have same element,we think they are matched )
 6     for (PlayingCard *otherCard in otherCards)
 7     {
 8         if ([self.suit isEqualToString:otherCard.suit])
 9         {
10             score += 1;
11         }
12         else if (self.rank == otherCard.rank)
13         {
14             score += 4;
15         }
16     }
17
18     return score;
19 }

      game公有API加入游戏模式及状态属性

        @property (nonatomic) NSUInteger gameModel;// >=2

        @property (nonatomic,readonly) NSString *gameState;

      实现文件更改权限

        @property (nonatomic,readwrite) NSString *gameState;

      重写选择纸牌方法逻辑:

        此次作业最难的部分,整个游戏的逻辑核心。首先保持两张纸牌匹配的框架不变,引入新的数组变量otherCards保存需要匹配的纸牌,先用for循环遍历检测纸牌状态,若符合要求则加入otherCards,遍历完毕再检测数组大小是否达到游戏模式要求(注意n张牌匹配数组大小应为n-1,想想为什么?:)),若不符合则返回,若符合则开始进行匹配。数组大小小于游戏模式要求时,此处应注意纸牌状态的保存位置与两张牌匹配时不同,下方代码注释有详细说明。匹配时的计分逻辑:在原有基础上乘以游戏模式数量,当匹配规则越难时匹配成功得分越高。并在匹配过程中保存游戏状态到gameState。

 1 - (void) chooseCardAtIndex:(NSUInteger)index
 2 {
 3     Card *card = [self cardAtIndex:index];
 4     if (!card.isMacthed)
 5     {
 6         if (card.isChosen)
 7         {
 8             card.chosen = NO;
 9         }
10         else
11         {
12             // match against other chosen cards
13
14             NSMutableArray *otherCards = [NSMutableArray arrayWithCapacity:self.gameModel];
15             for (Card *otherCard in self.cards)
16             {
17                 if (otherCard.isChosen && !otherCard.isMacthed)
18                 {
19                     [otherCards addObject:otherCard];
20                 }
21             }
22
23             //不能放于for循环之前,否则会将本次被选择的牌加入cards,不能放于下面的if之后,否则当if成立时返回,没有将本次翻牌的cost记录,且不能翻牌
24             self.score -= COST_TO_CHOOSE * self.gameModel;
25             card.chosen = YES;
26
27             if ([otherCards count] < self.gameModel - 1)
28             {
29                 self.gameState = [NSString stringWithFormat:@"State:%@",card.contents];
30                 return;
31             }
32             else
33             {
34                 int matchScore = [card match:otherCards];
35
36                 if (matchScore)
37                 {
38                     NSMutableString *state = [NSMutableString stringWithFormat:@"State:%@ matched",card.contents];
39                     self.score += matchScore * MATCH_BOUNDS * self.gameModel;
40                     for (Card *otherCard in otherCards)
41                     {
42                         [state appendFormat:@" %@",otherCard.contents];
43                         otherCard.matched = YES;
44                     }
45                     [state appendFormat:@". Get %d score!",matchScore * MATCH_BOUNDS * self.gameModel];
46                     card.matched = YES;
47
48                     self.gameState = state;
49                 }
50                 else
51                 {
52                     NSMutableString *state = [NSMutableString stringWithFormat:@"State:%@ with",card.contents];
53                     self.score -= MISMATCH_PENALTY * self.gameModel;
54                     for (Card *otherCard in otherCards)
55                     {
56                         [state appendFormat:@" %@",otherCard.contents];
57                         otherCard.chosen = NO;
58                     }
59                     [state appendFormat:@" not matched! %d point penalty!",MISMATCH_PENALTY * self.gameModel];
60
61                     self.gameState = state;
62                 }
63             }
64         }
65     }
66 }

  作业总结:虽然完成了作业的要求,但还有许多地方需要改进。如输入情况检测的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链接发给大家)

课程视频地址:网易公开课:http://open.163.com/movie/2014/1/H/U/M9H7S9F1H_M9H7VNFHU.html

       或者iTunes U搜索standford课程

时间: 2024-10-14 00:07:00

(3/18)重学Standford_iOS7开发_Objective-C_课程笔记的相关文章

(1/18)重学Standford_iOS7开发_iOS概述_课程笔记

写在前面:上次学习课程对iOS还是一知半解,由于缺乏实践,看公开课的视频有时不能很好地领会知识.带着问题去学习永远是最好的方法,接触一段时间iOS开发以后再来看斯坦福iOS公开课,又会有许多新的发现,对于已有的概念有了新的认识.这次课程笔记主要用作归纳知识点,整理学习思路,与大家讨论课后习题,交流等. 第一课:iOS概述 1.iOS分层:①Core OS:核心操作系统层,基于UNIX内核(套接字,文件系统,电源管理,钥匙串,Bonjour等).API多为C函数,实际应用使用较少. ②Core S

(6/18)重学Standford_iOS7开发_控制器多态性、导航控制器、选项卡栏控制器_课程笔记

终于有时间跟新了,两周时间复(yu)习(xi)了5门考试累觉不爱...... --------------------------------------------------------------------------我是正文分割线--------------------------------------------------------------------------------------------- 第六课 1.控制器多态性 这里控制器多态性是指在控制器中使用继承,通过继

(7/18)重学Standford_iOS7开发_视图、绘制、手势识别_课程笔记

第七课: 1.View 一般来说,视图是一个构造块,代表屏幕上一块矩形区域,定义了一个坐标空间,并在其中绘制及添加触控事件等. ①视图的层级关系 一个视图只能有一个父视图,可以有多个子视图 1 - (void)addSubview:(UIView *)aView; // 父视图添加子视图 2 - (void)removeFromSuperview; // 子视图从父视图移除自己 ②UIWindow UIView的顶级视图:一般情况下,iOS应用程序中只有一个UIWindow,指当前显示的屏幕内容

(8/18)重学Standford_iOS7开发_协议、block、动画_课程笔记

第八课: 1.协议 另一种安全处理id类型的方式如:id <MyProtocol> obj a.声明 //协议一般放于.h文件中或者在类的.h文件中 @protocol Foo <Xyzzy, NSObject>//<>中的内容表示还需实现自哪些协议,所有协议的根协议一般都是NSObject - (void)someMethod;//默认为必须实现的方法 @optional//可选方法声明 - (void)methodWithArgument:(BOOL)argumen

(2/18)重学Standford_iOS7开发_Xcode_课程笔记

第二课: 1.惰性初始化 1 -(ObjectType *)example 2 { 3 f(!_example) example =[[ObjectType alloc] init]; 4 5 return _example; 6 } 直到使用前最后一刻才初始化变量 2.数组字面量格式 @[a,b,c,…,m,n]; 3.@synthesize 同时重写属性的setter与getter方法时,需要显式合成,否则编译器默认生成@synthesize example = _example; 4.类方

(9/18)重学Standford_iOS7开发_动画、自动布局_课程笔记

最近开始实习,没多少时间更新了=_= 第九课: 1.上节课demo:Dropit完整实现 https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/cfc24c2c4300185d972cf151872d313414a48d32 2.Autolayout 比较简单请参照课件截图https://github.com/NSLogMeng/Stanford_iOS7_Study/blob/master/Slides/Lecture%209%20Sl

(5/18)重学Standford_iOS7开发_视图控制器生命周期_课程笔记

第五课: 1.UITextView @property (nonatomic, readonly) NSTextStorage *textStorage;//注意为只读属性,因此不能直接更改内容,NSTextStorage为NSMutableAttributeString的子类,因此可以更改字符串属性内容(而非字符串) //例如,添加属性 [self.body.textStorage addAttribute:NSForegroundColorAttributeName value:sender

Django开发BBS---51网络课程笔记(目录)

这是51cto中bbs课程中的一个项目,这里写一下每节的目录: Django开发BBS---51网络课程笔记(1) 这部分主要介绍了数据库的搭建及站点管理 http://4440271.blog.51cto.com/4430271/1663863 Bootstrap开发 这不分主要讲前端的设计 http://4440271.blog.51cto.com/4430271/1663934 Django开发BBS---51网络课程笔记(2) 这部分主要讲view与前端的衔接部分 http://4440

Django开发BBS---51网络课程笔记(1)

51上有一个用Django开发BBS论坛的免费视频,就开发过程写个简要的笔记.课程地址:http://edu.51cto.com/course/course_id-2787.html 论坛的开发以"抽屉"http://dig.chouti.com/ 为原型.开发一个类似的BBS网站. 抽屉网站的主界面结构: 由此,在创建项目之前,确定数据的表结构: 首先,应当有一个发帖的表, 其次, 是哪个用户发的,应当创建一个用户表 再有,应当有一个评论表.评论表中有一个id与帖子表相连 还应当建立