惱人的偽bug!

來源:互聯網
上載者:User

遊戲還沒做完,不但沒有做完,而且還差相當多的東西!
由於之前沒有仔細考慮過關卡檔案後期的拓展性,以至於很多預想的遊戲元素都無法通過關卡檔案添加到遊戲裡面
此數日主要用來對這些問題進行整改
整改之前也狠狠想了一段時間,根據遊戲後面的邏輯,還需要加入哪些元素,
怎麼在關卡裡面為這些元素預留初始化的資料,等等
可以說,遊戲看上去雖然簡單,但是一步步的走下來,每一個步伐都不那麼輕鬆
希望能認真做好一件事的態度、豐厚的回報以及遊戲慢慢展現出來的效果,這些都給我帶來了很大的動力!

今天遇到一個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 動畫相關的代碼出現了問題,
要第一時間去檢查這部分代碼!!


摘自 yang3wei的專欄

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.