UIKit基础:16-小游戏之舒尔特表

在前面, 我们学会制作了一个简单的小游戏石头剪刀布, 现在我们来学习制作第二个小游戏, 那就是舒尔特表啦, 首先让我们来创建一个新的工程并且配置好storyboard:



搭建好页面之后, 一般情况下我们是需要进行UI控件关联, 但这次比较特殊一点, 我们要创建多一个Class, 并且把右边的UIVIewController和我们新创的Class关联在一起


PS: 记得, 新建的Class要继承与UIViewController, 否则无法关联.



设置完之后, 我们还需要再配置一些细节, 就是从第一个页面跳转到第二个页面:



PS: 按住control键选中UIButton,  拖到第二个页面之后放手, 然后选择modal, 然后就把两个页面进行关联.


现在我们来关联控件, 首先我们先关联第二个页面的控件.


这里有一点要注意, 这里有一个IBOutletCollection, 是用来把第二个页面的所有UIButton堆在一起, 做成一个UIButton集合, 这样子方便我们对这一堆按钮进行随机操作, 并且这里还有一个IBAction方法, 也是保存所有的按钮, 但是这里我们需要设置好UIButtontag值.


我在这里定义了一个代理和一个协议, 代理是用来给第一个页面里面的UILabel使用的, 用来记录玩家最佳的成绩, 协议里面的方法就是用来实现该代理方法的, 接下来我们继续:

@interface GameViewController ()
{
    // 用户上次点击的数字
    NSInteger _lastTapNumber;
    
    // 游戏开始的时间
    NSDate *_gameStartTime;
    
    // 游戏时间
    NSTimer *_gameTimer;
}
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSArray *numberArray = [self createNumberArray];
    

    for (UIButton *button in _numberButtons) {
        
        NSString *text = [numberArray[button.tag]stringValue];
        
        [button setTitle:text forState:UIControlStateNormal];
    }
    _lastTapNumber = 0;
    
    // 设置定义时钟
    // 第一个参数:多少时间会触发一次, 以秒为单位
    // 第二个参数:如果看到函数的参数有target, 一般情况下都使用self
    // 第三个参数:SEL, 需要调用其他的方法, 就是每次时钟被触发的时候去调用, 最多可以一个参数, 就是时钟本身
    // 第四个参数:暂时不用考虑, 设置成nil
    // 第五个参数:是否重复
    _gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
    // 记录游戏开始的时间
    _gameStartTime = [NSDate date];
}

#pragma mark - 私有方法
// 时间触发执行方法
- (void)updateTimer:(NSTimer *)sender
{
    // 在此处设置游戏计时器标签的内容, 提示玩家当前过了多少秒
    
    // fireDate是时钟当前触发的时间
    NSInteger deltaTime = [sender.fireDate timeIntervalSinceDate:_gameStartTime];
    
    // 将时间专成NSString
    NSString *text = [NSString stringWithFormat:@"%02ld:%02ld", deltaTime / 60, deltaTime % 60];
    
    // 设置计时器时间
    [_timerLabel setText:text];
    
    // 设置时间的字符串 00:00 mm:ss
    NSLog(@"过了一秒了 %ld", deltaTime);

}

// 数组
- (NSArray *)createNumberArray
{
    NSMutableArray *array = [NSMutableArray array];
    
    for (NSInteger i = 1; i < 10; i++)
    {
        [array addObject:@(i)];
    }
    
    // 打乱数组的顺序
    // 思路: 使用随机数, 不能重复
    // 1,2,3,4,5,6,7,8,9
    // 先随机出来一个位置的数字0~9 假设是5, 用位置5的数字位置和0交换
    // 6,2,3,4,5,1,7,8,9
    // 再随机出来一个位置的数字1~9 假设是3, 用位置1的数字位置和1交换
    // 以此类推, 就可以得到一个随机顺序的数组.
    
    for (NSInteger i = 0; i < 9; i++) {
        NSInteger seed = i + arc4random_uniform(9 - (unsigned int)i);
        
        // 交换数据
        [array exchangeObjectAtIndex:i withObjectAtIndex:seed];
    }

    return array;
}

#pragma mark 回到主界面
- (IBAction)done {
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark 点击事件
- (IBAction)tapNumberButton:(UIButton *)sender {
    NSString *text = [[sender titleLabel] text];
    NSInteger number = [text integerValue];
    
    NSLog(@"%ld", number);
    
    if ((_lastTapNumber + 1) == number) {
        _lastTapNumber++;
        
        // 设置点击后的颜色
        [sender setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        
        // 点击后禁用按钮
        [sender setEnabled:NO];
    } else {
        NSLog(@"点错了");
    }
    
    NSLog(@"末次计数:%ld", _lastTapNumber);
    
    if (_lastTapNumber == 9) {
        NSLog(@"胜利了");
        
        //关闭时钟
        [_gameTimer invalidate];
        
        // 委托代理执行方法, 如果没有设置代理, 那么这条指令就不会执行, 但也不会报错
        [_delegate gameViewDidDone:_timerLabel.text];
        
        NSString *message = [NSString stringWithFormat:@"帅呆了, 用时:%@", _timerLabel.text];
        
        // UIAlertView是用来提示用户信息的小窗口
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
        
        [alert show];
    }
}

#pragma mark - AlertView代理方法
#pragma mark 回到游戏主界面
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [self done];
}

PS: 一般我们玩游戏, 无论是赢了或者是输了, 游戏都会弹出一个对话框出来, 提示游戏结束, 并且会释放游戏页面, 但释放页面方法并不是是在游戏胜利的方法里执行, 而是在代理方法里面执行, 否则我们会见到游戏页面结束的速度会比弹出对话框的速度要快.




接下来就是ViewController文件:



最后我们来实现ViewController.m里面所有的功能:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController


// ViewController的内置方法, 所有在storyboard中的连线在推出新的视图控制器之前都会调用这个方法.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // 获得目标视图控制器
    GameViewController *controller = [segue destinationViewController];
    
    [controller setDelegate:self];
}

#pragma mark - 游戏视图代理方法
- (void)gameViewDidDone:(NSString *)timeString
{
    NSLog(@"你花了%@时间",timeString);
    [_socreLabel3 setText:timeString];
}

@end

最终的效果:




好了, 基础控件讲到这里就已经全部讲完了, 之后的就是讲解高级控件了~~~

原文地址:https://www.cnblogs.com/iOSCain/p/4333151.html