八.發射子彈
我們前期的準備基本上已經完成了。發射臂已經準備就緒了。接下來,開始創建子彈!並且通過發射器發射子彈!
1. 在世界中加入子彈
首先創建一個子彈類Bullet.java類,實現BodyInterface 接口。實現方式與發射器類catapultArm.java類似,此處略。
首先創建所需的變量:
//用於存放子彈對象的集合 private Set<Body> bullet = new HashSet< Body >(); private final int BulletCount = 4; //子彈數量 private Bitmap bulletBitmap; //子彈圖片
在MainView.java主類中,編寫創建子彈CreateBulletBody方法
/** * 創建子彈 * @param bitmap * @param x * @param y * @param width * @param height * @param isStatic * @return */ public void createBulletBody(int count) { float pos = 62.0f; //子彈距離場景左端的位置 if(count >0) { float delta = 50f; //子彈之間的間隔 for(int i=0;i<count;i++, pos += delta) { PolygonShape pd = new PolygonShape(); //創建一個多邊形的物體 Vec2[] vec2s = new Vec2[6]; vec2s[0] = new Vec2(-0.6f, 0.66f); vec2s[1] = new Vec2(-0.8f, -0.2f); vec2s[2] = new Vec2(-0.28f,-0.88f); vec2s[3] = new Vec2(0.4f,-0.6f); vec2s[4] = new Vec2(0.88f,-0.1f); vec2s[5] = new Vec2(0.4f,0.82f); pd.set(vec2s, 6); FixtureDef fd = new FixtureDef(); fd.shape = pd; fd.density = 1; fd.friction = 0.8f; fd.restitution = 0.3f; BodyDef db= new BodyDef(); db.position.set(pos/RATE, (ScreenH-FLOOR_HEIGHT-50f)/RATE); db.type = BodyType.DYNAMIC; db.bullet = true; //表示這是個高速運轉的物體,需要精細的模擬 Body body = world.createBody(db); body.m_userData = new Bullet(bulletBitmap, pos, FLOOR_HEIGHT+15.0f,30,30, 0); body.createFixture(fd); bullet.add(body); } } }
子彈的物體創建完成了,接下來就需要在logic()與draw()方法中進行子彈的邏輯模擬以及繪畫,在這裏就不在贅述。
此時可以運行遊戲,查看一下效果。可以看到遊戲開始,子彈在半空中下落到地面。與現實世界似乎相同。
2. 子彈上膛
現在已經成功把子彈添加到了模擬世界中。接下來我們要讓子彈上膛,讓子彈和發射器綁定在一起。這時候我們需要引進第三個關節---焊接關節。顧名思義,就是我們需要把子彈焊接在發射器上。
首先創建所需要的變量。
private WeldJoint wj;//焊接關節
然後創建createWeldJoint()創建焊接關節的方法。
//創建焊接關節 public WeldJoint createWeldJoint() { Body body; Iterator<Body> aIterator = bullet.iterator(); //使用迭代器取出set集合中的數據 while (aIterator.hasNext()) { //判斷時候還有數據 body = aIterator.next(); //獲取下一個數據,第一次是獲取第一個數據 body.setTransform(new Vec2((360f/RATE), (ScreenH-FLOOR_HEIGHT-bulletBitmap.getHeight()-227)/RATE), 0); WeldJointDef wd = new WeldJointDef(); wd.initialize(body, catapultArmBody, catapultArmBody.getWorldCenter()); return (WeldJoint) world.createJoint(wd); } return null; }
方法創建完成之後,在surfaceCreated()方法中調用。
wj = createWeldJoint();
此時焊接關節創建完成。運行遊戲。可以看到效果。
3. 發射子彈
此時子彈已經上膛了。可以推動發射器看一下效果。子彈可以跟隨發射器一起移動。但是這也不是我們想要的效果。我們需要的效果是推動發射器,然後發射器復原的時候憑藉恢復力把子彈發射出去。接下來就去完成發射子彈的功能。
完成這個功能我們之需要在發射器恢復到一定角度的時候,銷燬焊接關節,使子彈脫離發射器。這樣就可以完成子彈的發射。
首先創建所需要的變量。
private boolean catapult_flag = false;//推動發射器標示
這個變量的目的用於防治觸摸到發射器,變使子彈發射的bug。只有推動發射器到達一定角度是,纔算推動了發射器。
接下來需要在logic()邏輯方法中,進行判斷。
//推動發射器到一定一角度 if(catapultArmBody.getAngle()< - (float) (30f*Math.PI/180)) { catapult_flag=true; } if(wj != null&&catapult_flag) { if(catapultArmBody.getAngle()>=-(float) (10f*Math.PI/180)){ world.destroyJoint(wj);//銷燬焊接關節 wj = null; } }
這裏我們默認只有推動發射器到達30°的時候才能發射子彈。並且當發射器恢復到10°的時候,銷燬焊接關節。此時子彈發出。運行遊戲可以看下效果。
4.子彈續膛
當一個子彈被我們發射出去之後,問題也就隨之而來了。對!剩下的子彈怎麼辦。我們接下來就完成,子彈續膛!
這裏需要考慮兩個問題。
- 何時銷燬已經發射的子彈?
- 何時讓新的子彈續膛?
何時銷燬子彈,可以設定兩種情況,第一種當子彈超出場景的範圍,第二種當子彈在場景內靜止時。這兩種情況滿足一種便可銷燬子彈。
何時讓薪資單續膛,這裏考慮兩種情況,第一種當前一個子彈脫離發射器時續膛。第二種是當前一個子彈銷燬時續膛。這裏第一種情況會出現一個bug。當前一個子彈脫離發射器,續膛的子彈會瞬間與發射器進行焊接,這樣會影響前一個子彈的運行軌道。所以在這裏才需第二種方式。
首先定義變量。
private boolean moveing_flag = false; //子彈是否處於移動狀態
接下來就是要判斷髮射的子彈時候靜止或者超出了場景範圍,需要在logic方法中進行判斷。
if(bullet.iterator().hasNext())//首先判斷時候還有爲發射的子彈 { //只要發射的子彈靜止或者超出了場景範圍就執行 if(!bullet.iterator().next().isAwake()||bullet.iterator().next().getPosition().x*RATE>background_bottom.getWidth()) { moveing_flag = false; } }
並且要在銷燬焊接關節的方法中,加入一條語句。是moveing_flag初始化。
moveing_flag = true;
然後我們在logic方法中編寫子彈續膛的方法。
//子彈續膛 if(wj == null&&!bullet.isEmpty()&&!moveing_flag) { //銷燬已經發出去的子彈 world.destroyBody(bullet.iterator().next()); bullet.remove(bullet.iterator().next()); catapult_flag = false; wj = createWeldJoint();//創建新的焊接關節 }
此時子彈續膛的功能已經完成。可以運行遊戲進行測試。
下一章節,我們將創建移動的鏡頭,添加目標。盡請期待!~~