Java實(shí)現(xiàn)經(jīng)典游戲超級(jí)瑪麗的示例代碼
前言
在你的童年記憶里,是否有一個(gè)蹦跳、頂蘑菇的小人?
如果你回憶起了它,你定然會(huì)覺(jué)得現(xiàn)在它幼稚、無(wú)聊,畫(huà)面不漂亮,游戲不精彩……但請(qǐng)你記住:這才是真正的游戲,它給了你無(wú)限的歡樂(lè)!
馬里奧是靠吃蘑菇成長(zhǎng),聞名世界的超級(jí)巨星。特征是大鼻子、頭戴帽子、身穿背帶工作服、還留著胡子。
如此經(jīng)典的游戲,你怎么能錯(cuò)過(guò),快來(lái)玩玩吧。
《超級(jí)瑪麗》游戲是用java語(yǔ)言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理,設(shè)計(jì)思路用了面向?qū)ο笏枷搿?/p>
主要需求
游戲劇情模擬超級(jí)瑪麗,用swing來(lái)做界面化處理,學(xué)會(huì)利用面向?qū)ο蟮乃枷雽?shí)現(xiàn)這個(gè)游戲
主要設(shè)計(jì)
1、游戲背景的設(shè)計(jì)
2、地圖的顯示
3、臺(tái)階的顯示
4、游戲物品的顯示
5、超級(jí)瑪麗的設(shè)計(jì),左右移動(dòng)能力、跳動(dòng)能力
6、小怪的設(shè)計(jì),包含出現(xiàn)的地點(diǎn)、殺傷功能、跳動(dòng)能力
7、游戲的分?jǐn)?shù)系統(tǒng)設(shè)計(jì)
8、地圖變動(dòng)功能
9、射擊功能
10、游戲采用多線(xiàn)程技術(shù)
11、背景音樂(lè)設(shè)計(jì)
功能截圖
游戲開(kāi)始:
超級(jí)瑪麗跳動(dòng)
換地圖
過(guò)了這一關(guān)
代碼實(shí)現(xiàn)
游戲主界面
public class MyFrame extends JFrame implements KeyListener,Runnable { //用于存儲(chǔ)所有的背景 private List<BackGround> allBg = new ArrayList<>(); //用于存儲(chǔ)當(dāng)前的背景 private BackGround nowBg = new BackGround(); //用于雙緩存 private Image offScreenImage = null; //馬里奧對(duì)象 private Mario mario = new Mario(); //定義一個(gè)線(xiàn)程對(duì)象,用于實(shí)現(xiàn)馬里奧的運(yùn)動(dòng) private Thread thread = new Thread(this); public MyFrame() { //設(shè)置窗口的大小為800 * 600 this.setSize(800,600); //設(shè)置窗口居中顯示 this.setLocationRelativeTo(null); //設(shè)置窗口的可見(jiàn)性 this.setVisible(true); //設(shè)置點(diǎn)擊窗口上的關(guān)閉鍵,結(jié)束程序 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設(shè)置窗口大小不可變 this.setResizable(false); //向窗口對(duì)象添加鍵盤(pán)監(jiān)聽(tīng)器 this.addKeyListener(this); //設(shè)置窗口名稱(chēng) this.setTitle("超級(jí)瑪麗"); //初始化圖片 StaticValue.init(); //初始化馬里奧 mario = new Mario(10,355); //創(chuàng)建全部的場(chǎng)景 for (int i = 1;i <= 3;i++) { allBg.add(new BackGround(i, i == 3 ? true : false)); } //將第一個(gè)場(chǎng)景設(shè)置為當(dāng)前場(chǎng)景 nowBg = allBg.get(0); mario.setBackGround(nowBg); //繪制圖像 repaint(); thread.start(); try { new Music(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { } } @Override public void paint(Graphics g) { if (offScreenImage == null) { offScreenImage = createImage(800,600); } Graphics graphics = offScreenImage.getGraphics(); graphics.fillRect(0,0,800,600); //繪制背景 graphics.drawImage(nowBg.getBgImage(),0,0,this); //繪制敵人 for (Enemy e : nowBg.getEnemyList()) { graphics.drawImage(e.getShow(),e.getX(),e.getY(),this); } //繪制障礙物 for (Obstacle ob : nowBg.getObstacleList()) { graphics.drawImage(ob.getShow(),ob.getX(),ob.getY(),this); } //繪制城堡 graphics.drawImage(nowBg.getTower(),620,270,this); //繪制旗桿 graphics.drawImage(nowBg.getGan(),500,220,this); //繪制馬里奧 graphics.drawImage(mario.getShow(),mario.getX(),mario.getY(),this); //添加分?jǐn)?shù) Color c = graphics.getColor(); graphics.setColor(Color.BLACK); graphics.setFont(new Font("黑體",Font.BOLD,25)); graphics.drawString("當(dāng)前的分?jǐn)?shù)為: " + mario.getScore(),300,100); graphics.setColor(c); //將圖像繪制到窗口中 g.drawImage(offScreenImage,0,0,this); } public static void main(String[] args) { MyFrame myFrame = new MyFrame(); } @Override public void keyTyped(KeyEvent e) { } //當(dāng)鍵盤(pán)按下按鍵時(shí)調(diào)用 @Override public void keyPressed(KeyEvent e) { //向右移動(dòng) if (e.getKeyCode() == 39) { mario.rightMove(); } //向左移動(dòng) if (e.getKeyCode() == 37) { mario.leftMove(); } //跳躍 if (e.getKeyCode() == 38) { mario.jump(); } } //當(dāng)鍵盤(pán)松開(kāi)按鍵時(shí)調(diào)用 @Override public void keyReleased(KeyEvent e) { //想左停止 if (e.getKeyCode() == 37) { mario.leftStop(); } //向右停止 if (e.getKeyCode() == 39) { mario.rightStop(); } } @Override public void run() { while (true) { repaint(); try { Thread.sleep(50); if (mario.getX() >= 775) { nowBg = allBg.get(nowBg.getSort()); mario.setBackGround(nowBg); mario.setX(10); mario.setY(355); } //判斷馬里奧是否死亡 if (mario.isDeath()) { JOptionPane.showMessageDialog(this,"馬里奧死亡!!!"); System.exit(0); } //判斷游戲是否結(jié)束 if (mario.isOK()) { JOptionPane.showMessageDialog(this,"恭喜你!成功通關(guān)了"); System.exit(0); } } catch (InterruptedException e) { e.printStackTrace(); } } } }
馬里奧
public class Mario implements Runnable{ //用于表示橫縱坐標(biāo) private int x; private int y; //用于表示當(dāng)前的狀態(tài) private String status; //用于顯示當(dāng)前狀態(tài)對(duì)應(yīng)的圖像 private BufferedImage show = null; //定義一個(gè)BackGround對(duì)象,用來(lái)獲取障礙物的信息 private BackGround backGround = new BackGround(); //用來(lái)實(shí)現(xiàn)馬里奧的動(dòng)作 private Thread thread = null; //馬里奧的移動(dòng)速度 private int xSpeed; //馬里奧的跳躍速度 private int ySpeed; //定義一個(gè)索引 private int index; //表示馬里奧上升的時(shí)間 private int upTime = 0; //用于判斷馬里奧是否走到了城堡的門(mén)口 private boolean isOK; //用于判斷馬里奧是否死亡 private boolean isDeath = false; //表示分?jǐn)?shù) private int score = 0; public Mario() { } public Mario (int x,int y) { this.x = x; this.y = y; show = StaticValue.stand_R; this.status = "stand--right"; thread = new Thread(this); thread.start(); } //馬里奧的死亡方法 public void death() { isDeath = true; } //馬里奧向左移動(dòng) public void leftMove() { //改變速度 xSpeed = -5; //判斷馬里奧是否碰到旗子 if (backGround.isReach()) { xSpeed = 0; } //判斷馬里奧是否處于空中 if (status.indexOf("jump") != -1) { status = "jump--left"; }else { status = "move--left"; } } //馬里奧向右移動(dòng) public void rightMove() { xSpeed = 5; //判斷馬里奧是否碰到旗子 if (backGround.isReach()) { xSpeed = 0; } if (status.indexOf("jump") != -1) { status = "jump--right"; }else { status = "move--right"; } } //馬里奧向左停止 public void leftStop() { xSpeed = 0; if (status.indexOf("jump") != -1) { status = "jump--left"; }else { status = "stop--left"; } } //馬里奧向右停止 public void rightStop() { xSpeed = 0; if (status.indexOf("jump") != -1) { status = "jump--right"; }else { status = "stop--right"; } } //馬里奧跳躍 public void jump() { if (status.indexOf("jump") == -1) { if (status.indexOf("left") != -1) { status = "jump--left"; }else { status = "jump--right"; } ySpeed = -10; upTime = 7; } //判斷馬里奧是否碰到旗子 if (backGround.isReach()) { ySpeed = 0; } } //馬里奧下落 public void fall() { if (status.indexOf("left") != -1) { status = "jump--left"; }else { status = "jump--right"; } ySpeed = 10; } @Override public void run() { while (true) { //判斷是否處于障礙物上 boolean onObstacle = false; //判斷是否可以往右走 boolean canRight = true; //判斷是否可以往左走 boolean canLeft = true; //判斷馬里奧是否到達(dá)旗桿位置 if (backGround.isFlag() && this.x >= 500) { this.backGround.setReach(true); //判斷旗子是否下落完成 if (this.backGround.isBase()) { status = "move--right"; if (x < 690) { x += 5; }else { isOK = true; } }else { if (y < 395) { xSpeed = 0; this.y += 5; status = "jump--right"; } if (y > 395) { this.y = 395; status = "stop--right"; } } }else { //遍歷當(dāng)前場(chǎng)景里所有的障礙物 for (int i = 0; i < backGround.getObstacleList().size(); i++) { Obstacle ob = backGround.getObstacleList().get(i); //判斷馬里奧是否位于障礙物上 if (ob.getY() == this.y + 25 && (ob.getX() > this.x - 30 && ob.getX() < this.x + 25)) { onObstacle = true; } //判斷是否跳起來(lái)頂?shù)酱u塊 if ((ob.getY() >= this.y - 30 && ob.getY() <= this.y - 20) && (ob.getX() > this.x - 30 && ob.getX() < this.x + 25)) { if (ob.getType() == 0) { backGround.getObstacleList().remove(ob); score += 1; } upTime = 0; } //判斷是否可以往右走 if (ob.getX() == this.x + 25 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)) { canRight = false; } //判斷是否可以往左走 if (ob.getX() == this.x - 30 && (ob.getY() > this.y - 30 && ob.getY() < this.y + 25)) { canLeft = false; } } //判斷馬里奧是否碰到敵人死亡或者踩死蘑菇敵人 for (int i = 0;i < backGround.getEnemyList().size();i++) { Enemy e = backGround.getEnemyList().get(i); if (e.getY() == this.y + 20 && (e.getX() - 25 <= this.x && e.getX() + 35 >= this.x)) { if (e.getType() == 1) { e.death(); score += 2; upTime = 3; ySpeed = -10; }else if (e.getType() == 2) { //馬里奧死亡 death(); } } if ((e.getX() + 35 > this.x && e.getX() - 25 < this.x) && (e.getY() + 35 > this.y && e.getY() - 20 < this.y)) { //馬里奧死亡 death(); } } //進(jìn)行馬里奧跳躍的操作 if (onObstacle && upTime == 0) { if (status.indexOf("left") != -1) { if (xSpeed != 0) { status = "move--left"; } else { status = "stop--left"; } } else { if (xSpeed != 0) { status = "move--right"; } else { status = "stop--right"; } } } else { if (upTime != 0) { upTime--; } else { fall(); } y += ySpeed; } } if ((canLeft && xSpeed < 0) || (canRight && xSpeed > 0)) { x += xSpeed; //判斷馬里奧是否到了最左邊 if (x < 0) { x = 0; } } //判斷當(dāng)前是否是移動(dòng)狀態(tài) if (status.contains("move")) { index = index == 0 ? 1 : 0; } //判斷是否向左移動(dòng) if ("move--left".equals(status)) { show = StaticValue.run_L.get(index); } //判斷是否向右移動(dòng) if ("move--right".equals(status)) { show = StaticValue.run_R.get(index); } //判斷是否向左停止 if ("stop--left".equals(status)) { show = StaticValue.stand_L; } //判斷是否向右停止 if ("stop--right".equals(status)) { show = StaticValue.stand_R; } //判斷是否向左跳躍 if ("jump--left".equals(status)) { show = StaticValue.jump_L; } //判斷是否向右跳躍 if ("jump--right".equals(status)) { show = StaticValue.jump_R; } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public BufferedImage getShow() { return show; } public void setShow(BufferedImage show) { this.show = show; } public void setBackGround(BackGround backGround) { this.backGround = backGround; } public boolean isOK() { return isOK; } public boolean isDeath() { return isDeath; } public int getScore() { return score; } }
小怪
public class Enemy implements Runnable{ //存儲(chǔ)當(dāng)前坐標(biāo) private int x; private int y; //存儲(chǔ)敵人類(lèi)型 private int type; //判斷敵人運(yùn)動(dòng)的方向 private boolean face_to = true; //用于顯示敵人的當(dāng)前圖像 private BufferedImage show; //定義一個(gè)背景對(duì)象 private BackGround bg; //食人花運(yùn)動(dòng)的極限范圍 private int max_up = 0; private int max_down = 0; //定義線(xiàn)程對(duì)象 private Thread thread = new Thread(this); //定義當(dāng)前的圖片的狀態(tài) private int image_type = 0; //蘑菇敵人的構(gòu)造函數(shù) public Enemy(int x,int y,boolean face_to,int type,BackGround bg) { this.x = x; this.y = y; this.face_to = face_to; this.type = type; this.bg = bg; show = StaticValue.mogu.get(0); thread.start(); } //食人花敵人的構(gòu)造函數(shù) public Enemy(int x,int y,boolean face_to,int type,int max_up,int max_down,BackGround bg) { this.x = x; this.y = y; this.face_to = face_to; this.type = type; this.max_up = max_up; this.max_down = max_down; this.bg = bg; show = StaticValue.flower.get(0); thread.start(); } //死亡方法 public void death() { show = StaticValue.mogu.get(2); this.bg.getEnemyList().remove(this); } public int getX() { return x; } public int getY() { return y; } public BufferedImage getShow() { return show; } public int getType() { return type; } @Override public void run() { while (true) { //判斷是否是蘑菇敵人 if (type == 1) { if (face_to) { this.x -= 2; }else { this.x += 2; } image_type = image_type == 1 ? 0 : 1; show = StaticValue.mogu.get(image_type); } //定義兩個(gè)布爾變量 boolean canLeft = true; boolean canRight = true; for (int i = 0;i < bg.getObstacleList().size();i++) { Obstacle ob1 = bg.getObstacleList().get(i); //判斷是否可以右走 if (ob1.getX() == this.x + 36 && (ob1.getY() + 65 > this.y && ob1.getY() - 35 < this.y)) { canRight = false; } //判斷是否可以左走 if (ob1.getX() == this.x - 36 && (ob1.getY() + 65 > this.y && ob1.getY() - 35 < this.y)) { canLeft = false; } } if (face_to && !canLeft || this.x == 0) { face_to = false; } else if ((!face_to) && (!canRight) || this.x == 764) { face_to = true; } //判斷是否是食人花敵人 if (type == 2) { if (face_to) { this.y -= 2; }else { this.y += 2; } image_type = image_type == 1 ? 0 : 1; //食人花是否到達(dá)極限位置 if (face_to && (this.y == max_up)) { face_to = false; } if ((!face_to) && (this.y == max_down)) { face_to = true; } show = StaticValue.flower.get(image_type); } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }
總結(jié)
通過(guò)此次的《超級(jí)瑪麗》游戲?qū)崿F(xiàn),讓我對(duì)JAVA的相關(guān)知識(shí)有了進(jìn)一步的了解,對(duì)java這門(mén)語(yǔ)言也有了比以前更深刻的認(rèn)識(shí)。
java的一些基本語(yǔ)法,比如數(shù)據(jù)類(lèi)型、運(yùn)算符、程序流程控制和數(shù)組等,理解更加透徹。java最核心的核心就是面向?qū)ο笏枷耄瑢?duì)于這一個(gè)概念,終于悟到了一些。
以上就是Java實(shí)現(xiàn)經(jīng)典游戲超級(jí)瑪麗的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java超級(jí)瑪麗游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用RabbitMQ實(shí)現(xiàn)延時(shí)消息自動(dòng)取消的案例詳解
這篇文章主要介紹了使用RabbitMQ實(shí)現(xiàn)延時(shí)消息自動(dòng)取消的簡(jiǎn)單案例,案例代碼包括導(dǎo)包的過(guò)程和相關(guān)配置文件,本文結(jié)合代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2024-03-03java.net.UnknownHostException異常的一般原因及解決步驟
關(guān)于java.net.UnknownHostException大家也許都比較熟悉,這篇文章主要給大家介紹了關(guān)于java.net.UnknownHostException異常的一般原因及解決步驟,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java基于控制臺(tái)的學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07SpringBoot如何監(jiān)控Redis中某個(gè)Key的變化(自定義監(jiān)聽(tīng)器)
這篇文章主要介紹了SpringBoot如何監(jiān)控Redis中某個(gè)Key的變化(自定義監(jiān)聽(tīng)器),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09JXLS根據(jù)模板導(dǎo)出Excel實(shí)例教程
這篇文章主要為大家詳細(xì)介紹了JXLS根據(jù)模板導(dǎo)出Excel實(shí)例教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12