根據引導自己動手試試看
源碼具體詳情請點擊 https://download.csdn.net/download/qq_40803710/11011232 進行下載。
1.第一個任務:做6個子類
Sky: y1;step step();
Hero: life;doubleFire move(int x,int y){}
Airplane: step step();
BigAirplane: step step();
Bee: xstep; ystep; awardType//0表示帶命;1表示帶分 step();
Bullet: step step();
2.第二個任務:使用構造方法,初始化數據
1)Sky:無參構造
public Sky() {
super(400,700,0,0);
y1=-700;
step = 1;
}
2) Hero:無參構造
public Hero() {
super(97,124,400/2-97/2,400);
life = 3;
doubleFire = 0;//0表示單倍火力 >0表示雙倍火力
}
3)敵人對象(Airplane,BigAirplane,Bee)無參構造
public Airplane() {
super(49,36);
step = 2;
}
public BigAirplane() {
super(69,99);
step = 2;
}
public Bee() {
super(60,50);
xstep = 1;
ystep = 2;
awardType = new Random().nextInt(2); //0:火力值 1:命
}
4)Bullet
public Bullet(int x,int y) {
super(8,14,x,y);
step = 3;
state = LIFE;
}
3. 第三個任務:定義FlyingObject(實現代碼重用)
1)定義FlyingObject,定義通用的變量和方法
2)設計兩個構造方法:
對Airplane,Bee ,BigAirplane對象的初始化方法
//給敵人對象初始化Airplane,BigAirplane,Bee
public FlyingObject(int width,int height){
this.width = width;
this.height = height;
x = new Random().nextInt(400-this.width);
y = -height;
},在子類中調用
對Hero,Sky,Bullet對象的初始化方法
//給Sky,Hero,Bullet三個類實例化的方法
public FlyingObject(int width,int height,int x,int y){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
},在子類中調用
3)調整成員變量的修飾符
父類中可以被訪問的成員訪問修飾符:protected
子類中的成員不被外界訪問修飾符:private
4.第四個任務:畫頁面
1)定義World類,繼承JPanel
2)定義窗口,顯示窗口
import javax.swing.JPanel;
import java.awt.Graphics;
import javax.swing.JFrame;
public class world extends JPanel{
Sky sky = new Sky();
public static void main(String args[]) {
JFrame frame = new JFrame();
world world = new world();
frame.add(world);
frame.setTitle("飛機大戰"); //設置窗口標題
frame.setSize(400,700); //設置窗口大小
frame.setLocationRelativeTo(null); //設置窗口居中顯示
frame.setVisible(true); //設置窗口可視化
}
//實現畫的功能
public void paint(Graphics g) {
sky.paintObject(g);
}
}
3)把圖片拷貝到工程包下
4)加載圖片
4.1)天空
//存放圖片對象
private static BufferedImage image;
static{
try {
//使用ImageIO讀取圖片
image = ImageIO.read(Sky.class.getResource("background.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
4.2)小敵機
//加載圖片到數組中
private static BufferedImage[] images = new BufferedImage[5];
static{
for(int i = 0;i<images.length;i++){
try {
images[i]=ImageIO.read(Airplane.class.getResource("airplane"+i+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4.3)大敵機
//加載圖片到數組中
private static BufferedImage[] images = new BufferedImage[5];
static{
for(int i = 0;i<images.length;i++){
try {
images[i]=ImageIO.read(Airplane.class.getResource("bigplane"+i+".png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5)獲取圖片
//類中有一個抽象方法時類不能定義爲對象 要想讓當前類創建對象
//要將父類抽象且方法抽象(父類中聲明)纔可以實現
public abstract BufferedImage getImage();
//子類中具體實現
5.1)天空@Override
public BufferedImage getImage() {
return image;
}
(1)小敵機
/*
* 1、如果當前狀態爲活着,加載數組的第一張圖片
* 2、如果當前狀態爲死亡,加載數組中剩餘的四張圖片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
//解決怎樣加載剩餘四張圖片 可以多次調用返回
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(2)大敵機
/*
* 1、如果當前狀態爲活着,加載數組的第一張圖片
* 2、如果當前狀態爲死亡,加載數組中剩餘的四張圖片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(3)蜜蜂
/*
* 1、如果當前狀態爲活着,加載數組的第一張圖片
* 2、如果當前狀態爲死亡,加載數組中剩餘的四張圖片,把state=REMOVE
*/
int deadIndex = 1;
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return images[0];
}else if(this.isDead()) {
//解決怎樣加載剩餘四張圖片 可以多次調用返回
BufferedImage image = images[deadIndex++];
if(deadIndex==images.length) {
state = REMOVE;
}
return image;
}
return null;
}
(4)子彈
public Bullet[] getBullet() {
if(doubleFire == 0) {
Bullet[] b = new Bullet[1];
int b_x = this.x + this.width/2;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
b[0] = b1;
return b;
}else {
Bullet[] b = new Bullet[2];
int b_x = this.x + this.width/4;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
b[0] = b1;
int b_x2 = this.x + this.width/4*3;
Bullet b2 = new Bullet(b_x2,b_y);
b[0] = b1;
b[1] = b2;
return b;
}
}
/*
* 1、如果當前狀態爲活着,加載數組的第一張圖片
* 2、如果當前狀態爲死亡,把state=REMOVE
*/
@Override
public BufferedImage getImage() {
if(this.isLife()) {
return image;
}else if(this.isDead()) {
state = REMOVE;
}
return null;
}
6)畫圖片
public void paintObject(Graphics g) {
g.drawImage(getImage(), x, y, null);
g.drawImage(getImage(), x, y, null);
}
在World類中畫圖片
定義方法objectAction
FlyingObject object [] = {};
//敵人入場
public void objectAction(){
//小敵機的初始化
object = new FlyingObject[6];
object[0] = new Airplane();
object[1] = new Airplane();
object[2] = new Airplane();
object[3] = new BigAirplane();
object[4] = new BigAirplane();
object[5] = new BigAirplane();
}
//實現畫的功能
public void paint(Graphics g){
sky.paintObject(g);
//畫小敵機
for(int i = 0;i<object.length;i++){
object[i].paintObject(g);
}
}
5.第五個任務:讓畫面動起來
(1)動起來
//天空向下移動
public void step() {
y += step;
y1 += step;
if(y >= 700) {
y = -700;
}
if(y1 >= 700) {
y1 = -700;
}
}
//敵人對象動起來
public void step() {
y += step;
}
//小蜜蜂的step方法
public void step() {
x += xstep;
y += ystep;
if(x>=400-this.width) {
xstep *= -1;
}
}
//子彈動起來
public void step() {
y -= step;
}
(2)在world中定義方法
//讓飛行物動起來
public void stepAction() {
//天空
sky.step();
//讓敵人(小敵機、大敵機、蜜蜂)動起來
for(int i = 0;i<object.length;i++) {
object[i].step();
}
//讓子彈動起來
for(int i = 0;i<bullets.length;i++) {
bullets[i].step();
}
}
在run方法中調用
public void action() {
//使用定時器
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
objectAction(); //生成敵人對象
stepAction(); //讓畫面動起來
bulletAction();
//run()功能:調用paint()方法
repaint();
}
}, 10, 10); //delay延遲 period
}
(3)隨機產生敵人對象
3.1)//隨機產生一個敵人對象
public FlyingObject nextOne() {
//20以內隨機數 分成三個範圍 定義其類型
int Random = new Random().nextInt(20);
if(Random<4) {
return new Bee();
}else if(Random>=4 && Random<12) {
return new BigAirplane();
}else {
return new Airplane();
}
}
//控制生成敵人數量
int flyIndex = 0;
//敵人入場
public void objectAction() {
flyIndex++;
if(flyIndex % 40 == 0) {
//敵人的初始化
FlyingObject obj = nextOne();
object = Arrays.copyOf(object, object.length+1);
object[object.length-1] = obj;
}
}
//控制生成子彈數量
int bulletIndex = 0;
public void bulletAction() {
bulletIndex++;
if(bulletIndex % 40 == 0) {
//子彈的初始化
Bullet b1[] = hero.getBullet();
//數組擴容:原來數組回收,新建數組拷貝擴容,第二參數爲數組總大小
//Arrays.copyOf(original, newLength)
bullets = Arrays.copyOf(bullets, bullets.length + b1.length);
//對原數組數據拷貝第一個:從哪裏開始拷;第四個:從哪裏開始拷貝;第五個:拷貝多少個
System.arraycopy(b1, 0, bullets, bullets.length - b1.length, b1.length);
}
}
3.2)把隨機對象放到數組中
int index = 0;
//敵人入場
public void objectAction(){
index++;
if(index%40==0){
//小敵機的初始化
FlyingObject ob = nextOne();
object = Arrays.copyOf(object,object.length+1);
object[object.length-1]=ob;
}
}
4)子彈的產生
4.1)在Hero類中定義方法
public Bullet[] getBullet(){
if(doubleFire==0){
Bullet[] b = new Bullet[1];
int b_x = this.x + this.width/2;
int b_y = this.y - 20;
Bullet bl = new Bullet(b_x,b_y);
b[0] = bl;
return b;
}else{
Bullet[] b = new Bullet[2];
int b_x = this.x + this.width/4;
int b_y = this.y - 20;
Bullet b1 = new Bullet(b_x,b_y);
int b_x2 = this.x + this.width/4*3;
Bullet b2 = new Bullet(b_x2,b_y);
b[0] = b1;
b[1] = b2;
return b;
}
}
4.2)把子彈對象放到數組中
int bulletIndex=0;
//子彈入場
public void bulletAction(){
bulletIndex++;
if(bulletIndex%30==0){
Bullet bl[] = hero.getBullet();
//數組擴容
bullets = Arrays.copyOf(bullets, bullets.length+bl.length);
//數組拷貝
System.arraycopy(bl, 0, bullets, bullets.length-bl.length, bl.length);
}
}
5)英雄機隨鼠標移動(Hero類中)
5.1)//x,y表示鼠標的座標 (Hero類中)
public void move(int x,int y){
this.x = x - this.width/2;
this.y = y - this.height/2;
}
5.2)添加事件監視器 (World類中)
//定義鼠標的移動事件處理方法(內部類:(匿名類))
MouseAdapter l = new MouseAdapter(){
public void mouseMoved(MouseEvent e){
//獲取鼠標點的座標
int x = e.getX();
int y = e.getY();
hero.move(x, y);
}
};
//給Jpanel添加事件監視器的對象
this.addMouseMotionListener(l);
6.第六個任務:刪除越界的對象
- 在父類定義越界的方法,分別在子類中實現方法
public abstract boolean outOfBounds();
- 分別實現方法(敵人對象y>700,子彈y<0,天空和英雄機永不越界)
- 敵人
public boolean outOfBounds() {
return this.y>700;
}
- 子彈
public boolean outOfBounds() {
return this.y<0;
}
- 天空和英雄機
public boolean outOfBounds() {
return false;
}
- 在world類中定義方法,回收越界對象,在action方法中調用
//回收越界的對象:(敵人,子彈)
public void outOfBoundsAction() {
//裝活着的敵人的對象的數組
FlyingObject[] fo = new FlyingObject[object.length];
//活着的敵人對象數目
int lifeIndex = 0;
//遍歷數組
for(int i = 0;i<object.length;i++) {
//從數組中獲取敵人的對象
FlyingObject f = object[i];
//找出沒有越界的敵人
if(!f.outOfBounds()&&!f.isRemove()) {
fo[lifeIndex] = f;
lifeIndex++;
}
}
//數組的拷貝
object = Arrays.copyOf(fo, lifeIndex);
//子彈的越界對象的刪除
//定義數組,裝沒有越界的子彈
Bullet[] bo = new Bullet[bullets.length];
//活着的子彈對象數目
int bulletsIndex = 0;
//遍歷數組
for(int i = 0;i<bullets.length;i++) {
//從數組中獲取子彈的對象
Bullet b = bullets[i];
//找出沒有越界的子彈
if(!b.outOfBounds()&&!b.isRemove()) {
bo[bulletsIndex] = b;
bulletsIndex++;
}
}
//數組的拷貝
bullets = Arrays.copyOf(bo, bulletsIndex);
}
7.第七個任務:定義敵人和子彈(英雄機)發生碰撞的方法
- 定義方法,對敵人和子彈(英雄機)是否碰撞,other表示子彈(英雄機) this表示敵人對象
public boolean hit(FlyingObject other) {
/* x軸的範圍:this.x-other.width(左x) this.x+this.width(右x)
y軸的範圍:this.y+this.height(上y) this.y-other.height(下y)
如果子彈的x,y座標在以上範圍內,說明撞上了,返回true,否則返回false */
int x1 = this.x-other.width;
int x2 = this.x + this.width;
int y1 = this.y - other.height;
int y2 = this.y + this.height;
int x = other.x;
int y = other.y;
return x>=x1 && x<=x2 && y>=y1 && y<=y2;
}
(2)定義接口,定義得分的方法
public interface Enemy {
public int getScore();
}
需要大敵機和小敵機實現接口,重寫方法
public int getScore() {
return 1;
}
(3)定義接口,定義福利
public interface Award {//接口中都是公有靜態常量,不用寫屬性,只需類型名字
int DOUBLEFIRE = 0;//帶火力值
int LIFE = 1;//帶名
int getType();
}
需要小蜜蜂實現接口
public int getType() {
return awardType;
}
(4)定義功能方法
//讓敵人去死的方法(在FlyingObject類中實現)
public void goDead() {
state = DEAD;
}
//加命(在Hero類中實現)
public void addLife(){
life++;
}
//獲取命(在Hero類中實現)
public int getLife(){
return life;
}
//增加火力值(在Hero類中實現)
public void addDoubleFire(){
doubleFire+=40;
}
8.第八個任務:當子彈和敵人碰撞之後的得分和福利的設置,並在頁面畫分和命
//子彈和敵人發生碰撞
int score = 0;
public void bulletHitAction(){
//遍歷子彈集合,
for(int i = 0;i<bullets.length;i++){
//拿到一個子彈對象
Bullet b = bullets[i];
for(int j = 0;j<object.length;j++){//遍歷敵人集合
FlyingObject f = object[j];//獲取一個敵人對象
if(b.isLife()&&f.isLife()&&f.hit(b)){//子彈對象和所有的敵人碰撞的匹配
f.goDead();//敵人去死
b.goDead();//子彈去死
if(f instanceof Enemy){//如果是(大敵機或者是小敵機)
score += ((Enemy) f).getScore();//得分
}
if(f instanceof Award){//如果是小蜜蜂
switch(((Award) f).getType()){
case Award.DOUBLEFIRE://帶火力值得小蜜蜂
hero.addDoubleFire();//火力值增加
case Award.LIFE://帶命的小蜜蜂
hero.addLife();//命增加
}
}
}
}
}
}
g.drawString("Scoure:"+score, 10, 40);
g.drawString("Life:"+hero.getLife(), 10, 60);
9.第九個任務:英雄機和敵人發生碰撞:如果碰到的是大(小)敵機,命-1;
如果碰到的是小蜜蜂:火力清0
(1)在Hero類中定義方法:subLife(); clearFire();
//減命
public void subLife(){
life--;
}
//清空火力值
public void clearFire(){
doubleFire = 0;
}
(2)heroHitAction();
//英雄機和敵人碰撞
public void heroHitAction() {
for(int i = 0;i<object.length;i++) //遍歷敵人集合
{
FlyingObject f = object[i]; //獲取一個敵人對象
if(f.isLife()&&f.hit(hero)) {
f.goDead(); //敵人去死
if(f instanceof Enemy) {
hero.subLife();
}
if(f instanceof Award) {
hero.clearFire();
}
}
}
}
10.第10個任務:畫窗口的狀態
- 在World類中定義4個常量,表示窗口的狀態:開始,運行,暫停,結束
public static final int START = 0;
public static final int RUNNING = 1;
public static final int PAUSE = 2;
public static final int GAMEOVER = 3;
private int state = START;
- 設計程序結束的方法,checkGameOverAction();
public void checkGameOverAction() {
if(hero.getLife()==0&&hero.isRemove()) {
state = GAMEOVER;
}
if(hero.getLife()==0)
{
hero.goDead();
}
}
- 在World類中定義3個靜態變量,加載圖片(啓動,暫停,結束)
//存放圖片對象
private static BufferedImage startImage;
private static BufferedImage pauseImage;
private static BufferedImage gameOverImage;
static {
try {
//以讀取流的方式加載圖片
startImage = ImageIO.read(Sky.class.getResource("start.png"));
pauseImage = ImageIO.read(Sky.class.getResource("pause.png"));
gameOverImage = ImageIO.read(Sky.class.getResource("gameover.png"));
}
catch(IOException e) {
e.printStackTrace();
}
}
- 在World類中的paint()方法中根據不同的狀態畫不同的的圖片
switch(state) {
case START:
g.drawImage(startImage, 0, 0, null);
break;
case PAUSE:
g.drawImage(pauseImage, 0, 0, null);
break;
case GAMEOVER:
g.drawImage(gameOverImage, 0, 0, null);
break;
}
- 在不同狀態下,顯示不同的運行情況
MouseAdapter l = new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
if(state == RUNNING) {
int x = e.getX();
int y = e.getY();
hero.move(x, y);
}
}
public void mouseEntered(MouseEvent e) {
if(state == PAUSE) {
state = RUNNING;
}
}
public void mouseExited(MouseEvent e) {
if(state == RUNNING) {
state = PAUSE;
}
}
public void mouseClicked(MouseEvent e) {
if(state == START) {
state = RUNNING;
}
if(state == GAMEOVER) {
//初始化操作
object = new FlyingObject[0];
bullets = new Bullet[0];
score = 0;
hero = new Hero();
state = START;
}
}
};