今天把子彈的釋放機制改了一下,設置為碰撞N次或持續一段時間後消亡(自殺)。
難點就是自殺這塊,很難保證自殺後不再“回魂”。
找了很久終於發現了哪個語句在“叫魂”:
這句話就是毛病所在,如果在物體的ActionUpdate內部釋放了自己,那麼下一句 pNew = pNew->pNext就出問題了,指向了一段釋放掉了的空間。所以我做了如下修改:
很經典很老套的方法,但是百試不爽。順利自殺。(這年頭不好混啊,自殺都不容易)
2015/ 03/27
***********************************
終於寫出來了,比預計的晚了一點,一直在修BUG,上圖:
圖片說明:
點鼠標左鍵,就會沿著攝像機視線發射一枚子彈,速度、子彈種類都需要事先設定。我下面貼下代碼。
為了防止子彈數目過多,以及子彈間隔過短,產生粘連(粘連這個問題我現在還沒徹底解決呢),設置一個子彈的冷卻時間,以及子彈的定時回收機制。
我這裡是將子彈統一回收的,不是每個子彈都帶一個定時器(可以帶,那是另一種子彈)。
*********************************************************************
技術相關:
稍微觀察,就明白了,子彈就是一個堆,先入先出(僅限於我選擇的這種,帶定時器的子彈可以是鏈表,任意刪除)。然後子彈占得內存空間不能過大,所以需要一個meshCopy類,我寫了兩個copy類,MeshCopy和MeshCopyNew, 不同之處在於MeshCopyNew會創建一個完全獨立的空間,不受母體影響。MeshCopy則與母體共用一部分內存空間(頂點、貼圖)。母體釋放掉,copy對象必須釋放。這個過程如果寫成任意刪除的模式,好麻煩,感覺得不償失。就把他們整到一起了,整個MeshCopy堆全部是一個整體,就是現在看到的Bullet類,Bullet負責新子彈的添加與刪除,同時子彈有各自獨立的“意識”,執行不同的任務。這樣看起來省事了許多。其實速度也提快了很多。
注意事項:寫堆的時候要注意,內存要釋放干淨。
下面是一部分代碼,只貼這麼多,杜絕懶癌症蔓延。
——————————————————————————————————————————————————
定時發射子彈代碼:
1 static float t_base_bullet = 0.0f, t_cur_bullet = 0.0f; 2 3 if(GetMouse().GetState() == LKEY_PRESSED) 4 { 5 t_cur_bullet = mTimer->getGameTime(); 6 if( (t_cur_bullet - t_base_bullet) >= BULLET_TIME_GAP) 7 { 8 gBullet->CreateOneBullet(curScene->GetObjList(), *gCrashList, GetCamera().position(), GetCamera().GetLook()); 9 t_base_bullet = t_cur_bullet; 10 } 11 }
定時回收子彈代碼(與定時發射有些微不同,只是一個小聰明而已,不難理解):
1 void Bullet::ActionUpdate(float dt) 2 { 3 // 定時回收子彈資源 4 static float t_base_bullet = 0.0f, t_cur_bullet = 0.0f; 5 6 if(!existBullet) 7 { 8 // 一個子彈也沒有的時候 9 t_base_bullet = t_cur_bullet = mTimer->getGameTime(); 10 return ; 11 } 12 13 if(pHead->pNext) 14 { 15 t_cur_bullet = mTimer->getGameTime(); 16 if( (t_cur_bullet - t_base_bullet) >= BULLET_LIFE_TIME) 17 { 18 DeleteOneBullet(); 19 20 // 計時 21 t_base_bullet = t_cur_bullet; 22 } 23 } 24 }
子彈的增刪,我使用了一點PV操作的知識。
創建子彈代碼:
1 void Bullet::CreateOneBullet(DemoList& paintList, CrashList& crashList, D3DXVECTOR3& position, D3DXVECTOR3& speed) // 創建一個子彈 2 { 3 // V操作 4 // 如果不存在子彈,就設置存在,如果存在,不修改該值 5 existBullet |= true; 6 7 MeshCopy* pNew = new MeshCopy(); 8 pNew->Copy( *bulletTypeArray[curBulletTypeIndex] ); 9 pNew->SetPosition(position); 10 pNew->SetSpeed(speed * mSpeed); 11 pNew->OpenCrash(); 12 13 pNew->SetMass(1.0f); 14 15 paintList.AddObj(pNew); 16 crashList.AddObj(pNew); 17 18 pTail->pContent = pNew; 19 20 pBulletPoint pP = (pBulletPoint)malloc(sizeof(BulletPoint)); 21 pP->pContent = NULL; 22 pP->pNext = NULL; 23 24 pTail->pNext = pP; 25 pTail = pP; 26 27 }
刪除子彈代碼
1 void Bullet::DeleteOneBullet() // 堆,先進先出刪除 2 { 3 if(pHead == pTail) 4 { 5 // 堆為空 6 // P操作 7 existBullet = false; 8 return; 9 } 10 11 static pBulletPoint pT; 12 13 pT = pHead->pNext; 14 15 delete(pHead->pContent); 16 17 free(pHead); 18 pHead = pT; 19 }
————————————————————————————————————————-
好了,本文到此結束吧, 希望對讀者們有用。
下一階段,添加一下音樂,以及實現說好的《是男人就點100下》!順手再做個CS設計視角的子彈Demo。
(關於Demo中出現的粘連的BUG,源頭正在查找,如果讀者有什麼發現,希望不吝賜教,謝謝了!orz)
——————————————————————————————-
本章演示Demo下載鏈接(百度網盤,用的次數不多,如果鏈接壞了,希望讀者能及時通知我):
http://pan.baidu.com/s/18R6iU