你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS游戲開發沒有你想的那麼難

iOS游戲開發沒有你想的那麼難

編輯:IOS開發基礎

和大家聊聊天

有段日子沒有發布過任何文字和代碼了,之前的文章下很多網友留言也沒有回復,其實每條評論我都有認真看.只是最近整個人有點迷茫,望大家理解.其實我很期盼大家和我聊聊天,但不要總是聊技術...

關於項目(代碼下載地址在文章最下面點擊GitHub鏈接)

項目說明:考慮到許多不會使用Cocos2D-X和Swift的朋友,此次項目采用Objective-C並且基於UIKit框架實現的.意思就是你會使用UIView,就可以嘗試開發游戲了,嘿嘿!

原生項目是采用Cocos2D-X開發的,所以在對圖片的動畫處理時,有些地方會沒有原生顯得那麼流暢(如切割圖片,對圖片的變形處理,圖片快速替換等),並且在性能上來說,UIKit也不如Cocos2D-X流暢,畢竟術業有專攻.如果是要開發游戲來上架的話,最好采用專門的游戲引擎來搭建項目(Cocos-2D,Unity3D,Sprite Kit等).

  • 開發語言:Objective-C

  • 開發工具:Xcode7.1

  • 編譯環境:大於Xcode7.0

  • 輔助工具:Photoshop CS6

項目講解: 把整個項目用文字帶著大家過一遍有點不現實.這裡我將項目的大體結構和一些主要邏輯,以及主要對象提供的接口功能下面列舉出來.建議同學們先看代碼,配合代碼再來看這篇文章,順著代碼和文字搞懂項目主體邏輯.當需要學習具體功能如何實現時,在看.m文件下的實現代碼學習如何實現功能,如果有哪些地方不清楚,在簡書下面留言或者微博留言.

學習建議:最好使用真機來進行運行調試,有些關卡需要使用加速計與陀螺儀等功能,模擬器是沒有的.當遇到實在無法過去的關卡時,點擊首頁的有些手柄按鈕,點擊解鎖下一關或者在代碼啟動時,手動寫入關卡得分信息即可.

575247-2cda5b9a5fe6a1ad.jpg

Hardest

主體架構

音效和背景音樂

音效和背景音樂采用了AVFoundation框架封裝了一個WNXSoundToolManager的單利對象,背景音樂采用AVAudioPlayer,背景音效采用AudioServicesPlaySystemSound.

提供以下方法和屬性供全局調用或修改,通過修改bgMusicType和soundType可以控制背景音樂和音效聲音的大小,通過playSoundWithSoundName:方法根據音效名稱設置播放不同的音效.

// 音效或背景音樂播放聲音打大小枚舉
typedef NS_ENUM(NSInteger, SoundPlayType) {
    SoundPlayTypeHight = 0,
    SoundPlayTypeMiddle,
    SoundPlayTypeLow,
    SoundPlayTypeMute
};

@interface WNXSoundToolManager : NSObject

// 背景音樂聲音大小Type
@property (nonatomic, assign) SoundPlayType bgMusicType;
// 音效聲音大小Type
@property (nonatomic, assign) SoundPlayType soundType;

// 暫停背景音樂
- (void)pauseBgMusic;
// 停止播放背景音樂
- (void)stopBgMusic;
// 重新播放背景音樂
- (void)playBgMusicWihtPlayAgain:(BOOL)playAgain;
// 播放音效:音效名稱
- (void)playSoundWithSoundName:(NSString *)soundName;
// 設置背景音樂音量:音量大小0~1
- (void)setBackgroundMusicVolume:(float)volume;

// 獲取SoundManager單利對象
+ (instancetype)sharedSoundToolManager;

@end

保存和讀取玩家關卡記錄(WNXStageInfoManager)

如何持久化存儲玩家過關信息和每關的得分記錄.本項目采用歸檔和解檔的方案.
拿到WNXStageInfoManager的單例對象,通過調用Save和Read方法保存或讀取關卡信息,當游戲關卡進入結算得分控制器後,判斷新記錄是否需要保存,如果需要調用保存接口.具體實現代碼請參照WNXStageInfoManager.m文件

// 單例方法
+ (instancetype)sharedStageInfoManager;

// 保存關卡信息
- (BOOL)saveStageInfo:(WNXStageInfo *)stageInfo;
// 讀取指定關卡編號的關卡信息
- (WNXStageInfo *)stageInfoWithNumber:(int)number;

// 這個接口是當游戲無法過關時,在RootViewController點擊手柄按鈕,解鎖下一關卡使用(**秘籍~慎用**)
- (BOOL)unlockNextStage;

啟動頁動畫

啟動頁動畫是目前App比較常見的功能(順豐優選,順手付,順豐海淘等都有).其實這裡有一種假象,在AppDelegate的didFinishLaunchingWithOptions()方法中,添加一個與啟動圖片完全一樣的AnimVC,將AnimVC設置為keyWindow的rootViewController,在AnimVC的viewDidApper()方法中執行動畫,當動畫完成後通過Block切換keyWindow的rootViewController為首頁VC就OK了.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [NSThread sleepForTimeInterval:1.0];

    [self setKeyWindow];

    return YES;
}

- (void)setKeyWindow {
    __weak typeof(self) weakSelf = self;

    WNXLaunchAnimationViewController *launchAnimationVC = [[WNXLaunchAnimationViewController alloc] init];
    launchAnimationVC.animationFinish = ^{
        UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        WNXBaseNavigationController *rootNav = (WNXBaseNavigationController *)[sb instantiateViewControllerWithIdentifier:@"RootNavigationController"];
        weakSelf.window.rootViewController = rootNav;
    };

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = launchAnimationVC;
    [self.window makeKeyAndVisible];
}

關於動畫這裡我就不講什麼了,有興趣的朋友可以自己參考工程代碼研究下.

52.gif

啟動頁動畫

首頁(WNXRootViewController)

首頁其實就是一張圖片,通過判斷當前設備屏幕尺寸,讀取當前設備尺寸對應按鈕的Plist文件,拿到首頁6個按鈕位置的Frame,在touchesBegan()方法中,通過CGRectContainsPoint方法判斷當前點擊位置時候在指定的Frame內,符合條件時做出對應 的操作,具體代碼

// 加載當前設備對應首頁按鈕Frame
- (void)loadHomeButtonFrame {
    NSString *framePath = [[NSBundle mainBundle] pathForResource:@"home.plist" ofType:nil];
    NSDictionary *frameDic = [NSDictionary dictionaryWithContentsOfFile:framePath];

    NSDictionary *dict;

    if (iPhone5) {
        dict = frameDic[@"iphone5"];
    } else {
        dict = frameDic[@"iphone4"];
    }

    _settingFrame = CGRectFromString(dict[@"btn_setting_frame"]);
    _languageFrame = CGRectFromString(dict[@"btn_language_frame"]);
    _moreFrame = CGRectFromString(dict[@"btn_more_frame"]);
    _rankFrame = CGRectFromString(dict[@"btn_rank_frame"]);
    _playFrame = CGRectFromString(dict[@"btn_play_frame"]);
    _getFrame = CGRectFromString(dict[@"btn_get_frame"]);
}

// 判斷點擊點是否在對應的Frame內
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];

    CGPoint touchPoint = [touch locationInView:touch.view];

    [[WNXSoundToolManager sharedSoundToolManager] playSoundWithSoundName: kSoundCliclName];

    if (CGRectContainsPoint(_settingFrame, touchPoint)) {

        [self performSegueWithIdentifier:@"Setting" sender:nil];

    } else if (CGRectContainsPoint(_languageFrame, touchPoint)) {

        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:kBlogURL]];

    } else if (CGRectContainsPoint(_moreFrame, touchPoint)) {
        [self performSegueWithIdentifier:@"Rare" sender:nil];

    } else if (CGRectContainsPoint(_rankFrame, touchPoint)) {

        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:kWeiBoURL]];

    } else if (CGRectContainsPoint(_playFrame, touchPoint)) {

        [self performSegueWithIdentifier:@"PlayGame" sender:nil];

    } else if (CGRectContainsPoint(_getFrame, touchPoint)) {

        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:kGithubUrl]];

    }
}



關卡選擇控制器(WNXSelectStageViewController)

關卡選擇控制器采用UIScrollView實現,在scrollView放入24個WNXStageListView(當然這裡也可以自己創建緩存池復用,個人覺得沒必要),每個WNXStageListView都有對應的一個關卡信息模型stageModel,模型屬性從工程->Resources->Plist->stages.plist文件中讀取,根據model裡的成員變量,加載關卡對應的信息,如關卡圖片,是否解鎖,玩家歷史得分以及Rank標記等.

每個WNXStageListView,根據ID設置不同的Tag,並且提供單擊手勢,在stageView的點擊事件中.調用導航控制器,Push到WNXPrepareViewController控制器,並將選擇關卡的stageModel作為參數傳過去,WNXPrepareViewController做出相應的展示即可.
選擇關卡效果如下圖所示

37.gif

選擇關卡效果圖

關卡准備開始控制器(WNXPrepareViewController)

每個關卡開始游戲前,都會以動畫的形式出現本關游戲名稱,過關規則,以及歷史得分等一系列功能.都是由這個控制器完成的.通過選擇關卡時傳入的stageModel,展示model內對應的數據,當用戶點擊Play按鈕時,使用WNXGameControllerViewManager單例對象,根據傳入的stageModel,返回對應的關卡ViewController,然後Push到返回的ViewController游戲關卡即可.

37.gif

准備開始控制器效果圖

關卡控制器

24關,每關都有很多重復的功能,這裡我們按照不同關卡的屬性抽取出幾種公共的父類,每個關卡根據自己的需求選擇繼承相應的控制器,並且在ViewDidLoad函數中初始化每個關卡不同的屬性,具體分類效果如下圖所示

575247-7af5c5adf4fe8a4c.jpg

邏輯圖

WNXBaseGameViewController --> UIViewController

WNXBaseGameViewController是所有關卡ViewController的基類控制器,提供每個游戲關卡的基本屬性設置,並且每個關卡的初始化操作都封裝在了這裡,每個關卡只需要在自己的ViewDidLoad方法中調用buildStageInfo()函數,添加構建自己的UI即可,重寫父類的方法,完成每關不同的操作.

公有屬性

1.WNXGameGuideType guideType每關第一次進入關卡,本關游戲手勢提示樣式

  • WNXGameGuideTypeNone無提示

  • WNXGameGuideTypeOneFingerClick單個手指頭點擊

  • WNXGameGuideTypeReplaceClick左右按鈕交替點擊

  • WNXGameGuideTypeMultiPointClick多個手指同時點擊

01.gif

單個手指頭點擊效果

02.gif

左右按鈕交替點擊效果

03.gif

多個手指同時點擊效果樣式

2.WNXStage *stage每關關卡信息model(model詳情)

3.WNXScoreboardType每關計分板樣式

  • WNXScoreboardTypeNone無計分板

  • WNXScoreboardTypeCountPTS [WNXScoreboardTypeCountPTS]()

  • WNXScoreboardTypeTimeMS [WNXScoreboardTypeTimeMS]()

  • WNXScoreboardTypeSecondAndMS [WNXScoreboardTypeSecondAndMS]()

01.jpg

WNXScoreboardTypeCountPTS計分板樣式

02.jpg

WNXScoreboardTypeTimeMS計分板樣式

03.jpg

WNXScoreboardTypeSecondAndMS計分板樣式

4.UIView *countScoreView計分板(考慮有多種樣式,使用了UIView,每個關卡在用的時候根據自己類型進行強制轉換)

5.WNXStateView *stateView關卡提示狀態View

6.UIButton *playAgainButton 重新開始游戲按鈕

7.UIButton *pauseButton暫停按鈕

公有方法

- (void)beginGame; // 開始游戲
- (void)endGame;   // 結束游戲
- (void)beginRedayGoView; // 開始顯示RedayGo動畫
- (void)readyGoAnimationFinish; // RedayGo動畫顯示結束
- (void)pauseGame;    // 暫停游戲
- (void)continueGame; // 繼續游戲
- (void)playAgainGame; // 重新開始游戲
- (void)showGameFail; //  游戲失敗(部分關卡有, 進入失敗ViewController)

// 顯示關卡游戲結果
- (void)showResultControllerWithNewScroe:(double)scroe // 玩家得分
                                    unit:(NSString *)unil  // 本關計分器顯示單位
                                   stage:(WNXStage *)stage // 關卡信息
                              isAddScore:(BOOL)isAddScroe; // 是否是添加分數(這裡偷了個懶,只做了添加動畫,應該有分數增長加動畫或者減少動畫)

// 構建關卡信息
- (void)buildStageInfo;

// 將廣告,重新開始,暫停按鈕放到最上層
- (void)bringPauseAndPlayAgainToFront;

// 構建顯示狀態View
- (void)buildStageView;

WNXRYBViewController --> WNXBaseGameViewController

WNXRYBViewController,繼承至WNXBaseGameViewController,底部擁有三個按鈕,並且默認有三條紅黃藍背景條(擁有高亮時圖片),底部按鈕默認Tag為0,1,2,游戲大部分關卡為這種樣式

公有屬性

@property (strong, nonatomic) UIImageView *redImageView;
@property (strong, nonatomic) UIImageView *yellowImageView;
@property (strong, nonatomic) UIImageView *blueImageView;

@property (strong, nonatomic) UIButton    *redButton;
@property (strong, nonatomic) UIButton    *yellowButton;
@property (strong, nonatomic) UIButton    *blueButton;

@property (nonatomic, strong) NSMutableArray *buttons;
@property (nonatomic, strong) NSArray *buttonImageNames;

公有方法

- (void)setButtonsIsActivate:(BOOL)isActivate; // 設置全部按鈕是否可以點擊

- (void)setButtonImage:(UIImage *)image // 當底部按鈕圖片相同時,設置底部按鈕圖片
      contenEdgeInsets:(UIEdgeInsets)insets; // 圖片的contenEdgeInsets

- (void)removeAllImageView; // 有寫關卡不需要紅黃藍背景圖片時,刪除三個UIImageView

// 底部按鈕Action
- (void)addButtonsActionWithTarget:(id)target 
                            action:(SEL)action
                  forControlEvents:(UIControlEvents)forControlEvents;

WNXTwoButtonViewController --> WNXBaseGameViewController

WNXTwoButtonViewController,底部擁有倆個按鈕關卡,並且默認帶有背景ImageView.

公有屬性

@property (nonatomic, strong) UIImageView *backgroundIV;

@property (nonatomic, strong) UIButton *leftButton;
@property (nonatomic, strong) UIButton *rightButton;

公有方法

// 統一設置按鈕是否可以被點擊,部分關卡按鈕點擊後,不允許再次點擊
- (void)setButtonActivate:(BOOL)isActivate;

WNXBackgroundViewController --> WNXBaseGameViewController

只帶有背景圖關卡,項目中有些關卡是采用陀螺儀和加速計的關卡.

關於每一關如何實現,我這裡就不一一列舉了,有點太多了,但是都並不復雜,寫個2~3關基本就能掌握套路了,就個別關卡使用了加速計和陀螺儀,具體實現的代碼我都在工程中寫的很明白了,在Stage文件夾下,大家自行參考即可.

分數結算控制器(WNXResultViewController)

當每個關卡游戲結束後,都會進入分數結算控制器,這裡通過在WNXBaseGameViewController中封裝了一個方法以保證每個關卡控制器都可以直接調用計算得分,當關卡游戲結束後,調用當前關卡的下面函數即可,這裡小熊偷了個懶,只實現了相加的功能,不過相信通過參考相加的功能,大家實現相減的功能也是小csae啦~

- (void)showResultControllerWithNewScroe:(double)scroe
                                    unit:(NSString *)unil
                                   stage:(WNXStage *)stage
                              isAddScore:(BOOL)isAddScroe;

說明下isAddScore的作用

  • 有些關卡是得分越高越好.這總關卡在顯示結果的時候分數是從0一點點網上加的,這種情況isAddScore傳入YES

  • 有些關卡是得分越少越好,這總卡在顯示結果的時候分數是從大網小一點點減少的,這種情況isAddScore傳入NO

當結算分數完成後,會出現以下幾種情況,跟據不同的得分情況執行不同的邏輯即可,具體邏輯如下所示

狀態一: 游戲失敗(當得分小於等於F,不保存得分),出現下圖

20.gif

得分不夠,顯示失敗

狀態二: 游戲成功

  • 當前關卡無得分記錄,並且得分大於F,保存玩家得分,正常顯示得分結果,並且解鎖下一關.

63.gif

成功狀態1

  • 當前關卡有記錄,但是本次游戲得分沒有超越歷史記錄,正常顯示得分結果,不保存本次游戲得分.

22.gif

成功狀態2

  • 當前關卡有記錄,並且本次游戲得分超越歷史記錄,顯示超越歷史得分動畫,並且講本次得分替換掉上一次得分.

23.gif

成功狀態3

失敗(WNXFailViewController)

  • 部分關卡會有在游戲中失敗的情況,如下圖

24.gif

游戲失敗

這裡也是在WNXBaseGameViewController中封裝了一個方法,當關卡失敗後,直接調用showGameFail()方法,Push到失敗控制器即可.

如果需要失敗時執行一些操作,如停止計時,停止動畫等,在當前關卡重寫showGameFail()方法,在調用父類方法前調用需要執行的相應代碼即可,如下

- (void)showGameFail {
    // 需要在游戲失敗時執行的相應代碼
    // do something
    
    [super showGameFail];
}

暫停控制器(WNXPauseViewController)

每個游戲關卡都有暫停的功能,所以將暫停的功能封裝到WNXBaseGameViewController中,並且提供兩個接口供子控制器調用,分別為

  • (void)pauseGame; 暫停游戲

  • (void)continueGame; 繼續游戲

在每個游戲關卡重寫上面兩個方法,當玩家點擊暫停按鈕時,回調用暫停方法,點擊返回時,會調用繼續方法,具體實現如下

// 玩家點擊暫停按鈕
- (void)pauseGame {
    // 關卡暫停,本關需要執行的相應操作,如暫停計時器,動畫等.

    [super pauseGame];
}

- (void)continueGame {
    [super continueGame];

    // 繼續游戲,繼續執行暫停前的操作
}

25.gif

暫停控制器效果圖

項目總結

項目寫的比較匆忙,基本每天晚上抽空寫點,寫完也沒有回頭CodeReview,說實話,這是一個非常非常不好的習慣,大家一定要養成定期回頭看看自己寫過代碼的習慣.隨著越網後寫,發現前面有很多地方可以修改,我吧有點懶,So你懂的...

感覺光靠文字來講述一個項目實在是太困難.希望大家還是參考工程代碼,當遇到無法看懂或者不理解的時候參考下我寫的Blog應該會更好一些.這個游戲項目說實話還是比較簡單的,相信大家仔細研究下都可以實現的.游戲還有24關,有興趣的同學可以嘗試自己將剩下的24關自己實現下~

有段日子沒使用OC寫項目了,如果有任何建議可在簡書留言,或者私信,或者在微博留言都可以,我都會看的.

這個項目完事後,可能會很長一段時間,不再寫這種大型的開源項目了,因為我個人准備開發一款游戲上架到AppStore,從設計到UI設計以及需求實現都是我一人完成,工作量比較大.PS(現在連做什麼都不知道呢...).

以後我會分享一些有意思的小功能,小動畫等給大家.希望朋友繼續關注維尼的小熊.

代碼下載地址(如果覺得有幫助,請點擊Star★)

代碼下載地址,記得Star★和Follow

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved