正好不知道接下來要怎么寫的時候,發現了一本好書:《 Learn IPhone and iPad Cocos2d Game Delevopment》。于是直接翻譯了第4章的例子。如果你看過這部分內容,可以直接跳過不看了。 本章講如何響應加速器事件。
一、游戲介紹
這個例子是一個叫做 Doodle Drop的游戲,是一個重力感應類游戲。玩家操縱角色來躲避從空中墜落的障礙物。游戲界面如下:
二、設置主場景
1、新建Cocos2d Application,工程名DoodleDrop。
2、游戲主場景。選File -> new file,選擇User Templates -> Cocos2d.0.99.x -> CCNode.class。Subclass Of選擇CCLayer。文件名選GameScene。
3、在頭文件中聲明靜態方法 +(id) scene;
4、.m文件
#import "GameScene.h"
@implementation GameScene
+(id) scene {
CCScene *scene = [CCScene node];
CCLayer* layer = [GameScene node];
[scene addChild:layer];
return scene;
}
-(id) init {
if ((self = [super init])) {
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); return self;
}
}
-(void) dealloc {
// never forget to call [super dealloc] [super dealloc];
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
[super dealloc];
}
@end
5、刪除HelloWorldScene.h和HelloWorldScene.m文件。
6、修改DoodleDropAppDelegate.m,將其中的主場景啟動代碼修改為GameScene:
[[CCDirector sharedDirector] runWithScene: [GameScene scene]];
三、游戲角色
1 、把玩家角色圖片 alien.png 添加到工程。添加時,選中“ Copy items ”,同時勾選“ add to targets ”中的“ DoodleDrop ”選項。
2 、在游戲主場景 (GameScene.h) 增加變量聲明:
CCSprite* player;
3、在游戲主場景(GameScene.m)的init方法中加入下列代碼:
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:@"alien.png"];
[self addChild:player z:0 tag:1];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageHeight = [player texture].contentSize.height;
player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);
這樣,玩家角色就被放到屏幕底部正中的位置上。注意, player變量未retain。因為addChild會自動retain。
[player texture].contentSize.height返回的是渲染圖的content size。渲染對象(玩家角色圖片alient.png)有兩個尺寸:content size和texture size。前者是圖片的實際尺寸,后者是渲染尺寸——iPhone規定渲染尺寸只能是2的n次方。比如圖片實際尺寸100*100,那么渲染尺寸則是128*128,因為最接近100的2的n次方為128。
四、使用加速器
1、為了響應加速器事件,你必須在init方法中加上:
self.isAccelerometerEnabled = YES;
同時實現 accelerometer方法:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
CGPoint pos = player.position;
pos.x += acceleration.x * 10;
player.position = pos;
}
跟 java和c不同。你不能對 player.position.x進行賦值。這種賦值在
c語言中是可以的,但oc中不行。因為player.position實際上是調用[player position],這個方法返回一個臨時的CGPoint變量。當你想對這個臨時的CGPoint的x進行賦值后,這個變量會被被拋棄,所以你的賦值沒有任何作用。所以你需要用一個新的CGPoint變量,修改其x值,然后再把這個CGPoint賦值給player.position(即調用[player setPosition:])。如果你是來自java和c++的程序員,在oc中需要留心這個“不幸的”問題并盡可能的修改編程習慣。
2、運行測試
模擬器不支持重力感應,請在物理設備上運行代碼。
五、玩家控制
現住發現用加速器控制有些不靈?反應遲鈍,移動也不流暢?為此,我們需要增加一些代碼。
首先需要增加變量聲明:
CGPoint playerVelocity;
為了便于今后的擴展(假設有一天我們會想上下移動角色),這是一個 CGPoint類型,而不是一個float。
然后修改加速器方法:
-(void) accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration
{
// 減速度系數(值越小=轉向越快)
float deceleration = 0.4f;
// 加速度系數 (值越大 = 越敏感)
float sensitivity = 6.0f;
// 最大速度
float maxVelocity = 100;
// 根據加速度計算當前速度
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
// 限制最大速度為 ± maxVelocity之間
directions if (playerVelocity.x > maxVelocity) {
playerVelocity.x = maxVelocity;
} else if (playerVelocity.x < - maxVelocity) {
playerVelocity.x = - maxVelocity;
}
}
現在,玩家速度由一個一次線性方程決定:
V= V ? * β + V ? * ε
其中,
V 為終速
V ? 為初速
β 為減速系數
V ? 為加速度
ε 為加速系數
其中, β 和 ε兩個系數(即減速度系數和加速度系數: deceleration和sensitivity變量)是兩個經驗值,你可以自己調整它以達到理想效果。
然后,需要通過以下方法來改變游戲角色的位置:
-(void) update:(ccTime)delta {
// 不斷改變角色x坐標
CGPoint pos = player.position;
pos.x += playerVelocity.x;
// 防止角色移到屏幕以外
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageWidthHalved = [player texture].contentSize.width * 0.5f; float leftBorderLimit = imageWidthHalved;
float rightBorderLimit = screenSize.width - imageWidthHalved;
if (pos.x < leftBorderLimit) {
pos.x = leftBorderLimit;
playerVelocity = CGPointZero;
} else if(pos.x > rightBorderLimit) {
pos.x = rightBorderLimit;
playerVelocity = CGPointZero;
}
player.position = pos;
}
然后,在 init方法中加入:
[self scheduleUpdate];
這樣,每隔一段時間 cocos2d會自動調用update方法。
六、添加障礙物
導入 spider.png圖片到工程。這是一張蜘蛛的圖片,在游戲中我們需要躲避的東西。
首先,增加如下變量聲明:
CCArray* spiders;
float spiderMoveDuration;
int numSpidersMoved;
在 init方法中,加上一句方法調用語句:
[self initSpiders];
下面是 initSpiders方法:
-(void) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
// 用一個臨時的CCSprider取得圖片寬度
CCSprite* tempSpider = [CCSprite spriteWithFile:@"spider.png"]; float imageWidth = [tempSpider texture].contentSize.width;
// 計算出要多少蜘蛛圖片可以布滿屏幕的寬度
int numSpiders = screenSize.width / imageWidth;
// 初始化數組并指定數組大小
spiders = [[CCArray alloc] initWithCapacity:numSpiders];
for (int i = 0; i < numSpiders; i++) {
CCSprite* spider = [CCSprite spriteWithFile:@"spider.png"]; [self addChild:spider z:0 tag:2];
[spiders addObject:spider];
}
[self resetSpiders];
}
tempSpider是一個臨時變量,我們僅用于取得圖片寬度。我們沒有retain他,也不需要release他——他會自動被release。
與此相反, spiders是由我們init的,我們也沒有retain(實際上init會自動retain),但我們必須自己release(OC規定,init/copy/new出來的對象,必須手動release,OC的內存管理不會自動release)。因此在dealloc方法中有這么一句:
[spiders release],spiders=nil;
同時,我們使用了 coco2d提供的一個類似NSMutableArray的CCArray類,該類對數組的操作更快。以下是CCArray提供的一些方法:
+ (id) array;
+ (id) arrayWithCapacity:(NSUInteger)capacity;
+ (id) arrayWithArray:(CCArray*)otherArray;
+ (id) arrayWithNSArray:(NSArray*)otherArray;
- (id) initWithCapacity:(NSUInteger)capacity;
- (id) initWithArray:(CCArray*)otherArray;
- (id) initWithNSArray:(NSArray*)otherArray;
- (NSUInteger) count;
- (NSUInteger) capacity;
- (NSUInteger) indexOfObject:(id)object;
- (id) objectAtIndex:(NSUInteger)index;
- (id) lastObject;
- (BOOL) containsObject:(id)object;
#pragma mark Adding Objects
- (void) addObject:(id)object;
- (void) addObjectsFromArray:(CCArray*)otherArray;
- (void) addObjectsFromNSArray:(NSArray*)otherArray;
- (void) insertObject:(id)object atIndex:(NSUInteger)index;
#pragma mark Removing Objects
- (void) removeLastObject;
- (void) removeObject:(id)object;
- (void) removeObjectAtIndex:(NSUInteger)index;
- (void) removeObjectsInArray:(CCArray*)otherArray;
- (void) removeAllObjects;
- (void) fastRemoveObject:(id)object;
- (void) fastRemoveObjectAtIndex:(NSUInteger)index;
- (void) makeObjectsPerformSelector:(SEL)aSelector;
- (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object;
- (NSArray*) getNSArray;
resetSpiders 方法如下所示:
-(void) resetSpiders {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
// 用一個臨時的CCSprider取得圖片寬度
CCSprite* tempSpider = [spiders lastObject];
CGSize size = [tempSpider texture].contentSize;
int numSpiders = [spiders count];
for (int i = 0; i < numSpiders; i++) {
// 放置每個蜘蛛的位置
CCSprite* spider = [spiders objectAtIndex:i];
spider.position =
CGPointMake(size.width * i + size.width * 0.5f,
screenSize.height + size.height);
[spider stopAllActions];
}
// 為保險起見,在注冊之前先從schedule中反注冊(未注冊則不動作)
[self unschedule:@selector(spidersUpdate:)];
// 注冊schedule,每0.7秒執行
[self schedule:@selector(spidersUpdate:) interval:0.7f];
}
-(void) {
// 找出空閑的蜘蛛(未在移動的).
for (int i = 0; i < 10; i++) {
// 從數組中隨機抽取一只蜘蛛
int randomSpiderIndex = CCRANDOM_0_1() * [spiders count];
CCSprite* spider = [spiders objectAtIndex:randomSpiderIndex];
// 若蜘蛛未在移動,讓蜘蛛往下掉
if ([spider numberOfRunningActions] == 0) {
// 控制蜘蛛往下掉
[self runSpiderMoveSequence:spider];
// 每次循環僅移動一只蜘蛛
break;
}
}
}
-(void) runSpiderMoveSequence:(CCSprite*)spider
{
// 隨時間逐漸加快蜘蛛的速度
numSpidersMoved++;
if (numSpidersMoved % 8 == 0 && spiderMoveDuration > 2.0f) {
spiderMoveDuration -= 0.1f;
}
// 移動的終點
CGPoint belowScreenPosition = CGPointMake(spider.position.x,
-[spider texture].contentSize.height);
// 動作:移動
CCMoveTo* move = [CCMoveTo actionWithDuration:spiderMoveDuration
position:belowScreenPosition];
// 瞬時動作:方法調用
CCCallFuncN* call = [CCCallFuncN actionWithTarget:self
selector:@selector(spiderBelowScreen:)];
// 組合動作:移動+方法調用
CCSequence* sequence = [CCSequence actions:move, call, nil];
// 運行組合動作
[spider runAction:sequence];
}
spiderBelowScreen方法重置蜘蛛的狀態,讓其回到屏幕上端等待下次墜落。
-(void) spiderBelowScreen:(id)sender {
// 斷言:sender是否為CCSprite.
NSAssert([sender isKindOfClass:[CCSprite class]], @"sender is not a CCSprite!");
CCSprite* spider = (CCSprite*)sender;
// 把蜘蛛重新放回屏幕上端
CGPoint pos = spider.position;
CGSize screenSize = [[CCDirector sharedDirector] winSize];
pos.y = screenSize.height + [spider texture].contentSize.height; spider.position = pos;
}
書中作者提到,出于一個“保守”程序員的習慣,作者使用了 NSAssert語句來測試sender是否是一個CCSprite類。雖然理論上,Sender應當是一個CCSprite,實際上它卻有可能根本不是。 因為作者曾犯過一個錯誤:把CCCallFuncN寫成了CCCallFunc(二者的區別在于,后者不能傳遞參數而前者帶一個sender參數),導致sender未被作為參數傳遞到調用方法,即sender=nil。這樣的錯誤也被NSAssert捕獲到了,于是作者發現并修改了這個錯誤。
七、碰撞檢測
很簡單。在 update方法中添加語句:
[self checkForCollision];
checkForCollision中包含了碰撞檢測的所有邏輯:
-(void ) checkForCollision {
// 玩家和蜘蛛的尺寸
float playerImageSize = [player texture].contentSize.width;
float spiderImageSize = [[spiders lastObject] texture].contentSize.width;
//玩家和蜘蛛的碰撞半徑
float playerCollisionRadius = playerImageSize * 0.4f;
float spiderCollisionRadius = spiderImageSize * 0.4f;
// 發生碰撞的最大距離,如果兩個對象間的距離<=此距離可判定為有效碰撞
float maxCollisionDistance=playerCollisionRadius +spiderCollisionRadius;
int numSpiders = [spiders count];
//循環檢測玩家和每一只蜘蛛間的碰撞距離
for (int i = 0; i < numSpiders; i++) {
CCSprite* spider = [spiders objectAtIndex:i];
// 計算每只蜘蛛和玩家間的距離. ccpDistance及其他非常有用的函數都列在 CGPointExtension中
float actualDistance = ccpDistance(player.position, spider.position);
// 如二者距離小于碰撞最大距離,認為發生碰撞?
if (actualDistance < maxCollisionDistance) {
// 結束游戲.
[self showGameOver];
}
}
}
-(void) showGameOver
{
// 屏保開啟
[self setScreenSaverEnabled:YES];
// 凍結所有對象的動作
CCNode* node;
CCARRAY_FOREACH([self children], node) {
[node stopAllActions];
}
// 使蜘蛛保持扭動
CCSprite* spider;
CCARRAY_FOREACH(spiders, spider) {
[self runSpiderWiggleSequence:spider];
}
// 游戲開始前,關閉加速器的輸入
self.isAccelerometerEnabled = NO;
// 允許觸摸
self.isTouchEnabled = YES;
// 取消所有schedule
[self unscheduleAllSelectors];
// 顯示GameOver文本標簽
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCLabel* gameOver = [CCLabel labelWithString:@"GAME OVER!" fontName:@"Marker Felt" fontSize:60];
gameOver.position = CGPointMake(screenSize.width / 2, screenSize.height / 3);
[self addChild:gameOver z:100 tag:100];
// 動作:色彩漸變
CCTintTo* tint1 = [CCTintTo actionWithDuration:2 red:255 green:0 blue:0];
CCTintTo* tint2 = [CCTintTo actionWithDuration:2 red:255 green:255 blue:0];
CCTintTo* tint3 = [CCTintTo actionWithDuration:2 red:0 green:255 blue:0];
CCTintTo* tint4 = [CCTintTo actionWithDuration:2 red:0 green:255 blue:255];
CCTintTo* tint5 = [CCTintTo actionWithDuration:2 red:0 green:0 blue:255];
CCTintTo* tint6 = [CCTintTo actionWithDuration:2 red:255 green:0 blue:255];
CCSequence* tintSequence = [CCSequence actions:tint1, tint2, tint3, tint4, tint5, tint6, nil];
CCRepeatForever* repeatTint = [CCRepeatForever actionWithAction:tintSequence];
[gameOver runAction:repeatTint];
// 動作:轉動、顫動
CCRotateTo* rotate1 = [CCRotateTo actionWithDuration:2 angle:3];
CCEaseBounceInOut* bounce1 = [CCEaseBounceInOut actionWithAction:rotate1];
CCRotateTo* rotate2 = [CCRotateTo actionWithDuration:2 angle:-3];
CCEaseBounceInOut* bounce2 = [CCEaseBounceInOut actionWithAction:rotate2];
CCSequence* rotateSequence = [CCSequence actions:bounce1, bounce2, nil];
CCRepeatForever* repeatBounce = [CCRepeatForever actionWithAction:rotateSequence];
[gameOver runAction:repeatBounce];
// 動作:跳動
CCJumpBy* jump = [CCJumpBy actionWithDuration:3 position:CGPointZero height:screenSize.height / 3 jumps:1];
CCRepeatForever* repeatJump = [CCRepeatForever actionWithAction:jump];
[gameOver runAction:repeatJump];
// 標簽:點擊游戲開始
CCLabel* touch = [CCLabel labelWithString:@"tap screen to play again" fontName:@"Arial" fontSize:20];
touch.position = CGPointMake(screenSize.width / 2, screenSize.height / 4);
[self addChild:touch z:100 tag:101];
// 動作:閃爍
CCBlink* blink = [CCBlink actionWithDuration:10 blinks:20];
CCRepeatForever* repeatBlink = [CCRepeatForever actionWithAction:blink];
[touch runAction:repeatBlink];
}
當然,為了使游戲一開始就停頓在 GameOver畫面,需要在init方法中調用:
[self showGameOver];
只有當用戶觸摸屏幕后,游戲才會開始。這需要實現方法:
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self resetGame];
}
resetGame方法負責重置游戲變量并啟動游戲。
-(void) resetGame
{
// 關閉屏保
[self setScreenSaverEnabled:NO];
// 移除GameOver標簽和啟動游戲標簽
[self removeChildByTag:100 cleanup:YES];
[self removeChildByTag:101 cleanup:YES];
// 啟動加速器輸入,關閉觸摸輸入
self.isAccelerometerEnabled = YES;
self.isTouchEnabled = NO;
// 重設蜘蛛數組
[self resetSpiders];
// 注冊schedule
[self scheduleUpdate];
// 積分
score = 0;
totalTime = 0;
[scoreLabel setString:@"0"];
}
開啟 /關閉屏保的方法:
-(void) setScreenSaverEnabled:(bool)enabled
{
UIApplication *thisApp = [UIApplication sharedApplication];
thisApp.idleTimerDisabled = !enabled;
}
使蜘蛛不停扭動的方法如下 (實際上是把圖像不斷的放大縮小):
-(void) runSpiderWiggleSequence:(CCSprite*)spider
{
//動作:放大
CCScaleTo* scaleUp = [CCScaleTo actionWithDuration:CCRANDOM_0_1() * 2 + 1 scale:1.05f];
//速度漸變動作:速度由慢至快,再由快至慢
CCEaseBackInOut* easeUp = [CCEaseBackInOut actionWithAction:scaleUp];
//動作:縮小
CCScaleTo* scaleDown = [CCScaleTo actionWithDuration:CCRANDOM_0_1() * 2 + 1 scale:0.95f];
//速度漸變動作:速度由慢至快,再由快至慢
CCEaseBackInOut* easeDown = [CCEaseBackInOut actionWithAction:scaleDown];
CCSequence* scaleSequence = [CCSequence actions:easeUp, easeDown, nil];
CCRepeatForever* repeatScale = [CCRepeatForever actionWithAction:scaleSequence];
[spider runAction:repeatScale];
}
八、 CCLabel、 CCBitmapFontAtlas 和 Hiero
我們的計分標準很簡單,以游戲時間作為游戲分數。
在 init方法中加入:
scoreLabel = [CCLabel labelWithString:@"0" fontName:@"Arial" fontSize:48];
scoreLabel.position = CGPointMake(screenSize.width / 2, screenSize.height);
// 調整錨點。
scoreLabel.anchorPoint = CGPointMake(0.5f, 1.0f);
// 把label添加到scene,z坐標為-1,則位于所有layer的下方
[self addChild:scoreLabel z:-1];
為了將計分牌對其到屏幕上端中心位置,這里使用了“錨點”的概念。 錨點即參考點,和 position屬性配合使用,用于將物體向其他物體對齊。比如當把一個物體移動到一個位置點時,實際上是把這個物體的“錨點”移動/對齊到另外一個點。錨點由兩個float表示,表示的是錨點相對于物體寬/高的比率。比如錨點(0.5f,1.0f)表示該錨點位于該物體寬1/2,高1/1的地方。
修改 update方法,在其中加入:
// 每秒更新一次計分牌
totalTime += delta;
int currentTime = (int)totalTime;
if (score < currentTime)
{
score = currentTime;
[scoreLabel setString:[NSString stringWithFormat:@"%i", score]];
}
這里需要說明的是, [CCLabel setString]方法的效率很低:它需要釋放老的texture,分配一個新的texture,并用iOS font的rendering方法重新構造texture。你只需要注釋[CCLabel setString]方法就可以知道,那有多么的糟糕。不使用setString方法時幀率為60幀/秒,而使用該方法的幀率竟然才30幀/秒。
象 CCSprite等刷新效率高(只是更費一點內存)的Label類,都是屬于 CCBitmapFontAtlas類的特例。我們可以通過簡單地把CCLabel變量聲明從CCLabel更改為 CCBitmapFontAtlas,并修改它的構造語句:
scoreLabel = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"0" fntFile:@"bitmapfont.fnt"];
在游戲中使用 bitmapfont是很好的選擇,因為操作更快速,同時會有一個缺點:bitmap字體都是大小固定的。如果同樣的字體,大小不同,你需要對CCBitmapFontAtlas 對象進行縮放。或者為不同尺寸的字體創建單獨的bitmap文件,并因此占用更多的內存。
當然需要把 bitmapfont.fnt文件和對應的.png文件一起加入到工程的資源目錄下。
如果你需要創建自己的 bitmap字體,可以用Hiero這個小工具(java web application):
http://slick.cokeandcode.com/demos/hiero.jnlp
也可以使用 BMFont (windows應用):
www.angelcode.com/products/bmfont/
Hiero允許你從TrueTypeFont創建一個.fnt文件,該文件可以直接用于 cocos2d的CCBitmapFontAtlas類。
安裝 Hiero時需要同意一個數字簽名 。請放心,迄今為止沒有跡象表明該簽名有任何問題。
Hiero的使用很簡單,首先挑選一種TrueType字體,在Sample Text 文本框中輸入你要用的字符,然后點擊File->Save BMFont Files…即可保存為.fnt文件。
其他的選項是可選的。比如你可以加上漸變和陰影效果,使字體顯得更 3D。
選擇 Glyph cache后,你還可以調整生成的.png文件的大小。 當然,如果你象我一樣只用到了極少的幾個字符,只要把頁寬/高設為最小值(比如在這里我們設成了256),然后點擊Reset Cache應用。這樣可以創建比較小.png文件同時減少內存占用。對于更復雜的字體,Hiero會創建多個.png文件——記住,每一個.png文件都應當加到工程中。
在這個例子里,我們的字體文件里只放了幾個數字。因為png文件被創建為256*256大小,不管你是輸入1個字還是再加幾個其他的字,都會占用這么多的空間。
*注意,如果你使用了在.fnt文件中不存在的字符,那么該字符會被忽略掉,且不會顯示在 CCBitmapFontAtlas中 。
九、加入音頻
在工程目錄中有一對音頻文件: blues.mp3 和 alien- sfx.caf 。
在cocos2d中播放音頻的最好也是最初的方法是用 SimpleAudioEngine。然而音頻支持并不是cocos2d內置的一部分。它屬于CocosDenshion,就像物理引擎一樣。因此,你需要import額外的頭文件:
#import "SimpleAudioEngine.h"
然后可以在init方法中象這樣來播放音樂/音頻:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"blues.mp3" loop:YES];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"alien-sfx.caf"];
對于背景音樂,我們設置loop參數為YES,這樣就會循環播放。
對于音頻聲效,我們并沒有立即播放,而僅僅是加載到內存。然后在條件合適時播放(比如碰撞發生時):
[[SimpleAudioEngine sharedEngine] playEffect:@"alien-sfx.caf"];
對于音樂,最好使用mp3格式。注意,同一時間內,只能播放1首背景音樂。雖然同時播放多首mp3從技術上是可行的,但物理硬件在同一時間內只能對一首mp3進行解碼。在游戲中拒絕任何額外的CPU開銷,因此對大部分游戲而言,都不會同時播放多首mp3.
至于聲效,我喜歡用CAF格式。如果要進行音頻格式的轉換,可以使用 SoundConverter:
http://dekorte.com/projects/ shareware/SoundConverter/
如果文件大小在500k以內,該軟件是免費的,無限制的許可僅僅需要$15。
如果你發現無法播放音頻文件或者出現雜音,不要擔心。有無數音頻軟件和音頻編碼擁有它們特有的文件格式。有些格式無法在iOS設備上播放,然而在其他設備上播放正常。解決辦法是打開它們,然后重新保存。或者使用音頻轉換程序或音頻軟件。
十、遷移至iPad
如果所有的坐標都采用屏幕坐標,在iPad的大屏上運行游戲將會進行簡單縮放而沒有任何問題。相反,如果采用了固定坐標,你不得不重新編寫游戲代碼。
遷移至iPad工程很簡單。在Groups&Files面板中選擇Target,選擇Project->Upgrade Current Target for iPad…,將打開對話框:
對于這個游戲,選“One Universal application”(即iPhone/iPad通用)。
這樣的缺點是兩個設備的特性都會被加到target,增加了程序大小。但程序既可在iPhone上運行,也可在iPad上運行。
另一個選擇是“Two device-specific application”,你會得到兩個獨立于設備的app,你需要提交兩次。如果用戶有兩個設備—— iPhone和iPad的,那么需要分別購買。
編譯運行。程序會自動偵測當前所連接的設備類型并運行對應的版本。如圖,選擇iPad Simulator 3.2 ,可以查看在iPad模擬器運行游戲的效果:
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
