我也做雷電
剛做完雷電小遊戲,現在總結一下。雷電小遊戲中我想核心的東西就是多執行緒的運用,做雷電就是為了能夠熟練的使用多執行緒,加深對執行緒執行過程的理解。至於現在對於多執行緒有了一定的瞭解,但不能說已經記載了血液中,能夠使用多執行緒做出雷電,是趁熱打鐵的原因,如果在過幾天做的話,我估計就會麻煩很多了。所以自己不看書不行。
正在執行的程式成為程序,在一個程序中,有多個執行緒,其中有個主執行緒,就是主函式,這個主執行緒負責啟動整個程式;程式裡面還存在很多其他的執行緒,比如負責重新整理的執行緒,加背景音樂的執行緒,在雷電中有發射子彈的執行緒,敵機進攻的執行緒等。他們的啟動有物件呼叫start();方法開始,這些執行緒所要執行的內容放在
下面說一下做雷電遊戲。這個雷電中,飛機的移動和子彈的發射可以同時進行,所以每一個都應該是執行緒,對方的飛機(不止一個,放在一個執行緒裡面)對方飛機發射子彈(也放在一個執行緒裡面)。這是最初的想法,很顯然是對的,後面再加一句就是,由飛機來啟動子彈執行緒,飛機的位置就是子彈的初始位置。當然一開始就是飛機移動一下就發射一個子彈,結果就是子彈太快了,然後改進了一下,飛機移動10下在發射一個子彈,這樣看起來就比較舒服。
現在說一下玩家的情況,空格鍵控制子彈的發射,上下左右鍵控制飛機的運動,當然用的就是鍵盤監聽器,關於它的使用方式是臨時問的同學很簡單。裡面有三個方法keyTyped();
程式碼
// 重寫鍵盤的方法 public void keyPressed(KeyEvent e) { x0=0; y0=0; isdisappear = false; ImageIcon img,img1; img1=addpic1(); img = addmypic(); // 按空格鍵控制發射子彈 if (e.getKeyCode() == KeyEvent.VK_SPACE) { //重寫設定子彈發射的位置 //呼叫子彈發射的方法 isstart=true; // mymis.ismisstart=false; // mymis.ismisdis = false; } // 按左鍵向左移動 if (e.getKeyCode() == KeyEvent.VK_LEFT) { x0=-8; if(isLeftOutbound){ x0=0; } if(x<=0){ isLeftOutbound=true; } if(x>0){ isLeftOutbound=false; } } //按右鍵 向右移動 if (e.getKeyCode() == KeyEvent.VK_RIGHT) { x0=+8; if(isRightOutbound){ x0=0; } if(x>=650){ isRightOutbound=true; } if(x<650){ isRightOutbound=false; } } //向上移動 if (e.getKeyCode() == KeyEvent.VK_UP) { y0 =-8; if (isUpOutbound) { y0=0; } if (y <= 60) { isUpOutbound = true; } if (y > 60) { isUpOutbound = false; } } //向下移動 if (e.getKeyCode() == KeyEvent.VK_DOWN) { y0 =+8; if (isDownOutbound) { y0=0; } if (y >= 490) { isDownOutbound = true; } if (y < 490) { isDownOutbound = false; } } g.drawImage(img1.getImage(), x, y, 40, 40, null); g.drawImage(img.getImage(), x+=x0, y+=y0,40,40, null); //用空格鍵控制子彈的發射 if (isstart) { minmis pm = new minmis(g, x, y,false ); Thread pmh = new Thread(pm);// 包裝成執行緒 pmh.start();// 啟動執行緒 mymis.add(pm); try { Thread.sleep(50); } catch (Exception d) { d.printStackTrace(); } } } //用空格鍵控制子彈的發射情況 public void keyReleased(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_SPACE){ isdisappear = false; Drawliskey.isstart=false; // mymis.ismisstart=true; } // Esc鍵退出 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { System.exit(0); } }
還有就是重繪的問題,當我們用一個執行緒去控制介面的重新整理,就會出現螢幕狂閃的情況,這時我們就要用到雙緩衝,非輕量級元件不需要雙緩衝,就是不用update();函式,雙緩衝的順序是update,paint,repaint,這些方法要放在輕量級元件中。在雷電中我是把所有的東西放在了JPanel上,所以,這些方法要在JPanel 的基礎去呼叫。
程式碼
// 重寫繪製自己的飛機
public void paintmyair(Graphics g) {
// 重新繪製自己的飛機
ImageIcon myimg = Drawliskey.addmypic();
g.drawImage(myimg.getImage(), Drawliskey.x, Drawliskey.y, 40, 40, null);
}
// 重寫繪製敵人的飛機的方法
public void paintair(Graphics g) {
ImageIcon eneair = stealPlane.addpic();
for (int j = 0; j < nair.size(); j++) {
g.drawImage(eneair.getImage(), nair.get(j).x, nair.get(j).y, 50,
50, null);
}
}
// 重寫繪製敵人子彈的方法
public void paintenemmis(Graphics g) {
// 重新繪製敵機的子彈
ImageIcon misimg = enemis.addpicmis1();
for (int i = 0; i < airmis.size(); i++) {
g.drawImage(misimg.getImage(), airmis.get(i).x, airmis.get(i).y,
10, 10, null);
}
}
// 重新繪製玩家子彈的方法
public void paintmymis(Graphics g) {
// 重新繪製玩家的子彈
ImageIcon mymisimg = minmis.addpicmis();
for (int m = 0; m < mymis.size(); m++) {
g.drawImage(mymisimg.getImage(), mymis.get(m).x, mymis.get(m).y,
10, 10, null);
}
}
class MyPanel extends JPanel {
// 重寫update方法,先將窗體上的圖形畫在圖片物件上,再一次性顯示
public void update(Graphics g) {
// URL url = this.getClass().getResource("img/15.jpg");
// javax.swing.ImageIcon img1 = new javax.swing.ImageIcon(url);
ImageIcon img1;
img1 = Drawliskey.addpic1();
g.drawImage(img1.getImage(), 0, 0, 680, 535, null);
if (offScreenImage == null) {
// 擷取窗體所在位置的圖片
offScreenImage = this.createImage(680, 535);
}
// 獲得擷取圖片的畫布
Graphics gImage = offScreenImage.getGraphics();
// 獲取畫布的底色並且使用這種顏色填充畫布
// Color c = Color.BLACK;
gImage.drawImage(img1.getImage(), 0, 0, 680, 535, null);
// gImage.fillRect(0, 0, 780, 640); //
// 有清除上一步影象的功能,相當於gImage.clearRect(0,
// // 0, WIDTH, HEIGHT)
// 將截下的圖片上的畫布傳給重繪函式,重繪函式只需要在截圖的畫布上繪製即可,不必在從底層繪製
paint(gImage);
// 將接下來的圖片載入到窗體畫布上去,才能看到每次畫的效果
g.drawImage(offScreenImage, 0, 0, null);
}
public void paint(Graphics g) {
URL url = this.getClass().getResource("img/15.jpg");
javax.swing.ImageIcon img = new javax.swing.ImageIcon(url);
ImageIcon img1;
img1 = Drawliskey.addpic1();
g.drawImage(img1.getImage(), 0, 0, 680, 535, null);
if (offScreenImage == null) {
// 擷取窗體所在位置的圖片
offScreenImage = this.createImage(685, 535);
}
// 獲得擷取圖片的畫布
Graphics gImage = offScreenImage.getGraphics();
// 獲取畫布的底色並且使用這種顏色填充畫布
// Color c = Color.BLACK;
// gImage.setColor(c);
// gImage.fillRect(0, 0, 780, 640);
// 有清除上一步影象的功能,相當於gImage.clearRect(0,
gImage.drawImage(img1.getImage(), 0, 0, 680, 535, null);
super.paint(gImage);
paintair(gImage);// 重新繪製敵機
paintenemmis(gImage);// 重新繪製敵機的子彈
paintmymis(gImage);// 重新玩家的子彈
paintmyair(gImage); // 重新繪製自己的飛機
// 將接下來的圖片載入到窗體畫布上去,才能看到每次畫的效果
g.drawImage(offScreenImage, 0, 0, null);
}
}