今天把子彈的釋放機制改了一下,設置為碰撞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