成果展現
製做思路
第1步:發現類(對象)
人物-小丑: Buffoon 子彈-帽子:Missile 牆體:Wall 爆炸物:Explode
第2步:發現屬性
小丑:寬和高,位置(x,y),移動速度 帽子:寬和高,位置(x,y),移動速度 牆體:寬和高,位置(x,y) 爆炸物:寬和高,位置(x,y)
第3步:發現方法
小丑:移動、攻擊、人物撞邊界 子彈:移動、子彈撞牆、子彈撞邊界 爆炸物:消失
重難點分析
窗體如何建立
public class GameClient extends Frame
經過繼承Frame類實現Java窗體html
public class Frame extends Window implements MenuContainer
Frame類繼承了Window類和MenuContainer接口java
如何將圖片加載到窗體裏
步驟1:建立經常使用工具類CommonUtils,新建getImage方法實現將圖片資源轉換爲Java對象api
public class CommonUtils { /** * 讀取圖片資源, 轉變爲Java對象 Image * @param imgPath 圖片路徑 * @return Image對象 */ public static Image getImage(String imgPath) { ImageIcon imageIcon = new ImageIcon(imgPath); return imageIcon.getImage(); } }
步驟2:調用getImage方法添加對象圖片併發
public class GameClient extends Frame { Image bg_image = CommonUtils.getImage("images/bg.png"); Image explode = CommonUtils.getImage("images/explode.png"); Image missile = CommonUtils.getImage("images/missile.png"); Image wall_h = CommonUtils.getImage("images/wall-h.png"); Image wall_v = CommonUtils.getImage("images/wall-v.png"); Image buffoon = CommonUtils.getImage("images/body/s-left.png");
步驟3:重寫Framed的paint方法,實現窗體加載圖片ide
@Override public void paint(Graphics g){ //畫背景圖 g.drawImage(bg_image,0,0,1100,700,this); //畫小丑 g.drawImage(buffoon,300,200,80,80,this); //畫爆炸物 g.drawImage(explode,800,400,90,90,this); //畫原諒帽 g.drawImage(missile,300,300,60,60,this); //畫橫着的牆體 g.drawImage(wall_h,400,300,100,20,this); //畫豎着的牆體 g.drawImage(wall_v,400,300,20,100,this);
Graphics類的drawImage方法須要提供Image類參數、窗體的x參數、窗體的y參數、Image類的寬度width、Image類的長度length以及observer(當轉換了更多圖像時要通知的對象)工具
對象移動的實現
指向標的地圖,一般採用「上北下南,左西右東」的規則肯定方向。移動的八個方向一般指的是北、東北、東、東南、南、西南、西、西北。所以在定義移動方向時用上、左、下、右、上右、下右、上左、下左來表示動畫
小丑:移動 move<Orientation類傳遞方向參數> 'left向左' :x = x - this.speed; 'right向右' :x = x + this.speed; 'down向下' :y = y + this.speed; 'up向上' :y = y - this.speed; 'ur東北方向' : x = x + this.speed; y = y - this.speed; 'ul西北方向' : x = x - this.speed; y = y - this.speed; 'dr東南方向' : x = x + this.speed; y = y + this.speed; 'dl西南方向' : x = x - this.speed; y = y + this.speed;
窗體關閉的實現
public void start() { //窗體添加偵聽方法 this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { super.windowClosing(e); //退出遊戲 System.exit(0); } });
WindowAdapter類:
1.接收窗口事件的抽象適配器類。此類中的方法爲空。此類存在的目的是方便建立偵聽器對象。
2.擴展此類可建立 WindowEvent 偵聽器併爲所需事件重寫該方法。(若是要實現 WindowListener 接口,則必須定義該接口內的全部方法。此抽象類將全部方法都定義爲 null,因此只需針對關心的事件定義方法。
3.使用擴展的類能夠建立偵聽器對象,而後使用窗口的 addWindowListener 方法向該窗口註冊偵聽器。當經過打開、關閉、激活或停用、圖標化或取消圖標化而改變了窗口狀態時,將調用該偵聽器對象中的相關方法,並將 WindowEvent 傳遞給該方法。
windowAdapter監聽器
this
按鍵事件觸發的實現
this.addKeyListener(new KeyAdapter() { //鍵盤按下的時候出發 @Override public void keyPressed(KeyEvent e) { super.keyPressed(e); } //鍵盤松開 @Override public void keyReleased(KeyEvent e) { //獲取被按下的鍵對應的數值,如,a:67,b:68 int keyCode = e.getKeyCode(); switch (keyCode){ case KeyEvent.VK_UP: System.out.println("向上走!!!"); buffoon.setDir("UP"); break; case KeyEvent.VK_DOWN: System.out.println("向下走"); buffoon.setDir("DOWN"); break; case KeyEvent.VK_RIGHT: System.out.println("向右走"); buffoon.setDir("RIGHT"); break; case KeyEvent.VK_LEFT: System.out.println("向左走!!"); buffoon.setDir("LEFT"); break; } buffoon.move(buffoon.getDir()); } });
按鍵觸發的要點
要點一:‘new KeyAdapter()’ 新建一個按鍵事件的監聽器,並經過addKeyListener()向主窗體註冊該監聽器;
要點二:重寫KeyAdapter的方法,分別是KeyTyped(鍵入)、KeyPresdded(按下)、KeyReleased(釋放)。這裏咱們只監聽KeyPressed事件並重寫該方法,實現對人物方向狀態的改變;
要點三:KeyEvent e.getKeyCode返回的是按下按鍵對應的鍵值,參考KeyEvent的鍵值屬性。Java 8在線API
url
建立對象Buffoon.move()方法
public void move(String dir){ switch (dir){ case "UP": this.y -= this.speed; setDir("STOP"); break; case "DOWN": this.y += this.speed; setDir("STOP"); break; case "RIGHT": this.x += this.speed; setDir("STOP"); break; case "LEFT": this.x -= this.speed; setDir("STOP"); break; }
每次監聽到按鍵事件調用move方法實現buffoon對象的移動
對象移動的原理
對象移動的畫面也叫動畫,是在屏幕上顯示一系列連續動畫畫面的一幀一幀的圖形,而後在間隔很短的時間顯示下一幀圖形,如此反覆,利用人眼的‘視覺暫留’現象主觀感受好像畫面的物體在運動。
FPS(Frames Per Second),是每秒鐘的幀數。一幀就是一幅靜態畫像,電影的播放速度是24FPS。幀數越多,所顯示的動做就會越流暢。一般,要避免動做不流暢的最低是30FPS。FPS百度百科
spa
動畫移動的搬運工-線程(thread)
什麼是線程
線程(thread)是操做系統可以進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運做單位。一條線程指的是進程中一個單一順序的控制流,一個進程中能夠併發多個線程,每條線程並行執行不一樣的任務。
/** * 定義一個從新繪製畫面的線程,至關於招一個工人專門去從事這項工做 */ public class RePaintThread implements Runnable{ @Override //線程操做的全都在run方法中 public void run() { while (true){ //每50毫秒 執行一次 try { Thread.sleep(20); //從新繪製圖像 gameClient.repaint(); } catch (InterruptedException e) { e.printStackTrace(); } } }
要點一:Runnable接口
public class RePaintThread implements Runnable
使用實現接口 Runnable 的對象建立一個線程時,啓動該線程將致使在獨立執行的線程中調用對象的 run 方法。
要點二:重寫Run方法
方法 run 的常規協定是:它可能執行任何所需的動做。
從新繪製圖像
gameClient.repaint();
要點三:Thread.sleep—線程反覆執行的時間間隔
一、使用’While(true)'構造死循環
二、在死循環中執行repaint()重繪圖形方法
三、線程中斷異常(InterruptedException)是當前線程被中斷的表現之一。遇到這個異常時,若是你不知道如何處理,你應當向上拋出。