iOS學習之flappyBird游戲的實現
來自: http://www.cnblogs.com/chars/p/5183899.html
導言
在本人還是學生的時候,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文件。具體操作方法可以參看本人另一篇文章:
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