主頁 > 軟體設計 > Java實作超級瑪麗,老程式員的國慶假期泡湯了!

Java實作超級瑪麗,老程式員的國慶假期泡湯了!

2021-10-13 08:48:35 軟體設計

作者簡介

作者名:編程界明世隱
簡介:CSDN博客專家,從事軟體開發多年,精通Java、JavaScript,博主也是從零開始一步步把學習成長、深知學習和積累的重要性,喜歡跟廣大ADC一起打野升級,歡迎您關注,期待與您一起學習、成長、起飛!

<iframe id="tuQ81QIq-1633914049655" src="https://live.csdn.net/v/embed/178190" allowfullscreen="true" data-mediaembed="csdn"></iframe>

超級瑪麗

系列目錄

1. Java俄羅斯方塊
2. Java五子棋小游戲
3. 老Java程式員花一天時間寫了個飛機大戰
4. Java植物大戰僵尸
5. 老Java程式員花2天寫了個連連看
6. Java消消樂(天天愛消除)
7. Java貪吃蛇小游戲
8. Java掃雷小游戲
9. Java坦克大戰
10. Java迷宮小游戲

引言:

國慶前與群里的小伙伴們聊了一下,決定做一下超級瑪麗這個游戲,畢竟以前也經常玩,網上找了一下資源,然后國慶就整起來了,果然程式員不配有假期,我的假期就這樣泡湯了,超級瑪麗你給我發工資,

實作思路

  1. 創建視窗,
  2. 創建加載所有圖片的類,
  3. 創建場景,實體化場景,
  4. 創建障礙物,顯示障礙物,
  5. 創建敵人,創建主執行緒,讓敵人動起來,
  6. 創建馬里奧,顯示馬里奧,
  7. 創建鍵盤事件,
  8. 馬里奧的跳躍、左右移動、死亡等處理,
  9. 處理障礙物的消除,怪物的死亡等,
  10. 其他收尾處理(場景切換,背景音樂),

代碼實作

創建視窗

首先創建一個游戲表單類GameFrame,繼承至JFrame,用來顯示在螢屏上(window的物件),每個游戲都有一個視窗,設定好視窗標題、尺寸、布局等就可以,

package main;

import javax.swing.JFrame;

/**
 *表單類
 */
public class GameFrame extends JFrame {
	//構造方法
	public GameFrame(){
		setTitle("超級瑪麗");//設定標題
		setSize(900, 600);//設定表單大小
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//關閉后行程退出
		setLocationRelativeTo(null);//居中
		setResizable(false);//不允許變大
	}
}

創建面板容器GamePanel繼承至JPanel

package main;

import javax.swing.JPanel;

/**
 * 畫布類
 */
public class GamePanel extends JPanel {
    private GameFrame mainFrame = null;
    private GamePanel panel = null;

  //構造里面初始化相關引數
  public GamePanel(GameFrame frame){
    this.setLayout(null);
    this.setOpaque(false);
    this.mainFrame=frame;
    this.panel =this;
  }
}

再創建一個Main類,來啟動這個視窗,用來啟動,

package main;

//Main類
public class Main {

	public static void main(String[] args) {
		GameFrame frame = new GameFrame();
		GamePanel panel = new GamePanel(frame);
		frame.add(panel);
		frame.setVisible(true);
	}
}

右鍵執行這個Main類,視窗建出來了
在這里插入圖片描述

加載所有的圖片

創建StaticValue類,用來加載圖片,屬性全部定義為static 型別,其中 init 方法,只需呼叫一次,然后加載好所有的圖片,方便后面使用,

package main;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;

public class StaticValue {

  //存盤馬里奧的圖片
  public static List<BufferedImage> allMarioImage = new ArrayList<BufferedImage>();
  //開始圖片
  public static BufferedImage startImage = null;
  //結束圖片
  public static BufferedImage endImage = null;
  //背景圖片
  public static BufferedImage bgImage = null;
  //食人花圖片
  public static List<BufferedImage> allFlowerImage = new ArrayList<BufferedImage>();
  //敵人圖片
  public static List<BufferedImage> allTriangleImage = new ArrayList<BufferedImage>();
  //烏龜圖片
  public static List<BufferedImage> allTurtleImage = new ArrayList<BufferedImage>();
  //障礙物圖片
  public static List<BufferedImage> allObstructionImage = new ArrayList<BufferedImage>();
  //馬里奧死亡圖片
  public static BufferedImage mariDeadImage = null;
  //定義檔案路徑
  public static String ImagePath = "/image/";

  //將圖片初始化
  public static void init() {

    String path = "";
    //瑪麗奧圖片初始化
    for (int i = 1; i <= 10; i++) {
      try {
        path = ImagePath + i + ".png";

        allMarioImage.add(ImageIO.read(StaticValue.class.getResource(path)));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    //匯入背景圖片
    try {
      startImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "start.jpg"));
      bgImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "firststage.jpg"));
      endImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "firststageend.jpg"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    //匯入敵人圖片
    for (int i = 1; i <= 5; i++) {
      try {
        if (i <= 2) {
          allFlowerImage
              .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "flower" + i + ".png")));
        }
        if (i <= 3) {
          allTriangleImage.add(
              ImageIO.read(StaticValue.class.getResource(ImagePath + "triangle" + i + ".png")));
        }
        allTurtleImage
            .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "Turtle" + i + ".png")));
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    //匯入障礙物圖片
    for (int i = 1; i <= 12; i++) {
      try {
        allObstructionImage
            .add(ImageIO.read(StaticValue.class.getResource(ImagePath + "ob" + i + ".png")));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    //匯入瑪麗奧死亡圖片
    try {
      mariDeadImage = ImageIO.read(StaticValue.class.getResource(ImagePath + "over.png"));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

創建場景

創建場景的背景

有7個場景,前6個的背景圖如下:
在這里插入圖片描述
第7個背景圖如下:
在這里插入圖片描述
其實就是多了個旗桿和城堡,用來結束游戲的,這里在設定背景的時候有些區別,我們來定義BackGround類,

定義BackGround類

  1. sort代表場景的數字,比如第一個場景就是1,
  2. flag為true就是最后一個場景,所以最后一個場景的圖片有點不一樣,
package main;

import java.awt.image.BufferedImage;

public class BackGround {
  //當前場景圖片
  private BufferedImage bgImage = null;
  //場景順序
  private int sort;
  //是否為最后的場景
  private boolean flag;
  //游戲結束標記
  private boolean isOver = false;
  //定義降旗結束
  private boolean isDown = false;

  //構造方法
  public BackGround(int sort,boolean flag) {
    this.sort = sort;
    this.flag = flag;
    if (flag) {//最后一個場景
      bgImage = StaticValue.endImage;
    } else {//1-6場景
      bgImage = StaticValue.bgImage;
    }
  }
    //繪制
  public void draw(Graphics g) {
    g.drawImage(bgImage,0,0,null);
  }
}

實體化場景

  1. 在GamePanel類中加入相關成員
//存全部7個場景的集合
private List<BackGround> allBG = new ArrayList<BackGround>();
 //存當前場景
private BackGround nowBG = null;
  1. 在GamePanel類中加入init方法,此方法用來做游戲的全部初始化操作,比如 初始化圖片、創建背景(包含障礙物、敵人等)、設定當前背景,
//初始化
private void init() {
  //圖片初始化
  StaticValue.init();

  //創建全部場景
  for (int i = 1; i <= 7; i++) {
    //i==7?true:false  最后一個場景有點區別,有個結束的城堡
    this.allBG.add(new BackGround(i, i == 7 ? true : false));
  }
  //將第一個場景設定為當前場景
  this.nowBG = this.allBG.get(0);
}

在GamePanel中重寫paint方法,并在此方法中繪制背景,

@Override
  public void paint(Graphics g) {
    super.paint(g);
    //繪制背景
    this.nowBG.draw(g);
  }

運行一下,背景被繪制到視窗上了,
在這里插入圖片描述

創建障礙物類

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Obstruction implements Runnable{
    //坐標
    private int x;
    private int y;

    //控制旗子
    private Thread t = new Thread(this);

    //型別
    private int type;
    //初始型別
    private int starttype;
    //顯示圖片
    private BufferedImage showImage = null;

    //取得場景
    private BackGround bg;

    //構造方法
    public Obstruction(int x,int y,int type,BackGround bg){
        this.x = x;
        this.y = y;
        this.type = type;
        this.starttype = type;
        this.bg = bg;
        setImage();
        if(this.type == 11){
            t.start();
        }
    }

    //繪制
    public void draw(Graphics g) {
        g.drawImage(showImage,x,y,null);
    }

    //重置方法
    public void reset(){
        this.type = starttype;
        this.setImage();
    }

    //根據狀態改變顯示圖片
    public void setImage(){
        showImage = StaticValue.allObstructionImage.get(type);
    }

    public BufferedImage getShowImage() {
        return showImage;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }

    public void run() {
        while(true){
            if(this.bg.isOver()){
                if(this.y < 420){
                    this.y += 5;
                }else{
                    this.bg.setDown(true);
                }
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

障礙物介紹

總共有12種障礙物,圖片如下:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

修改BackGround類

加入繪制障礙物的方法,比如第一個場景的 buildBackGround1()

注意點:
比如:this.allObstruction.add(new Obstruction(i * 60, 540, 9, this));
這里傳入的是9,但其實取得是第10個障礙物
在這里插入圖片描述
因為我們在StaticValue存障礙物的集合allObstructionImage,集合是從0開始的,所以這里傳入9等于取到的是第10個障礙物,其他的一樣的意思,

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

public class BackGround {
  //當前場景圖片
  private BufferedImage bgImage = null;
  //場景順序
  private int sort;
  //是否為最后的場景
  private boolean flag;
  //游戲結束標記
  private boolean isOver = false;
  //定義降旗結束
  private boolean isDown = false;

  //用集合保存障礙物
  private List<Obstruction> allObstruction = new ArrayList<Obstruction>();
  //被消滅的障礙物
  private List<Obstruction> removeObstruction = new ArrayList<Obstruction>();

  //構造方法
  public BackGround(int sort,boolean flag) {
    this.sort = sort;
    this.flag = flag;
    if (flag) {//最后一個場景
      bgImage = StaticValue.endImage;
    } else {//1-6場景
      bgImage = StaticValue.bgImage;
    }

    //根據場景來配置對應的背景
    switch (sort){
      case 1:
        buildBackGround1();
        break;
      case 2:
        buildBackGround2();
        break;
      case 3:
        buildBackGround3();
        break;
      case 4:
        buildBackGround4();
        break;
      case 5:
        buildBackGround5();
        break;
      case 6:
        buildBackGround6();
        break;
      case 7:
        buildBackGround7();
        break;
    }
  }

  //第1個場景
  void buildBackGround1() {
	//繪制地面
    for (int i = 0; i < 15; i++) {
      this.allObstruction.add(new Obstruction(i * 60, 540, 9, this));
    }

    //繪制磚塊和問號
    this.allObstruction.add(new Obstruction(120, 360, 4, this));
    this.allObstruction.add(new Obstruction(300, 360, 0, this));
    this.allObstruction.add(new Obstruction(360, 360, 4, this));
    this.allObstruction.add(new Obstruction(420, 360, 0, this));
    this.allObstruction.add(new Obstruction(480, 360, 4, this));
    this.allObstruction.add(new Obstruction(540, 360, 0, this));
    this.allObstruction.add(new Obstruction(420, 180, 4, this));

    //繪制水管
    this.allObstruction.add(new Obstruction(660, 540, 6, this));
    this.allObstruction.add(new Obstruction(720, 540, 5, this));
    this.allObstruction.add(new Obstruction(660, 480, 8, this));
    this.allObstruction.add(new Obstruction(720, 480, 7, this));
    //隱藏磚塊
    this.allObstruction.add(new Obstruction(660, 300, 3, this));
  }
  void buildBackGround2(){}
  void buildBackGround3(){}
  void buildBackGround4(){}
  void buildBackGround5(){}
  void buildBackGround6(){}
  void buildBackGround7(){}
  //繪制背景
  public void draw(Graphics g) {
    g.drawImage(bgImage,0,0,null);
  }

  public boolean isFlag() {
    return flag;
  }

  public boolean isOver() {
    return isOver;
  }

  public void setOver(boolean isOver) {
    this.isOver = isOver;
  }

  public boolean isDown() {
    return isDown;
  }

  public void setDown(boolean isDown) {
    this.isDown = isDown;
  }

  public int getSort() {
    return sort;
  }

  public List<Obstruction> getRemoveObstruction() {
    return removeObstruction;
  }
  //回傳所有的障礙物
  public List<Obstruction> getAllObstruction() {
    return allObstruction;
  }

}

繪制障礙物到視窗

//繪制障礙物
private void drawObstruction(Graphics g) {
	//繪制障礙物
	Obstruction ob = null;
	Iterator<Obstruction> iter = this.nowBG.getAllObstruction().iterator();
	while(iter.hasNext()){
		ob = iter.next();
		ob.draw(g);
	}
}

在paint方法中呼叫它

@Override
public void paint(Graphics g) {
  super.paint(g);
  //繪制背景
  this.nowBG.draw(g);
  //繪制障礙物
  drawObstruction(g);
}

運行一下,第一個場景的障礙物就繪制出來了, ,

定義敵人類

  1. 因為這里的敵人有兩類,一類是蘑菇怪,一類是食人花,所以定義了2個構造,分別是創建不同型別的敵人,
  2. 執行緒先默認加好,因為敵人要運動的,待會在來具體寫run方法,
package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Enemy implements Runnable{
    //坐標
    private int x;
    private int y;
    //初始坐標
    private int startx;
    private int starty;
    //怪物型別
    private int type;
    //顯示圖片
    private BufferedImage showImage;
    //移動方向
    private boolean isLeftOrUp = true;
    //移動范圍
    private int upMax = 0;
    private int downMax = 0;
    //加入執行緒
    private Thread t = null;

    //定義圖片變化
    private int imageType = 0;

    //定義所在場景
    private BackGround bg ;
    //存活狀態
    private boolean alive = false;
    //蘑菇怪
    public Enemy(int x,int y,boolean isLeft,int type,BackGround bg){
        this.x = x;
        this.y = y;
        this.startx = x;
        this.starty = y;
        this.isLeftOrUp = isLeft;
        this.type = type;
        this.bg = bg;

        if(type==1){
            this.showImage = StaticValue.allTriangleImage.get(0);
        }
        this.t = new Thread(this);
        t.start();
    }
    //食人花
    public Enemy(int x,int y,boolean isUp,int type,int upMax,int downMax,BackGround bg){
        this.x = x;
        this.y = y;
        this.startx = x;
        this.starty = y;
        this.isLeftOrUp = isUp;
        this.type = type;
        this.upMax = upMax;
        this.downMax = downMax;
        this.bg = bg;

        if(type==2){
            this.showImage = StaticValue.allFlowerImage.get(0);
        }
        this.t = new Thread(this);
        t.start();
    }
    //繪制
    public void draw(Graphics g){
        g.drawImage(showImage,x,y,null);
    }

    //現場的run方法
    public void run() {
        while (true) {
            if(alive){
               
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public BufferedImage getShowImage() {
        return showImage;
    }
    public void setBg(BackGround bg) {
        this.bg = bg;
    }
    public int getType() {
        return type;
    }

    public void startMove(){
        alive = true;
    }
}

場景中初始化敵人,修改buildBackGround1 方法,加入以下代碼,

//繪制怪物
    this.allEnemy.add(new Enemy(600, 480, true, 1,this));
    //繪制食人花
    this.allEnemy.add(new Enemy(690, 540, true, 2, 420, 540,this));

在GamePanel類中創建方法,并在paint中呼叫,繪制出敵人,

//繪制敵人
	private void drawEnemy(Graphics g){
		//繪制怪物敵人
		Iterator<Enemy> iterEnemy = this.nowBG.getAllEnemy().iterator();
		while(iterEnemy.hasNext()){
			Enemy e = iterEnemy.next();
			e.draw(g);
		}
	}

運行
在這里插入圖片描述

讓敵人運動起來

一、蘑菇怪運動

  1. 先向左運動,讓其X坐標遞減就行,到最左邊后反過來向右運動,坐標依次遞增,碰到障礙物反過來繼續,
  2. 每次執行緒執行的時候,要切換圖片哦,

修改Enemy類的run方法(同時把alive先默認設定為true,測驗用)

if(alive){
    //判斷怪物型別
    if (type == 1) {
        //左右移動
        if (this.isLeftOrUp) {
            this.x -= 5;
        } else {
            this.x += 5;
        }
        //imageType的切換來達到圖片的切換
        if (imageType == 0) {
            imageType = 1;
        } else {
            imageType = 0;
        }

        //定義標記
        boolean canLeft = true;
        boolean canRight = true;

        for (int i = 0; i < this.bg.getAllObstruction().size(); i++) {
            Obstruction ob = this.bg.getAllObstruction().get(i);
            //不能向右移動
            if (ob.getX() == this.x + 60 && (ob.getY() + 50 > this.y
                && ob.getY() - 50 < this.y)) {
                canRight = false;
            }
            //不能向左移動
            if (ob.getX() == this.x - 60 && (ob.getY() + 50 > this.y
                && ob.getY() - 50 < this.y)) {
                canLeft = false;
            }
        }

        if (!canLeft && this.isLeftOrUp || this.x == 0) {
            this.isLeftOrUp = false;
        } else if (!canRight && !this.isLeftOrUp || this.x == 840) {
            this.isLeftOrUp = true;
        }

        this.showImage = StaticValue.allTriangleImage.get(imageType);
    }
}

在GamePanel加入主執行緒代碼,

private class RefreshThread implements Runnable {

    @Override
    public void run() {
      while (true) {
        if (!"end".equals(gameFlag)) {
          repaint();
        }
        try {
          Thread.sleep(50);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

建構式里面呼叫此執行緒
在這里插入圖片描述
運行效果:
在這里插入圖片描述

二、食人花運動

  1. 向上運動在遞減y坐標,向下運動遞增y坐標,
  2. 每次切換圖片
  3. 達到最高處,則反過來往下;達到最低處,反過來往上;

在Enemy類中的run方法加入以下代碼:

if (type == 2) {
    if (this.isLeftOrUp) {//向上運動
        this.y -= 5;
    } else {//向下運動
        this.y += 5;
    }
    //imageType的切換來達到圖片的切換
    if (imageType == 0) {
        imageType = 1;
    } else {
        imageType = 0;
    }
    //達到最高處,則反過來往下
    if (this.isLeftOrUp && this.y == this.upMax) {
        this.isLeftOrUp = false;
    }
    //達到最低處,則反過來往上
    if (!this.isLeftOrUp && this.y == this.downMax) {
        this.isLeftOrUp = true;
    }
    this.showImage = StaticValue.allFlowerImage.get(imageType);
}

在這里插入圖片描述

加入馬里奧

創建類

package main;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Mario implements Runnable {

    //坐標
    private int x;
    private int y;
    //定義瑪麗奧所在場景
    private BackGround bg;
    //加入執行緒
    private Thread t = null;
    //移動速度e
    private int xmove = 0;
    //跳躍速度
    private int ymove = 0;

    private int speed = 5;
    //狀態
    private String status;
    //顯示圖片
    private BufferedImage showImage;
    //生命和分數
    private int score;
    private int life;

    //當前移動中的圖片
    private int moving = 0;

    //跳躍時間
    private int upTime = 0;

    //標記瑪麗奧是否死亡
    private boolean isDead = false;

    //完成游戲,游戲結束
    private boolean isClear = false;

    //構造方法
    public Mario(int x, int y) {
        this.x = x;
        this.y = y;
        //初始化瑪麗奧圖片
        this.showImage = StaticValue.allMarioImage.get(0);
        this.score = 0;
        this.life = 3;

        this.t = new Thread(this);
        t.start();

        this.status = "right-standing";
    }

    public void draw(Graphics g) {
        g.drawImage(showImage, x, y, null);
    }

    public void run() {
        while(true){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public void setBg(BackGround bg) {
        this.bg = bg;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public boolean isDead() {
        return isDead;
    }


    public int getScore() {
        return score;
    }


    public void setScore(int score) {
        this.score = score;
    }


    public int getLife() {
        return life;
    }


    public void setLife(int life) {
        this.life = life;
    }

    public boolean isClear() {
        return isClear;
    }

    public void setClear(boolean isClear) {
        this.isClear = isClear;
    }
}

修改init方法,加入馬里奧的初始化

//初始化
  private void init() {
    //圖片初始化
    StaticValue.init();

    //創建全部場景
    for (int i = 1; i <= 7; i++) {
      //i==7?true:false  最后一個場景有點區別,有個結束的城堡
      this.allBG.add(new BackGround(i, i == 7 ? true : false));
    }

    //將第一個場景設定為當前場景
    this.nowBG = this.allBG.get(0);

    //初始化瑪麗奧
    this.mario = new Mario(0, 480);
    //將瑪麗奧放入場景中
    this.mario.setBg(nowBG);
  }

paint方法中繪制馬里奧
在這里插入圖片描述

運動

移動代碼

  public void leftMove(){
        //移動速度
        xmove = -speed;
        //改變狀態
        //如果當前已經是跳躍,應該保持原有狀態,不能再改變
        if(this.status.indexOf("jumping") != -1){
            this.status = "left-jumping";
        }else{
            this.status = "left-moving";
        }
    }

    public void rightMove(){
        xmove = speed;
        if(this.status.indexOf("jumping") != -1){
            this.status = "right-jumping";
        }else{
            this.status = "right-moving";
        }
    }

    public void leftStop(){
        this.xmove = 0;
        if(this.status.indexOf("jumping") != -1){
            this.status = "left-jumping";
        }else{
            this.status = "left-standing";
        }
    }

    public void rightStop(){
        this.xmove = 0;
        if(this.status.indexOf("jumping") != -1){
            this.status = "right-jumping";
        }else{
            this.status = "right-standing";
        }
    }

跳躍和死亡方法

 public void jump(){
        if(this.status.indexOf("jumping") == -1){
            if(this.status.indexOf("left") != -1){
                this.status = "left-jumping";
            }else{
                this.status = "right-jumping";
            }
            ymove = -10;
            upTime = 18;
        }
    }

    //下落方法
    public void down(){
        if(this.status.indexOf("left") != -1){
            this.status = "left-jumping";
        }else{
            this.status = "right-jumping";
        }
        ymove = 10;
    }
    //死亡方法
    public void dead(){
        this.life--;
        if(this.life == 0){
            this.isDead = true;
        }else{
            if(!isDead){
            }

            this.x = 0;
            this.y = 480;
        }
    }

加入鍵盤事件

在GamePanel中加入鍵盤事件,并在構造方法在呼叫,

//添加鍵盤監聽
	private void createKeyListener() {
		KeyAdapter l = new KeyAdapter() {
			//按下
			@Override
			public void keyPressed(KeyEvent e) {
				int key = e.getKeyCode();

				if("start".equals(gameFlag)){
					switch (key) {
						//向上
						case KeyEvent.VK_UP:
						case KeyEvent.VK_W:
							mario.jump();
							break;

						//向右
						case KeyEvent.VK_RIGHT:
						case KeyEvent.VK_D:
							mario.rightMove();
							break;

						//向左
						case KeyEvent.VK_LEFT:
						case KeyEvent.VK_A:
							mario.leftMove();
							break;

						//空格
						case KeyEvent.VK_SPACE:
							//起跳
							mario.jump();
							break;
					}
				}else if("load".equals(gameFlag)||"end".equals(gameFlag)){
					//游戲開始
					//gameStart();
				}
			}
			//松開
			@Override
			public void keyReleased(KeyEvent e) {
				if("start".equals(gameFlag)){
					int key = e.getKeyCode();
					//控制瑪麗奧的停止
					if(key==KeyEvent.VK_RIGHT||key==KeyEvent.VK_D){
						mario.rightStop();
					}
					if(key==KeyEvent.VK_LEFT||key==KeyEvent.VK_A){
						mario.leftStop();
					}

				}
			}
			
		};
		//給主frame添加鍵盤監聽
		mainFrame.addKeyListener(l);
	}

修改馬里奧類的run方法

public void run() {
    while(true){
        //判斷是否與障礙物碰撞
        //定義標記
        if(this.bg.isFlag() && this.x >= 520){
            if(!this.bg.isOver()){
            }
            this.bg.setOver(true);
            if(this.bg.isDown()){
                //降旗后瑪麗奧開始移
                this.status = "right-moving";
                if(this.x < 580){
                    //向右
                    this.x += 5;
                }else{
                    if(this.y < 480){
                        //向下
                        this.y += 5;
                    }
                    this.x += 5;
                    if(this.x >= 780){
                        //游戲結束
                        this.setClear(true);
                    }
                }
            }else{
                //如果為最后一個場景,同事Mario的x坐標到了550,游戲結束
                //自動控制瑪麗奧
                if(this.y < 420){
                    this.y += 5;
                }
                if(this.y >= 420){
                    this.y = 420;
                    this.status = "right-standing";
                }
            }
        }else{
            boolean canLeft = true;
            boolean canRight = true;
            //能否跳躍標記
            boolean onLand = false;
            for(int i=0;i<this.bg.getAllObstruction().size();i++){
                Obstruction ob = this.bg.getAllObstruction().get(i);

                if(this.status.indexOf("jumping") != -1){//在空中
                    //不能向右移動
                    if((ob.getX()<=this.x+60 && this.x <ob.getX() )&& (ob.getY()+50>this.y && ob.getY()-50<this.y)){
                        if(ob.getType() != 3){
                            canRight = false;
                        }
                    }
                    //不能向左移動
                    if((ob.getX()>=this.x-60 && this.x >ob.getX())&& (ob.getY()+50>this.y && ob.getY()-50<this.y)){
                        if(ob.getType() != 3){
                            canLeft = false;
                        }
                    }
                }else{

                    //不能向右移動
                    if(ob.getX()==this.x+60 && (ob.getY()+50>this.y && ob.getY()-50<this.y)){
                        if(ob.getType() != 3){
                            canRight = false;
                        }
                    }
                    //不能向左移動
                    if(ob.getX()==this.x-60 && (ob.getY()+50>this.y && ob.getY()-50<this.y)){
                        if(ob.getType() != 3){
                            canLeft = false;
                        }
                    }
                }

                //判斷能否跳躍
                if(ob.getY()==this.y+60 && (ob.getX()+60>this.x && ob.getX()-60<this.x)){
                    if(ob.getType() != 3){
                        onLand = true;
                    }
                }
                //判斷瑪麗奧跳躍時是否撞到障礙物
                if(ob.getY()==this.y-60 && (ob.getX()+50>this.x && ob.getX()-50<this.x)){
                    //如果是磚塊
                    if(ob.getType()==0){
                        //移除磚塊
                        this.bg.getAllObstruction().remove(ob);
                        //保存到移除的障礙物中
                        this.bg.getRemoveObstruction().add(ob);
                    }
                    //如果是問號||隱藏的磚塊
                    if((ob.getType()==4 || ob.getType()==3) && upTime > 0){
                        //增加分數
                        score += 10;

                        ob.setType(2);
                        ob.setImage();
                    }
                    upTime = 0;
                }
            }

            //對敵人的判斷
            for(int i=0;i<this.bg.getAllEnemy().size();i++){
                Enemy e = this.bg.getAllEnemy().get(i);
                if((e.getX()+50>this.x && e.getX()-50<this.x) && (e.getY()+60>this.y && e.getY()-60<this.y)){
                    //瑪麗奧死亡
                    this.dead();
                    canLeft=false;
                    canRight=false;
                }
                if(e.getY()==this.y+60 && (e.getX()+60>this.x && e.getX()-60<this.x)){
                    if(e.getType() == 1){
                        //e.dead();
                        this.upTime = 5;
                        this.ymove = -10;
                        //敵人死亡,增加分數
                        score += 10;
                    }else if(e.getType() == 2){
                        this.dead();
                        canLeft=false;
                        canRight=false;
                    }
                }
            }



            if(onLand && upTime == 0){
                if(this.status.indexOf("left") != -1){
                    if(xmove != 0){
                        this.status = "left-moving";
                    }else{
                        this.status = "left-standing";
                    }
                }else{
                    if(xmove != 0){
                        this.status = "right-moving";
                    }else{
                        this.status = "right-standing";
                    }
                }
            }else{
                //上升狀態
                if(upTime != 0){
                    upTime--;
                }else{
                    this.down();
                }
                y += ymove;
            }

            if(this.y>600){
                this.dead();
                canLeft=false;
                canRight=false;
            }


            if(canLeft && xmove<0 || canRight && xmove>0){
                x += xmove;
                if(x<0){
                    x = 0;
                }
            }
        }

        //默認向右
        int temp = 0;
        //向左狀態
        if(this.status.indexOf("left") != -1){
            temp += 5;
        }

        //判斷是否移動
        if(this.status.indexOf("moving") != -1){
            temp += this.moving;
            moving++;
            if(moving==4){
                this.moving = 0;
            }
        }

        if(this.status.indexOf("jumping") != -1){
            temp += 4;
        }

        //改變顯示圖片
        this.showImage = StaticValue.allMarioImage.get(temp);

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在這里插入圖片描述

加入其他場景的代碼

//第2個場景
void buildBackGround2(){

  for(int i=0;i<15;i++){
    if(i != 9 && i != 10 && i != 11 ){
      this.allObstruction.add(new Obstruction(i*60, 540, 9,this));
    }
  }
  //繪制水管
  this.allObstruction.add(new Obstruction(60, 540, 6,this));
  this.allObstruction.add(new Obstruction(120, 540, 5,this));
  this.allObstruction.add(new Obstruction(60, 480, 6,this));
  this.allObstruction.add(new Obstruction(120, 480, 5,this));
  this.allObstruction.add(new Obstruction(60, 420, 8,this));
  this.allObstruction.add(new Obstruction(120, 420, 7,this));

  this.allObstruction.add(new Obstruction(300, 540, 6,this));
  this.allObstruction.add(new Obstruction(360, 540, 5,this));
  this.allObstruction.add(new Obstruction(300, 480, 6,this));
  this.allObstruction.add(new Obstruction(360, 480, 5,this));
  this.allObstruction.add(new Obstruction(300, 420, 6,this));
  this.allObstruction.add(new Obstruction(360, 420, 5,this));
  this.allObstruction.add(new Obstruction(300, 360, 8,this));
  this.allObstruction.add(new Obstruction(360, 360, 7,this));

  //繪制怪物
  this.allEnemy.add(new Enemy(330, 360, true, 2, 300, 420,this));
}

//第3個場景
void buildBackGround3(){
  for(int i=0;i<15;i++){
    this.allObstruction.add(new Obstruction(i*60, 540, 9,this));
  }

  //繪制磚塊和問號
  this.allObstruction.add(new Obstruction(180, 360, 4,this));
  this.allObstruction.add(new Obstruction(420, 360, 4,this));
  this.allObstruction.add(new Obstruction(660, 360, 4,this));
  this.allObstruction.add(new Obstruction(420, 180, 4,this));

}

//第4個場景
void buildBackGround4(){

  for(int i=0;i<15;i++){
    if(i<2||i>12){
      this.allObstruction.add(new Obstruction(i*60, 540, 9,this));
    }
  }
  this.allObstruction.add(new Obstruction(120, 360, 0,this));
  this.allObstruction.add(new Obstruction(180, 360, 0,this));
  this.allObstruction.add(new Obstruction(300, 180, 0,this));
  this.allObstruction.add(new Obstruction(360, 180, 0,this));
  this.allObstruction.add(new Obstruction(420, 180, 0,this));
  this.allObstruction.add(new Obstruction(480, 180, 0,this));
  this.allObstruction.add(new Obstruction(540, 180, 0,this));
  this.allObstruction.add(new Obstruction(660, 360, 0,this));
  this.allObstruction.add(new Obstruction(720, 360, 0,this));

}

//第5個場景
void buildBackGround5(){

  int z = 2;
  for(int i=0;i<15;i++){
    if(i%2==0 && i<7){
      this.allObstruction.add(new Obstruction(i*60, 540-(i*60), 9,this));
      for(int x=i;x>0;x--){
        this.allObstruction.add(new Obstruction(i*60, 540-(x*60)+60, 10,this));
      }
    }
    if(i%2==0 && i>7){
      this.allObstruction.add(new Obstruction(i*60, 540-((i-z)*60), 9,this));
      for(int x=i-z;x>0;x--){
        this.allObstruction.add(new Obstruction(i*60, 540-(x*60)+60, 10,this));
      }
      z+=4;
    }
  }

}

//第6個場景
void buildBackGround6(){

  for(int i=0;i<15;i++){
    this.allObstruction.add(new Obstruction(i*60, 540, 9,this));
  }
  this.allObstruction.add(new Obstruction(480, 480, 1,this));
  this.allObstruction.add(new Obstruction(480, 420, 1,this));
  this.allObstruction.add(new Obstruction(480, 360, 1,this));
  this.allObstruction.add(new Obstruction(480, 300, 1,this));
  this.allObstruction.add(new Obstruction(480, 240, 1,this));
  this.allObstruction.add(new Obstruction(480, 180, 1,this));
  this.allObstruction.add(new Obstruction(540, 240, 1,this));
  this.allObstruction.add(new Obstruction(540, 300, 1,this));
  this.allObstruction.add(new Obstruction(540, 360, 1,this));
  this.allObstruction.add(new Obstruction(540, 420, 1,this));
  this.allObstruction.add(new Obstruction(540, 480, 1,this));
  this.allObstruction.add(new Obstruction(600, 300, 1,this));
  this.allObstruction.add(new Obstruction(600, 360, 1,this));
  this.allObstruction.add(new Obstruction(600, 420, 1,this));
  this.allObstruction.add(new Obstruction(600, 480, 1,this));
  this.allObstruction.add(new Obstruction(660, 360, 1,this));
  this.allObstruction.add(new Obstruction(660, 420, 1,this));
  this.allObstruction.add(new Obstruction(660, 480, 1,this));
  this.allObstruction.add(new Obstruction(720, 420, 1,this));
  this.allObstruction.add(new Obstruction(720, 480, 1,this));
  this.allObstruction.add(new Obstruction(780, 480, 1,this));

  //通關要點,隱形磚塊
  this.allObstruction.add(new Obstruction(300, 360, 3,this));
}
//第7個場景
void buildBackGround7(){

  for(int i=0;i<15;i++){
    this.allObstruction.add(new Obstruction(i*60, 540, 9,this));
  }
  this.allObstruction.add(new Obstruction(490, 180, 11,this));
  this.allObstruction.add(new Obstruction(520, 480, 2,this));
  //地上障礙物
  this.allObstruction.add(new Obstruction(240, 360, 1,this));
  this.allObstruction.add(new Obstruction(240, 420, 1,this));
  this.allObstruction.add(new Obstruction(240, 480, 1,this));
  this.allObstruction.add(new Obstruction(180, 420, 1,this));
  this.allObstruction.add(new Obstruction(180, 480, 1,this));
  this.allObstruction.add(new Obstruction(120, 480, 1,this));
}

最后

加入積分、生命、場景切換、游戲結束、背景音樂等就完成了

在這里插入圖片描述

看到這里的大佬,動動發財的小手 點贊 + 回復 + 收藏,能【 關注 】一波就更好了,

代碼獲取方式
訂閱我的專欄《Java游戲大全》后,可以查看專欄內所有的文章,并且聯系博主免費獲取其中1-3份你心儀的源代碼,專欄的文章都是上過csdn熱榜的,值得信賴!專欄內目前有[ 13 + 1 ] 篇實體,未來2個月內專欄會更新到15篇以上,一般2周一更,了解一下我的專欄

更多精彩

1. Java俄羅斯方塊
2. 老Java程式員花2天寫了個連連看
3. 老Java程式員花一天時間寫了個飛機大戰
4. Java五子棋人機版
5. Java植物大戰僵尸
6. Java消消樂(天天愛消除)
7. Java貪吃蛇小游戲
8. Java掃雷小游戲
9. Java坦克大戰

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/310620.html

標籤:其他

上一篇:如何快速學會別人的代碼和思維

下一篇:Java期末大作業基礎專案--在線學生選課系統(建議收藏)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more