• iOS学习之flappyBird游戏的实现


    导言

    在本人还是学生的时候,flappyBird这款游戏非常火爆,最后等到Android版的出来之后,也是很痴迷的玩了一把。可是,本人游戏天赋一直平平,几度玩得想摔手机。本文主要介绍如何开发iOS平台的flappyBird,游戏中使用了原本软件的图片资源,仅作学习交流使用。本人实现的flappyBird游戏包含游戏等级设定,排行榜,音效等功能。

    技术点

    flappyBird是单机游戏,主要涉及界面逻辑、图片资源、游戏动画、得分排行。

    为了实现这几个功能,需要使用以下几个技术框架:

    1)AVFoundation

    2)归档

    3)模态视图

    4)NSTimer

    5)视图控件,包括UIImageView、UILabel、UITableView等

    实现过程

    1、创建工程

    1)打开Xcode,点击新建工程,选择Single View Application模板

    2)填写工程信息

     2、移除Main.storyboard文件

    上图是flappyBird的文件目录,因为Xcode6使用模板创建工程时会自动生成Main.storyboard文件,而工程中本人使用代码布局,所以可以移除Main.storyboard文件。具体操作方法可以参看本人另一篇文章:

    《iOS学习之移除Main.storyboard》

    3、游戏界面布局

    1)主菜单界面,游戏难度设定界面、排行榜界面,效果图如下

            

    2)游戏界面,效果图如下

    需要说明的是,Game Over这个界面,首先需要隐藏或者等到游戏结束才创建。本人是选择在游戏判定结束时才创建并显示。

    4、游戏运行

    这款游戏的两个关键点:

    1)使用定时器驱动游戏界面运行,即游戏界面中的柱子高低变化与柱子的消失与产生。

    2)游戏结束的判定,这里涉及两个问题,一是碰撞检测,二是计分统计。

    具体实现部分代码

    1、计分统计

    -(void)columnLabelClick {
        
        if (topPipeFrame.origin.x == (100 + 30 - 70)) {
            columnNumber++;
            columnLabel.text = [NSString stringWithFormat:@"%zi",columnNumber];
        }
    }

    2、绘制柱子

    -(void)pipe {
        //通道高度
        NSInteger tunnelHeight = 0;
        //根据游戏难度设定通道高度
        if([[DataTool stringForKey:kRateKey] isEqualToString:@"ordinary"]) {
            tunnelHeight = 100;
        }else if([[DataTool stringForKey:kRateKey] isEqualToString:@"general"]) {
            tunnelHeight = 90;
        }else if([[DataTool stringForKey:kRateKey] isEqualToString:@"difficult"]) {
            tunnelHeight = 80;
        }else if([[DataTool stringForKey:kRateKey] isEqualToString:@"hard"]) {
            tunnelHeight = 75;
        } else if([[DataTool stringForKey:kRateKey] isEqualToString:@"crazy"]) {
            tunnelHeight = 70;
        }
        
        //柱子图像
        NSInteger tall = arc4random() % 200 + 40;
        
        topPipe = [[UIImageView alloc]initWithFrame:CGRectMake(320, -20, 70, tall)];
        topPipe.image = [UIImage imageNamed:@"pipe"];
        [self.view addSubview:topPipe];
    
        bottomPipe = [[UIImageView alloc]initWithFrame:CGRectMake(320, tall + tunnelHeight, 70, 400)];
        bottomPipe.image = [UIImage imageNamed:@"pipe"];
        [self.view addSubview:bottomPipe];
    
        //把底部图片视图放在柱子视图上面
        [self.view insertSubview:roadView aboveSubview:bottomPipe];
    }

    3、使用定时器,驱动游戏界面运行,并进行碰撞检测

    //添加定时器
    timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
    
    //定时器操作
    -(void)onTimer {
        //底部动画移动
        CGRect frame = roadView.frame;
        if (frame.origin.x == -15) {
            frame.origin.x = 0;
        }
        frame.origin.x--;
        roadView.frame = frame;
        
        //上升
        if (isTap == NO) {
            CGRect frame = birdsView.frame;
            frame.origin.y -= 3;
            number += 3;
            birdsView.frame = frame;
            if (number >= 60) {
                isTap = YES;
            }
        }
        
        //下降
        if(isTap == YES && birdsView.frame.origin.y < 370){
            CGRect frame = birdsView.frame;
            frame.origin.y++;
            number -= 2;
            birdsView.frame = frame;
            number = 0;
        }
        
        //柱子移动
        topPipeFrame = topPipe.frame;
        CGRect bottomPipeFrame = bottomPipe.frame;
        topPipeFrame.origin.x--;
        bottomPipeFrame.origin.x--;
        topPipe.frame = topPipeFrame;
        bottomPipe.frame = bottomPipeFrame;
        if (topPipeFrame.origin.x < -70) {
            [self pipe];
        }
        
        //碰撞检测(交集)
        bool topRet = CGRectIntersectsRect(birdsView.frame, topPipe.frame);
        bool bottomRet = CGRectIntersectsRect(birdsView.frame, bottomPipe.frame);
        if (topRet == true || bottomRet == true) {
            [self.soundTool playSoundByFileName:@"punch"];
            [self onStop];
        }
        if (topPipeFrame.origin.x == (100 + 30 - 70)) {
            [self.soundTool playSoundByFileName:@"pipe"];
            [self columnLabelClick];
        }
    }

    4、更新分数,更新最佳分数与排行榜分数,并使用归档将数据持久化

    -(void)updateScore {
        //更新最佳成绩
        if (columnNumber > [DataTool integerForKey:kBestScoreKey]) {
            [DataTool setInteger:columnNumber forKey:kBestScoreKey];
        }
        //更新本局分数
        [DataTool setInteger:columnNumber forKey:kCurrentScoreKey];
        //更新排行榜
        NSArray *ranks = (NSArray *)[DataTool objectForKey:kRankKey];
        NSMutableArray *newRanksM = [NSMutableArray array];
        NSInteger count = ranks.count;
        BOOL isUpdate = NO;
        for (NSInteger i = 0; i < count; i++) {
            NSString *scoreStr = ranks[i];
            NSInteger score = [scoreStr integerValue];
            if (score < columnNumber && isUpdate == NO) {
                scoreStr = [NSString stringWithFormat:@"%zi", columnNumber];
                [newRanksM addObject:scoreStr];
                isUpdate = YES;
                i--;
            } else {
                scoreStr = [NSString stringWithFormat:@"%zi", score];
                [newRanksM addObject:scoreStr];
            }
        }
        if (newRanksM.count > count) {
            [newRanksM removeLastObject];
        }
        [DataTool setObject:newRanksM forKey:kRankKey];
    }

    5、绘制GameOver提示显示

    -(void)pullGameOver {
        //游戏结束操作界面
        gameOver = [[GameOverView alloc] initWithFrame:CGRectMake(20, 160, 280, 300)];
        gameOver.delegate = self;
        [self.view addSubview:gameOver];
    }

    6、游戏停止操作

    -(void)onStop {
        //更新分数
        [self updateScore];
        //停止定时器
        [timer setFireDate:[NSDate distantFuture]];
        //弹出游戏结束操作界面
        [self pullGameOver];
    }

    小结

    这款游戏的实现还是很简单的,主要使用UIImageView自带的动画实现方式,即可实现bird的动画效果。使用NSTimer即可实现游戏场景的柱子移动,至于柱子的高度,则可以使用随机数方式在一定范围内实现高低变化。最后可以使用CGRectIntersectsRect来实现边界碰撞检测来判定游戏是否结束。

    以上是本人开发iOS版flappyBird的简要过程介绍,其中只包含了关键点的代码实现,具体完整游戏源代码地址:https://github.com/CharsDavy/flappyBird

    【扫描关注更多干货】

    公众号:xiaoniu

  • 相关阅读:
    JAVA实现AES的加密和解密算法
    工厂方法模式(Factory Method)
    Java开发23种设计模式
    读取Maven项目下resources目录下的配置文件(properties为例)
    迭代解析JSON简单实例
    Tomcat8.0配置JNDI多数据源
    SpringMVC DispatcherServlet-------视图渲染过程
    【C/C++】求解线性方程组的雅克比迭代与高斯赛德尔迭代
    【C/C++】实现牛顿迭代
    【C/C++】查找(一):静态查找表
  • 原文地址:https://www.cnblogs.com/chars/p/5183899.html
Copyright © 2020-2023  润新知