游戲還沒做完,不但沒有做完,而且還差相當多的東西!
由於之前沒有仔細考慮過關卡文件後期的拓展性,以至於很多預想的游戲元素都無法通過關卡文件添加到游戲裡面
此數日主要用來對這些問題進行整改
整改之前也狠狠想了一段時間,根據游戲後面的邏輯,還需要加入哪些元素,
怎麼在關卡裡面為這些元素預留初始化的數據,等等
可以說,游戲看上去雖然簡單,但是一步步的走下來,每一個步伐都不那麼輕松
希望能認真做好一件事的態度、豐厚的回報以及游戲慢慢展現出來的效果,這些都給我帶來了很大的動力!
今天遇到一個bug,有很奇葩的地方,待我貼兩段代碼看一下就知道奇葩在什麼地方了:
片段1:
-(void) tick: (ccTime) dt {
if(_single.cutCount <_maxCutCount && !_drawing &&_laserSegment) {//在更早的時候消除可能報出的錯誤,提高程序性能~
b2Vec2 p1 =_laserSegment.p1;
b2Vec2 p2 =_laserSegment.p2;
float segmentLength = sqrt(pow(p2.y - p1.y,2.0f) +pow(p2.x - p1.x,2.0f));
if(segmentLength >=2.0f) { // 如果劃線的長度超過64個像素(retina裡面是128個像素)~
{
NSLog(@"1");
RayCastCallbackPrepare prepareCallback;
_world->RayCast(&prepareCallback, _laserSegment.p1, _laserSegment.p2);
_world->RayCast(&prepareCallback, _laserSegment.p2, _laserSegment.p1);
NSLog(@"2");
}
NSLog(@"3");
BOOL isCutValid = [self checkCutValidOrNot:_laserSegment.p1p2:_laserSegment.p2];
片段2:
#import"RayCastCallbackPrepare.h"
/** 相信我,會有的!! */
int fixtureIndexInVector(vector<b2Fixture*> *v,b2Fixture *fixture);
int bodyIndexInVector(vector<b2Body*> *v,b2Body *body);
/** 構造 */
RayCastCallbackPrepare::RayCastCallbackPrepare() {
NSLog(@"RayCastCallbackPrepare構造開始~");
_single = [BYSinglegetInstance];
_validCallbackTimes =0;
_affectedBodyByLaser =newvector<b2Body*>();
_affectedBodyByLaserFinal =newvector<b2Body*>();
_affectedByLaser =newvector<b2Fixture*>();
_balloonsBeenCutted =newvector<b2Body*>();
[_singlesetIsPirateExists:NO];
[_singlesetIsBalloonBeenCutted:NO];
NSLog(@"RayCastCallbackPrepare構造結束~");
}
/**
* 析構
* 因為回調函數的特殊性,如果不想在每次回調的時候都對單例對象設置一次值的話
* 唯有在析構方法裡面完成最後一次設置(因為回調的次數是難以確定的)
* 這也就是 GoldMineScene 中raycast方法調用的那幾行必須用小括號包起來的原因!!!
* 因為要即時析構獲得計算出來的結果!!!
*/
RayCastCallbackPrepare::~RayCastCallbackPrepare() {
NSLog(@"RayCastCallbackPrepare析構開始~");
[_singlesetReverseDirectionCallbackTimes:_validCallbackTimes];
[_singlesetAffectedBodyByLaserFinal:_affectedBodyByLaserFinal];
// vector的釋放需要謹慎處理~
for(uint i = 0; i < _affectedBodyByLaser->size(); ++ i) {
//斷絕關系(用不著銷毀,銷毀由world所維護),避免SOA池出現內存故障~
_affectedBodyByLaser->at(i) =NULL;
}
_affectedBodyByLaser->clear();
_affectedBodyByLaser =NULL;
// vector的釋放需要謹慎處理~
for(uint i = 0; i < _affectedByLaser->size(); ++ i) {
_affectedByLaser->at(i) = NULL;
}
_affectedByLaser->clear();
_affectedByLaser =NULL;
// vector的釋放需要謹慎處理~
for(uint i = 0; i < _balloonsBeenCutted->size(); ++ i) {
_balloonsBeenCutted->at(i) =NULL;
}
_balloonsBeenCutted->clear();
_balloonsBeenCutted =NULL;
NSLog(@"RayCastCallbackPrepare析構結束~");
}
float32RayCastCallbackPrepare::ReportFixture(b2Fixture* fixture, const b2Vec2& point,constb2Vec2& normal,float32 fraction) {
NSLog(@"-3");
b2Body *affectedBody = fixture->GetBody();
if(affectedBody->GetType() != b2_staticBody) {
if(affectedBody->m_isCuttable == true) {
if(fixture->m_isPirate == true) {
[[BYSinglegetInstance]setIsPirateExists:YES];
}
//只要累加出所切割 fixture的次數就 ok了,保存在單例裡面是為了擴大使用的界限~
int fixtureIndex = fixtureIndexInVector(_affectedByLaser, fixture);
if(fixtureIndex == -1) {
//正方向切割的時候僅僅將受影響的body、切入點保存起來,沒有繪制任何圓圈
_affectedByLaser->push_back(fixture);
} else {
_validCallbackTimes += 1;
}
/**得到所有被切割路徑涉及到的 body(目的是為了消除切割之後出現內部黑邊)~ */
int bodyIndex = bodyIndexInVector(_affectedBodyByLaser, affectedBody);
if(bodyIndex == -1) {
_affectedBodyByLaser->push_back(affectedBody);
} else {
//這才是最後要遞交給 _single的~
_affectedBodyByLaserFinal->push_back(affectedBody);
}
} else if(affectedBody->m_isBalloon ==true) {
NSLog(@"-4");
int bodyIndex = bodyIndexInVector(_balloonsBeenCutted, affectedBody);
if(bodyIndex == -1) {
NSLog(@"不存在,添加進去");
_balloonsBeenCutted->push_back(affectedBody);
} else {
NSLog(@"存在,進行處理~");
//這才是最後要遞交給 _single的~
[_singlesetIsBalloonBeenCutted:YES];
CCSprite *actor = (CCSprite*)affectedBody->GetUserData();
CGPoint position = actor.position;
[_single.gameLayerremoveChild:actorcleanup:YES];
NSLog(@"asf begin!");
AnimSpriteFactory *asf = [[[AnimSpriteFactoryalloc]init]autorelease];
CCSprite *animSprite = [asf genAnimSprite:position
animName:[_single.gCfgobjectForKey:@"balloonAnimName"]
startIndex:[[_single.gCfgobjectForKey:@"balloonAnimBegin"]intValue]
endIndex:[[_single.gCfgobjectForKey:@"balloonAnimEnd"]intValue]
repeatForever:NO
delay:[[_single.gCfgobjectForKey:@"balloonAnimDelay"]floatValue]];
NSLog(@"asf finished!");
affectedBody->SetUserData(animSprite);
_single.gameSceneWorld->DestroyBody(affectedBody);
// 即時播放氣球爆炸的音效~
[[AudioManagergetInstance]musicBalloonExplode];
}
NSLog(@"-5");
}
}
return 1.0f;
}
運行之後控制台打印出的部分關鍵信息為:
2012-01-06 18:19:24.289 GoldMine0.6[818:10a03] 1
2012-01-06 18:19:24.290 GoldMine0.6[818:10a03] RayCastCallbackPrepare構造開始~
2012-01-06 18:19:24.291 GoldMine0.6[818:10a03] RayCastCallbackPrepare構造結束~
2012-01-06 18:19:24.292 GoldMine0.6[818:10a03] -3
2012-01-06 18:19:24.292 GoldMine0.6[818:10a03] -4
2012-01-06 18:19:24.293 GoldMine0.6[818:10a03]不存在,添加進去
2012-01-06 18:19:24.294 GoldMine0.6[818:10a03] -5
2012-01-06 18:19:24.294 GoldMine0.6[818:10a03] -3
2012-01-06 18:19:24.295 GoldMine0.6[818:10a03] -4
2012-01-06 18:19:24.296 GoldMine0.6[818:10a03]存在,進行處理~
2012-01-06 18:19:24.297 GoldMine0.6[818:10a03] asf begin!
2012-01-06 18:19:24.304 GoldMine0.6[818:10a03] RayCastCallbackPrepare析構開始~
2012-01-06 18:19:24.305 GoldMine0.6[818:10a03] RayCastCallbackPrepare析構結束~
2012-01-06 18:19:24.306 GoldMine0.6[818:10a03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x197d052 0x1b0ed0a 0x196a36e 0x196b220 0x3fb0d 0x15a0d 0x27e31 0x28240 0x2612e 0x6f3a 0x6a26a 0x6a678 0x7c80e 0x7b795 0x92c2db 0x92c1af 0x1951966 0x1951407 0x18b47c0 0x18b3db4 0x18b3ccb 0x2384879 0x238493e 0x9e1a9b 0x295b 0x2905)
terminate called throwing an exceptionsharedlibrary apply-load-rules all
(gdb)
結果表明:
是 AnimSpriteFactory(用於生成帶動畫的 sprite 對象) 這個對象在調用 genAnimSprite 方法的時候出現了問題,然而,需要注意的是:
在 RayCastCallbackPrepare 對象執行其 ReportFixture 方法的時候,出現了bug,
為什麼程序沒有在出現 bug 的地方即時中斷,
還能執行到 RayCastCallbackPrepare 對象執行析構函數的時候?
這個讓我非常不解,難道不是在哪個地方一出現問題就馬上終止程序麼?
這個問題的答案我沒有找到
但是,bug的出現原因我卻是找到了!
這是一個典型的偽 bug,說他是偽 bug 就是因為:
app 通常針對不同的設備會使用不同規格的素材圖片,
我之前用的是 iTouch4 做的真機測試,那麼就是用的高清的那套素材圖片~
不過這二日我伙計把設備拿過去了,因此我也就只能用 mac裡面的模擬器來進行調試了
mac裡面模擬器的分辨率是480*320,使用的是普通的那套素材圖片
而我之前又偷懶,因此普通的那套素材便沒有准備,
這在真機上面沒有妨害,但是到了mac的模擬器裡面,卻是帶來了直接的隱患
這次果不其然便中招了
另外一個原因就是我最近又有所懈怠,
好一段時間不寫,有些問題如沒准備普通素材這件事便給拋到腦後了~
仔細做總結,其實我遇到過很多次控制台打出這樣的信息,但是我依然是死豬不怕開水燙,這次,牢牢的記住這兩句提示吧:
2012-01-06 18:19:24.306 GoldMine0.6[818:10a03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x197d052 0x1b0ed0a 0x196a36e 0x196b220 0x3fb0d 0x15a0d 0x27e31 0x28240 0x2612e 0x6f3a 0x6a26a 0x6a678 0x7c80e 0x7b795 0x92c2db 0x92c1af 0x1951966 0x1951407 0x18b47c0 0x18b3db4 0x18b3ccb 0x2384879 0x238493e 0x9e1a9b 0x295b 0x2905)
terminate called throwing an exceptionsharedlibrary apply-load-rules all
(gdb)
一旦出現了這樣的提示,
很有可能就是因為與 sprite 動畫相關的代碼出現了問題,
要第一時間去檢查這部分代碼!!