心得體會是指一種讀書、實踐后所寫的感受性文字。語言類讀書心得同數(shù)學札記相近;體會是指將學習的東西運用到實踐中去,通過實踐反思學習內(nèi)容并記錄下來的文字,近似于經(jīng)驗總結(jié)。下面是小編帶來的有關java飛機大戰(zhàn)心得體會,希望大家喜歡
1.首先有玩家類,窗口類,主函數(shù)類和圖片文件(.jpg)
2.然后是先行知識,創(chuàng)建窗口(JFrame),設置窗口屬性;窗口上不能直接添加組件(鍵盤監(jiān)聽等),所以先在窗口上添加容器(Jpanel),將組件(KeyAdapter)添加到容器;
3.畫出玩家:重寫窗口類中的paintComponent方法,創(chuàng)建Graphics對象,調(diào)用drawImage方法可畫圖,調(diào)用drawString方法可標注其名字
4.移動:在窗口類中創(chuàng)建鍵盤監(jiān)聽抽象類KeyAdapter(實現(xiàn)了接口的部分方法但無具體操作),需要重寫該類的Keypressed方法和KeyRleased方法,賦給按鍵變量真值,隨后將該對象添加到窗口
5.隨機生成初始坐標:在開始游戲后隨機給定玩家的x、y坐標,創(chuàng)建Random對象,調(diào)用Random.nextInt(n)方法,n代表從[0,n)區(qū)間的隨機值。
6.最后通過一個Timer.schedule(匿名內(nèi)部類對象,指定延遲后開始,周期)方法來實現(xiàn)移動效果。匿名內(nèi)部類【TimerTask的子類,重寫了run方法,包括repaint方法(實則調(diào)用paintComponent)和yidong方法】來重畫、監(jiān)聽鍵盤的指令()并作出相應動作
下面是源代碼(有注釋):
容器類
package a;
import javax.swing._;
import java.awt._;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import static a.Newgame.frame;
//新建面板
public class War extends JPanel {
private Timer timer;
private boolean sUp, sDown, sRight, sLeft;//右飛機按鍵變量
private boolean sW, sD, sS, sA;//左飛機按鍵變量
private Player1 player1 = new Player1();
private Player2 player2 = new Player2();
private ImageIcon img11 = player1.img1;
private ImageIcon img22 = player2.img2;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//此句調(diào)用父類方法進行界面重繪,恢復到某個界面,下面的步驟再畫玩家;如果注釋掉會有重影
//在面板上畫出玩家
g.drawImage(img11.getImage(), player1.x, player1.y, 100, 100, this);
g.drawString("P1", player1.x, player1.y);
g.drawImage(img22.getImage(), player2.x, player2.y, 100, 100, this);
g.drawString("P2", player2.x, player2.y);
}
public void startGame() {
timer = new Timer();
timer.schedule(new TimerTask() {//匿名內(nèi)部類(TimerTask的子類)
@Override
public void run() {//重寫run()函數(shù)
repaint();//調(diào)用重寫的paintComponent來畫兩飛機
yidong();//并每次判斷按下哪個鍵,然后移動
}
}, 0, 50);//安排指定的任務從指定的延遲后開始進行重復的固定延遲執(zhí)行。50毫秒執(zhí)行一次
}
public void yidong() {
//因為每打印一次可能用戶按下一個飛機的幾個鍵或者兩個飛機的幾個鍵,這些是都要檢測到的,改成else if后只能檢測到一個鍵,無法實現(xiàn)兩架飛機同時多方向移動
if (sW && player1.y > 0) {
player1.y -= player1.speed;
}
if (sA && player1.x > 0) {
player1.x -= player1.speed;
}
if (sS && player1.y < 700) {
player1.y += player1.speed;
}
if (sD && player1.x < 900) {
player1.x += player1.speed;
}
if (sUp && player2.y > 0) {
player2.y -= player2.speed;
}
if (sDown && player2.y < 700) {
player2.y += player2.speed;
}
if (sLeft && player2.x > 0) {
player2.x -= player2.speed;
}
if (sRight && player2.x < 900) {
player2.x += player2.speed;
}
}
public void act() {
//隨機生成兩飛機的初始坐標
Random rd = new Random();
player1.x = rd.nextInt(900);
player1.y = rd.nextInt(700);
player2.x = rd.nextInt(900);
player2.y = rd.nextInt(700);
//開始游戲后獲得計時器開始監(jiān)聽并重畫
startGame();
//KeyAdapter是KeyListener的實現(xiàn)類,重寫了所有方法但沒有具體操作
KeyAdapter keyAdapter = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_W:
sW = true;
break;
case KeyEvent.VK_A:
sA = true;
break;
case KeyEvent.VK_D:
sD = true;
break;
case KeyEvent.VK_S:
sS = true;
break;
case KeyEvent.VK_RIGHT:
sRight = true;
break;
case KeyEvent.VK_LEFT:
sLeft = true;
break;
case KeyEvent.VK_DOWN:
sDown = true;
break;
case KeyEvent.VK_UP:
sUp = true;
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_W:
sW = false;
break;
case KeyEvent.VK_A:
sA = false;
break;
case KeyEvent.VK_D:
sD = false;
break;
case KeyEvent.VK_S:
sS = false;
break;
case KeyEvent.VK_RIGHT:
sRight = false;
break;
case KeyEvent.VK_LEFT:
sLeft = false;
break;
case KeyEvent.VK_DOWN:
sDown = false;
break;
case KeyEvent.VK_UP:
sUp = false;
break;
}
}
};
frame.addKeyListener(keyAdapter);
}
}
主函數(shù)類:
package a;
import javax.swing._;
public class Newgame {
public static JFrame frame;
public static void main(String[] args) {
frame = new JFrame("逃出生天");
frame.setSize(1000,800);
//絕對布局組件位置和形狀不會隨窗體改變,不設置布局管理器就可以使用setBounds()來控制位置
frame.setLayout(null);
//設置窗體關閉程序自動關閉
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//窗體居中顯示
frame.setLocationRelativeTo(null);
//添加主面板
War war = new War();
frame.add(war);
//設置面板大小
war.setBounds(0,0,1000,800);
//設置主面板可見
frame.add(war);
frame.setVisible(true);
war.act();
}
}
1234567891011121314151617181920212223242526
玩家類:
玩家1
package a;
import javax.swing._;
public class Player1 {
public int x;
public int y;
public int speed = 50;
public ImageIcon img1 = new ImageIcon("D:\\Program_Files\\Jetbrains\\workspace_idea\\src\\a\\plane.jpg");
}
12345678910
玩家2
package a;
import javax.swing._;
public class Player2 {
public int x;
public int y;
public int speed = 50;
public ImageIcon img2 = new ImageIcon("D:\\Program_Files\\Jetbrains\\workspace_idea\\src\\a\\plane2.jpg");
}
做成一個桌面小游戲:
點“+”號
選好主函數(shù)類后點ok
然后點Build中的Build Artificts
選擇jar包點Build即可
然后jar包就在你的workspace生成了,找到它發(fā)送桌面快捷方式,更改圖標名字即可
圖片轉(zhuǎn)換成圖標的網(wǎng)站附上
用Java制作游戲之前,一定要做到方向明確,思路清晰。首先確定自己需要用到幾個類,類里的內(nèi)容大致是什么,用腦圖進行表達展現(xiàn)。
Java語言是一種跨平臺、適合于分布式計算環(huán)境的面向?qū)ο缶幊陶Z言,具有簡單性、面向?qū)ο?、分布式,多線程性等,其中面向?qū)ο笥蟹庋b,繼承,多態(tài)三大特性。
1)封裝:數(shù)據(jù)和基于數(shù)據(jù)的操作封裝
2) 繼承:一個對象直接使用另一個對象的屬性和方法,子類可以繼承父類
3) 多態(tài):一個程序中同名的多個不同方法,實現(xiàn)多態(tài)的常見方法 子類對父類的覆蓋,利用重載在同一個類中定義多個同名的不同方法;
Java游戲制作中必須有 public static void main(String[] args)的主方法,main()方法是程序執(zhí)行的入口。例如我的飛機大戰(zhàn)main(),便是游戲開始執(zhí)行的入口,寫在GameFace類中。
游戲框架的制作,其大部分的代碼都是固定形式,可以通用。使用setVisible(true)的方法,改變默認的不可見狀態(tài),setLayout(null)取消默認的管理布局,然后setLocation(),setSize(),setBound()等方法設置其大小。將按鈕添加監(jiān)聽,實現(xiàn)監(jiān)聽。在對應方法中編寫代碼,,為監(jiān)聽者創(chuàng)建對象,完成注冊,即在接口名字前添加“add”。
游戲版面要繼承JPanel,其原因是JPanel帶有雙緩沖技術(shù),可以解決閃爍的問題,需要加入到JFrame窗體中,JPanel默認的布局管理器是FlowLayout。調(diào)用畫筆,將所要顯示的圖片畫出來。然后再根據(jù)自己的思路,在游戲版面內(nèi)添加敵機,實現(xiàn)矩形碰撞,生命值判定,游戲結(jié)束對話框。要熟練掌握調(diào)用其他的類,畫出分數(shù),畫出生命值。制作容器,裝子彈,飛機,炸彈。
制作游戲思路一定要清晰,對于共有屬性,可以建立一個父類,例如在創(chuàng)建一個FlyingObject類,這樣可以避免代碼的反復編寫。對于子類myplane 、enemies可以直接繼承父類,子類可以根據(jù)自己的需求再增加新的變量。在子類myplane中,畫出我的飛機,控制飛機飛行的邊界,調(diào)用子彈容器,畫出容器中子彈,與敵機進行碰撞檢測。飛機大戰(zhàn)還應該實現(xiàn)鍵盤監(jiān)聽,例如Enter鍵實現(xiàn)暫停,上下左右鍵實現(xiàn)移動等。在敵機Enemies類中,定義敵機隨機出現(xiàn)坐標,敵機圖片的相對路徑,敵機速度,敵機子彈與我的plane碰撞出現(xiàn)的結(jié)果以及敵機子彈生成的時間等。
游戲制作時需要注意的事項:1.JLabel的位置一定要放對,應當先添加背景JLabel,再添加其它控件。否則其它控件將被JLabel所遮擋。
2.對于多次重復編寫的代碼,盡可能的用for循環(huán),簡單方便。但是也要注意跳出語句的使用。
3.調(diào)用函數(shù)時要注意順序
4.類名,方法名要遵循命名規(guī)范性,盡量做到見名知義,也要注意大小寫。
線程:進程(process)就是一塊包含了某些資源的內(nèi)存區(qū)域。操作系統(tǒng)利用進程把它的工作劃分為一些功能單元。 線程:進程中所包含的一個或多個執(zhí)行單元稱為線程(thread)。進程還擁有一個私有的虛擬地址空間,該空間僅能被它所包含的線程訪問。 線程和進程的區(qū)別如下: 1)一個進程至少有一個線程。線程的劃分尺度小于進程,使得多線程程序的并發(fā)性高。 另外,進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存,從而極大地提高了程序的運行效率。 2)線程在執(zhí)行過程中與進程的區(qū)別在于每個獨立的線程有一個程序運行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨立執(zhí)行,必須依存在應用程序中,由應用程序提供多個線程執(zhí)行控制。 3)從邏輯角度來看,多線程的意義在于一個應用程序中,有多個執(zhí)行部分可以同時執(zhí)行。但操作系統(tǒng)并沒有將多個線程看做多個獨立的應用來實現(xiàn)進程的調(diào)度和管理以及資源分配。
2 簡述線程的狀態(tài)及其轉(zhuǎn)換 1)New,創(chuàng)建一個線程,但是線程并沒有進行任何的操作。 2)Runnable,新線程從New狀態(tài),調(diào)用start方法轉(zhuǎn)換到Runnable狀態(tài)。線程調(diào)用start方法向線程調(diào)度程序(JVM或者是操作系統(tǒng))注冊一個線程,這個時候一切就緒只等CPU的時間。 3)Running,從Runnable狀態(tài)到Running狀態(tài),線程調(diào)度根據(jù)調(diào)度策略的不同調(diào)度不同的線程,被調(diào)度執(zhí)行的線程進入Running狀態(tài),執(zhí)行run方法。 4)Dead狀態(tài),從Running狀態(tài)到Runnable,run方法運行完畢后,線程就會被拋棄,線程就進入Dead狀態(tài)。 5)Block狀態(tài),從Running狀態(tài)到Block狀態(tài),如果線程在運行的狀態(tài)中因為I/O阻塞、調(diào)用了線程的sleep方法以及調(diào)用對象的wait方法則線程將進入阻塞狀態(tài),直到這些阻塞原因被結(jié)束,線程進入到Runnable狀態(tài)。
3 簡述線程的兩種創(chuàng)建方式以及它們的區(qū)別 創(chuàng)建線程的兩種方式: 1)使用Thread創(chuàng)建線程。Thread類是線程類,其每一個實例表示一個可以并發(fā)運行的線程。我們可以通過繼承該類并重寫run方法來定義一個具體的線程。其中重寫run方法的目的是定義該線程要執(zhí)行的邏輯。啟動線程時調(diào)用線程的start()方法而非直接調(diào)用run()方法。start()方法會將當前線程納入線程調(diào)度,使當前線程可以開始并發(fā)運行。當線程獲取時間片段后會自動開始執(zhí)行run方法中的邏輯。 2)使用Runnable創(chuàng)建線程。實現(xiàn)Runnable接口并重寫run方法來定義線程體,然后在創(chuàng)建線程的時候?qū)unnable的實例傳入并啟動線程。 兩種創(chuàng)建線程方式的區(qū)別: 使用Thread創(chuàng)建線程,編寫簡單,可以直接操縱線程,無需使用Thread.currentThread(),但是不能夠再繼承其他類。 使用Runnable創(chuàng)建線程可以將線程與線程要執(zhí)行的任務分離開減少耦合,同時Java是單繼承的,定義一個類實現(xiàn)Runnable接口,這樣該類還可以繼承自其他類。
多線程實現(xiàn)方法
使用Thread創(chuàng)建線并啟動線程
java.lang.Thread類是線程類,其每一個實例表示一個可以并發(fā)運行的線程。我們可以通過繼承該類并重寫run方法來定義一個具體的線程。其中 重寫run方法的目的是定義該線程要執(zhí)行的邏輯。啟動線程時調(diào)用線程的start()方法而非直接調(diào)用run()方法。start()方法會將當前線程納入線程調(diào) 度,使當前線程可以開始并發(fā)運行。當線程獲取時間片段后會自動開始執(zhí)行run方法中的邏輯。
public class TestThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("我是線程");
}
}
}
創(chuàng)建預啟動線程
…
Thread thread = new TestThread();//實例化線程
thread.start();//啟動線程
…
使用Runnable創(chuàng)建并啟動線程
實現(xiàn)Runnable接口并重寫run方法來定義線程體,然后在創(chuàng)建線程的時候?qū)unnable的實例傳入并啟動線程。 這樣做的好處在于可以將線程與線程要執(zhí)行的任務分離開減少耦合,同時java是單繼承的,定義一個類實現(xiàn)Runnable接口這樣的做法可以更好的 去實現(xiàn)其他父類或接口。因為接口是多繼承關系。
public class TestRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("我是線程");
}
}
}
啟動線程的方法:
…
Runnable runnable = new TestRunnable();
Thread thread = new Thread(runnable);//實例化線程并傳入線程體
thread.start();//啟動線程
…
使用內(nèi)部類創(chuàng)建線程
通常我們可以通過匿名內(nèi)部類的方式創(chuàng)建線程,使用該方式可以簡化編寫代碼的復雜度,當一個線程僅需要一個實例時我們通常使用這種方式來 創(chuàng)建。 例如: 繼承Thread方式:
Thread thread = new Thread(){ //匿名類方式創(chuàng)建線程
public void run(){
//線程體
}
};
thread.start();//啟動線程
Runnable方式:
Runnable runnable = new Runnable(){ //匿名類方式創(chuàng)建線程
public void run(){
}
};
Thread thread = new Thread(runnable);
thread.start();//啟動線程
線程的方法
currentThread:方法可以用于獲取運行當前代碼片段的線程
Thread current = Thread.currentThread();
獲取線程信息 Thread提供了 獲取線程信息的相關方法: long getId():返回該線程的標識符 String getName():返回該線程的名稱 int getPriority():返回線程的優(yōu)先級 Thread.state getState():獲取線程的狀態(tài) boolean isAlive():測試線程是否處于活動狀態(tài) boolean isDaemon():測試線程是否為守護線程 boolean isInterrupted():測試線程是否已經(jīng)中斷
線程優(yōu)先級
線程的切換是由線程調(diào)度控制的,我們無法通過代碼來干涉,但是我們可以通過提高線程的優(yōu)先級來最大程度的改善線程獲取時間片的幾率。 線程的優(yōu)先級被劃分為10級,值分別為1-10,其中1最低,10最高。線程提供了3個常量來表示最低,最高,以及默認優(yōu)先級: Thread.MIN_PRIORITY, Thread.MAX_PRIORITY, Thread.NORM_PRIORITY 設置優(yōu)先級的方法為:
void setPriority(int priority)
守護線程
守護線程與普通線程在表現(xiàn)上沒有什么區(qū)別,我們只需要通過Thread提供的方法來設定即可: __void setDaemon(boolean )__ 當參數(shù)為true時該線程為守護線程。 守護線程的特點是,當進程中只剩下守護線程時,所有守護線程強制終止。 GC就是運行在一個守護線程上的。 需要注意的是,設置線程為后臺線程要在該線程啟動前設置。
Thread daemonThread = new Thread();
daemonThread.setDaemon(true);
daemonThread.start();
sleep方法
Thread的靜態(tài)方法sleep用于使當前線程進入阻塞狀態(tài): __static void sleep(long ms)__ 該方法會使當前線程進入阻塞狀態(tài)指定毫秒,當指定毫秒阻塞后,當前線程會重新進入Runnable狀態(tài),等待分配時間片。 該方法聲明拋出一個InterruptException。所以在使用該方法時需要捕獲這個異常 改程序可能會出現(xiàn)"跳秒"現(xiàn)象,因為阻塞一秒后線程并非是立刻回到running狀態(tài),而是出于runnable狀態(tài),等待獲取時間片。那么這段等待 時間就是"誤差"。所以以上程序并非嚴格意義上的每隔一秒鐘執(zhí)行一次輸出。
yield方法:
Thread的靜態(tài)方法yield: __static void yield()__ 該方法用于使當前線程主動讓出當次CPU時間片回到Runnable狀態(tài),等待分配時間片。
join方法
__void join()__ 該方法用于等待當前線程結(jié)束。此方法是一個阻塞方法。 該方法聲明拋出InterruptException。
線程同步
synchronized關鍵字 多個線程并發(fā)讀寫同一個臨界資源時候會發(fā)生"線程并發(fā)安全問題“ 常見的臨界資源: 多線程共享實例變量 多線程共享靜態(tài)公共變量 若想解決線程安全問題,需要將異步的操作變?yōu)橥讲僮鳌?所謂異步操作是指多線程并發(fā)的操作,相當于各干各的。 所謂同步操作是指有先后順序的操作,相當于你干完我再干。
同步代碼塊(synchronized 關鍵字 ),同步代碼塊包含兩部分:一個作為鎖的對象的引用,一個作為由這個鎖保護的代碼塊 這個比較難理解故寫了下面代碼幫助理解
/__
_ 多線程并發(fā)安全問題
_ 當多個線程同時操作同一資源時,由于
_ 線程切換時機不確定,導致出現(xiàn)邏輯混亂。
_ 嚴重時可能導致系統(tǒng)崩潰。
_ @author ylg
_
_/
public class SyncDemo1 {
public static void main(String[] args) {
/_
_ 當一個方法中的局部內(nèi)部類想引用該方法
_ 的其他局部變量時,這個變量必須被聲明
_ 為final的
_/
final Table table = new Table();
Thread t1 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//模擬線程切換
System.out.println(
getName()+":"+bean
);
}
}
};
Thread t2 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//模擬線程切換
System.out.println(
getName()+":"+bean
);
}
}
};
t1.start();
t2.start();
}
}
class Table{
//20個豆子
private int beans = 20;
/__
_ 當一個方法被synchronized修飾后,該方法
_ 成為"同步方法"。多個線程不能同時進入到
_ 方法內(nèi)部。
_ @return
_/
public synchronized int getBean(){
if(beans==0){
throw new RuntimeException("沒有豆子了!");
}
Thread.yield();//模擬線程切換
return beans--;
}
}
/__
_ 有效的縮小同步范圍可以保證在
_ 安全的前提下提高了并發(fā)的效率
_ @author ylg
_
_/
public class SyncDemo2 {
public static void main(String[] args) {
final Shop shop = new Shop();
Thread t1 = new Thread(){
public void run(){
shop.buy();
}
};
Thread t2 = new Thread(){
public void run(){
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
/_
_ 在方法上使用synchroinzed,同步監(jiān)視器對象即當前方法所屬對象:this
_/
// public synchronized void buy(){
public void buy(){
try{
Thread t = Thread.currentThread();
System.out.println(t+"正在挑選衣服..");
Thread.sleep(5000);
/_
_ 同步塊可以縮小同步范圍。
_ 但是必須保證"同步監(jiān)視器"即:"上鎖對象"是同一個才可以。
_ 通常,在一個方法中使用this所謂同步監(jiān)視器對象即可。
_/
synchronized (this) {
System.out.println(t+"正在試衣服..");
Thread.sleep(5000);
}
System.out.println(t+"結(jié)賬離開");
}catch(Exception e){
}
}
}
/__
_ synchronized也成為"互斥鎖"
_ 當synchronzed修飾的是兩段代碼,但是"鎖對象"相同時,這兩段代碼就是互斥的。
_ @author ylg
_
_/
public class SyncDemo4 {
public static void main(String[] args) {
final Boo b = new Boo();
Thread t1 = new Thread(){
public void run(){
b.methodA();
}
};
Thread t2 = new Thread(){
public void run(){
b.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public synchronized void methodA(){
Thread t = Thread.currentThread();
System.out.println(t+"正在調(diào)用方法A");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t+"調(diào)用方法A完畢");
}
public synchronized void methodB(){
Thread t = Thread.currentThread();
System.out.println(t+"正在調(diào)用方法B");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t+"調(diào)用方法B完畢");
開發(fā)登錄界面、設計地圖加載、子彈飛機的加載、主控制程序的開發(fā)登錄界面的開發(fā),通常是在界面上顯示游戲菜單選項,用戶可根據(jù)菜單項選擇需要的操作。菜單項是和游戲的功能緊密相關的。手機游戲的開發(fā)往往在界面和操作方式上有較高的要求,Java ME提供了低級界面開發(fā)的API,可用于游戲開發(fā)。低級界面畫布類主要有Canvas和GameCanvas,其中Canvas是屬于MIDP 1.0,GameCanvas則是屬于MIDP 2.0。低級用戶界面技術(shù)為用戶提供了靈活的開發(fā)方法,可以進行一些較為底層的操作,例如:按鍵的處理事件更為豐富,組件位置的設置更為靈活。手機上的屏幕坐標系和我們常規(guī)數(shù)學的坐標系不相同。對于坐標(x,y),若x值越大,則越向右,y值越大,則越向下。對于飛機射擊游戲,飛機在飛行過程中經(jīng)過不同的地理環(huán)境,例如大海、小島、石礁等作為地圖的背景。地圖的寬度通常要求能夠自動匹配不同類型的手機寬度,高度則是以一個關卡所需的時間為依據(jù)進行設計。在此我們采用簡化操作方法,給地圖寬度和高度設置一個具體值。子彈的射擊應該支持不同的方向,例如我方飛機自下而上發(fā)射子彈,敵方飛機自上而下發(fā)射子彈。當子彈與飛機碰撞之后,飛機的血量相應地要減少,如果飛機的血量為0,則產(chǎn)生爆炸效果,子彈和飛機都消失。飛機主角在開始游戲時出現(xiàn)在屏幕最底部的中間處,玩家可以通過上、下、左、右鍵控制其飛行方向,按下確認鍵后可以發(fā)射子彈。敵機在游戲開始后從背景上部出現(xiàn),飛行,并發(fā)射子彈。在本任務中需要考慮敵機出現(xiàn)的位置,出現(xiàn)的數(shù)量和頻率,飛行的速度和子彈的發(fā)射方向。
為了更好地控制游戲的主體邏輯,可以統(tǒng)一對游戲地圖進行設置,對主角飛機、敵方飛機初始化,并在多線程中實現(xiàn)游戲的邏輯控制。
游戲主框架的首要模塊的安排:
1.游戲的初始化。主要是完成游戲資源的加載,各種游戲?qū)ο蟆⒆兞咳≈档某跏蓟?,游戲運行環(huán)境的獲取和設置,歷史記錄的讀取等。
2.游戲的主循環(huán)。執(zhí)行游戲處理的主要代碼,直到滿足退出要求才停止循環(huán),例如:玩家選擇退出游戲,玩家游戲失敗,玩家最終完成游戲等。主要實現(xiàn)分為三步:(1)獲得游戲的輸入信息;(2)處理游戲的邏輯;(3)更新游戲的畫面
3.退出游戲
Canvas為抽象類,負責圖形圖像的繪制和用戶交互。進行低級玩家界面的開發(fā)通常需要繼承Canvas類,主要方法如下:
1.getHeight():獲取Canvas繪圖區(qū)域的高度。
2.getWidth():獲取Canvas繪圖區(qū)域的寬度。
3.paint(Graphics g):渲染畫布,向屏幕畫圖,通常將畫圖的操作放在該方法中實現(xiàn)。當屏幕需要重新繪制時,Java ME主線程會自動調(diào)用paint方法,程序員不能在代碼中直接聲明調(diào)用該方法。
4.repaint():主動向系統(tǒng)請求刷新界面,具體的刷新操作實際是通過調(diào)用paint方法來完成。
5.isDoubleBuffered():判斷手機設備是否匹配雙緩沖。有些手機匹配雙緩沖技術(shù),有些則不匹配。
6.getGameAction(int keyCode):將手機的鍵值切換為游戲動作。
7.getKeyName(keyCode):得到按鍵的名字。
Graphics提供2D渲染能力,作用是在屏幕上繪制圖形,類似于一支畫筆。
Graphics繪制的圖形不能夠直接顯示,必須通過Canvas或GameCanvas才能顯示在屏幕上,因此Canvas和GameCanvas類似于可以顯示圖形的畫布
Graphics類支持繪制圖形主要包括以下3種:
(1)文本:可以設置文本的顏色、字體大小等
(2)圖像:可以直接繪制圖像文件或者從緩存中繪制
(3)2D幾何圖形:繪制點、直線、平面圖形等
Graphics類沒有構(gòu)造方式,獲取對象的途徑有3種:
1.Canvas類中的paint方法有一個Graphics對象參數(shù),系統(tǒng)會自動調(diào)用paint方法,并傳進一個Graphics對象,因此可以在paint方法中使用Graphics對象編寫繪圖代碼。
2.在GameCanvas類中通過getGraphics方法來獲取一個Graphics對象,因此可以在要求的地方靈活地編寫與繪圖有關的代碼。
3.Image對象的getGraphics()方法得到Graphics對象,可用于編寫雙緩沖區(qū)代碼。
1.直接用整幅圖片作為背景,再在上面重疊一層加入物件、擺設等,優(yōu)點在于圖形相對豐富、漂亮,但消耗資源較多,受手機硬件條件的影響不能做太大的圖。
2.游戲地圖是用一個個圖塊重復拼接成,而在程序中就可以通過一個較小的圖像文件和一個二維數(shù)組,繪制出一幅較大的地圖。具體的做法是將圖像文件劃分為若干個相同大小的圖塊(一般每個圖塊是16像素 × 16像素或者32像素 × 32像素),每個圖塊給一個索引值,例如:1表示草地圖塊,2表示磚頭圖塊。而二維數(shù)據(jù)中記錄的數(shù)字就是圖像文件中的圖塊索引值,例如:某個數(shù)組元素的數(shù)值若為1,則表示在此處畫草地。此方法的益處在于比較節(jié)約系統(tǒng)資源,可做出來的地圖相對比較一般。
地圖編輯器能夠幫助將地圖最后轉(zhuǎn)變成程序直接使用,所以一個好的地圖編輯器能夠加速游戲的開發(fā)周期。
業(yè)界已經(jīng)推出多款地圖編輯器,例如Mappy(MapWin)、Tiled、TILE STUDIO等,其中Mappy功能比較強大,可以很方便地對2D地圖進行編輯。
下載mayppy軟件:HTTP:/ / www.tilemap.uk /mappy
假如需支持png圖片,那么還需下載兩個dll文件,這兩個文件也都放在Mappy軟件的網(wǎng)址上
zlib.dll用于文件壓縮
libpng12.dll是PNG圖像壓縮庫
將這兩個文件下載復制到Mappy可執(zhí)行文件的同一個目錄下即可,否則在導入PNG文件時,會報圖5-23的錯誤
制作游戲還需要用到圖像素材,因此除了Mappy軟件之外,還需要用到圖像處理軟件Photoshop來制作原始游戲素材。
J2SE中提供了多個接口和類管理集合,例如有Collection、List、Set、Map接口,實現(xiàn)接口的集合類有LinkedList、ArrayList、Vector、Hashtable、HashMap和WeakHashMap類。
在Java ME中只有java.util包提供Vector類,其功能和J2SE的Vector類似,實現(xiàn)的是一個動態(tài)增長的數(shù)組,可以在程序代碼中調(diào)整或者裁減集合的大小,能向集合插入、刪除和修改元素。
每一個集合中的元素都被分派一個整數(shù)索引號,能夠直接根據(jù)索引號插入和刪除一個元素,也能夠修改和得到一個元素的值。
為了更好地控制游戲的主體邏輯,可以統(tǒng)一對游戲地圖進行設置,對主角飛機、敵方飛機初始化,并在多線程中實現(xiàn)游戲的邏輯控制。