• 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
    

    最终的效果:




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

  • 相关阅读:
    C#项目间循环引用的解决办法,有图有真相
    打破关注自己的门
    引用AForge.video.ffmpeg,打开时会报错:找不到指定的模块,需要把发行包第三方文件externalsffmpegin里的dll文件拷到windows的system32文件夹下。
    Gs_Class.Gs_DataFunction数据操作类库20160225
    Gs_Class._BaseQueryWeb查询页面基类(aspx.net)
    关于开钱箱(不是用螺丝刀子开)
    处理模糊查询时读取url地址参数变化的情况
    jeecg单步调试
    jeecg安装——mysql数据库创建+手动执行初始化脚本
    小程序动画效果
  • 原文地址:https://www.cnblogs.com/iOSCain/p/4333151.html
Copyright © 2020-2023  润新知