【Java】游戏小程序-超级玛丽(代码渗入)
一、游戲基本功能
1、能夠向左向右行走(鍵盤監(jiān)聽)
2、能夠跳躍
3、能夠發(fā)射子彈
4、能夠檢測和障礙物之間的碰撞
5、背景圖片的移動
二、游戲運行界面
三、游戲大致實現(xiàn)思路:
1.窗體
2.自己角色的添加
3.背景圖片的添加
4.背景圖片的移動
5.人物的移動和跳躍
6.磚頭、水管等等障礙物的添加
7.任務(wù)和障礙物的碰撞
難點分析:
1.人物的多鍵控制
1)給人物設(shè)定方向boolean變量:向左、向右、向上、向下
2)通過鍵盤監(jiān)聽來修改方向的變量值
按下某個鍵的時候,我們把相應(yīng)方向改為true,釋放的時候改false
2.地圖配置
自定義文件讀取方式實現(xiàn):文件流的使用和字符串String類的方法調(diào)用
3.碰撞檢測
封裝一個Rectangle類的對象
4.子彈添加
1)先定義一個容器,這個用于封裝所有的子彈對象
2)按下某個鍵的時候,創(chuàng)建一個子彈對象(以角色的坐標為基準初始化)
3)把子彈對象添加到容器當(dāng)中
4)在paint方法中,遍歷容器,取出子彈對象并進行繪制
5)檢測子彈如果超出了窗體邊界,則需要把當(dāng)前子彈從容器當(dāng)中移除掉
四、程序源代碼:
代碼結(jié)構(gòu)圖:分了三個包、敵人類包、游戲界面類包、游戲地圖配置包
mario包:
主體框架
import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.util.ArrayList;import javax.swing.ImageIcon; import javax.swing.JFrame;import com.huaxin.enery.Enery; import com.huaxin.enery.Pipe;import Util.Map;public class GameFrame extends JFrame{public Mario mario;public Enery pipe,cion,brick;//背景圖片public BackgroundImage bg ;//容器裝敵人public ArrayList<Enery> eneryList = new ArrayList<Enery>();//子彈容器public ArrayList<Boom> boomList = new ArrayList<Boom>();//子彈的速度public int bspeed=0;//畫地圖,制定規(guī)則,是1畫磚頭,是2畫金幣,是3畫水管public int [][] map =null;//構(gòu)造函數(shù)里面初始化背景圖片和馬里奧對象public GameFrame() throws Exception {mario = new Mario(this);mario.start();Map mp= new Map();bg = new BackgroundImage();//窗體重繪線程new Thread(){public void run(){while(true){//重繪窗體repaint();//檢查子彈是否出界checkBoom();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();map=mp.readMap();//讀取地圖,并配置地圖for (int i = 0; i < map.length; i++) {for (int j = 0; j < map[0].length; j++) {//讀取到的是1,畫磚頭if(map[i][j]==1){brick = new Pipe(j*30,i*30,30,30,new ImageIcon("image/brick.png").getImage());eneryList.add(brick);}//讀到2畫金幣if(map[i][j]==2){cion = new Pipe(j*30,i*30,30,30,new ImageIcon("image/coin_brick.png").getImage());eneryList.add(cion);}//讀到3畫水管if(map[i][j]==3){pipe = new Pipe(j*30,i*30,60,120,new ImageIcon("image/pipe.png").getImage());eneryList.add(pipe);}}}//設(shè)置背景音樂com.huaxin.music.Util.startMusic("music/bg1.wav");}public void initFrame(){//設(shè)置窗體相關(guān)屬性this.setSize(800,450);this.setTitle("山寨版超級瑪麗");this.setResizable(false);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(3);this.setVisible(true);//該窗體添加鍵盤監(jiān)聽KeyListener kl = new KeyListener(this);this.addKeyListener(kl);}public void paint(Graphics g) {//利用雙緩沖畫背景圖片和馬里奧BufferedImage bi =(BufferedImage)this.createImage(this.getSize().width,this.getSize().height);Graphics big =bi.getGraphics();big.drawImage(bg.img, bg.x, bg.y, null);for (int i = 0; i <eneryList.size(); i++) {Enery e =eneryList.get(i);big.drawImage(e.img, e.x, e.y, e.width, e.height,null);}//畫子彈for (int i = 0; i < boomList.size(); i++) {Boom b =boomList.get(i);Color c =big.getColor();big.setColor(Color.red);big.fillOval(b.x+=b.speed, b.y, b.width, b.width);big.setColor(c);}//畫人物big.drawImage(mario.img, mario.x, mario.y, mario.width, mario.height,null);g.drawImage(bi,0,0,null);}//檢查子彈是否出界,出界則從容器中移除,不移除的話,內(nèi)存會泄漏public void checkBoom(){for (int i = 0; i < boomList.size(); i++) {Boom b = boomList.get(i);if(b.x<0 || b.x>800){boomList.remove(i);}}}}
角色類:
import java.awt.Image; import java.awt.Rectangle;import javax.swing.ImageIcon;import com.huaxin.enery.Enery;//自己的角色類 public class Mario extends Thread{public GameFrame gf;public boolean jumpFlag=true;//馬里奧的坐標public int x=0,y=358;//馬里奧的速度public int xspeed=5,yspeed=1;//馬里奧的寬高public int width=30,height=32;//馬里奧的圖片public Image img = new ImageIcon("image/mari1.png").getImage();public boolean left=false,right=false,down=false,up=false;public String Dir_Up="Up",Dir_Left="Left",Dir_Right="Right",Dir_Down="Down";public Mario (GameFrame gf) {this.gf=gf;this.Gravity();}public void run(){while(true){//向左走if(left){//碰撞到了if(hit(Dir_Left)){this.xspeed=0;}if(this.x>=0){this.x-=this.xspeed;this.img=new ImageIcon("image/mari_left.gif").getImage();}this.xspeed=5;}//向右走if(right){if(hit(Dir_Right)){this.xspeed=0;}//任人物向右移動if(this.x<400){this.x+=this.xspeed;this.img=new ImageIcon("image/mari_right.gif").getImage();}if(this.x>=400){//背景向左移動gf.bg.x-=this.xspeed;//障礙物項左移動for (int i = 0; i <gf.eneryList.size(); i++) {Enery enery = gf.eneryList.get(i);enery.x-=this.xspeed;}this.img=new ImageIcon("image/mari_right.gif").getImage();}this.xspeed=5;}//向上跳if(up){if(jumpFlag && !isGravity){jumpFlag=false;new Thread(){public void run(){jump();jumpFlag=true;}}.start();}}try {this.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}}}//向上跳的函數(shù)public void jump(){int jumpHeigh=0;for (int i = 0; i < 150; i++) {gf.mario.y-=this.yspeed;jumpHeigh++;if(hit(Dir_Up)){break;}try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 0; i <jumpHeigh; i++) {gf.mario.y+=this.yspeed;if(hit(Dir_Down)){this.yspeed=0;}try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}}this.yspeed=1;//還原速度}//檢測碰撞public boolean hit(String dir){Rectangle myrect = new Rectangle(this.x,this.y,this.width,this.height);Rectangle rect =null;for (int i = 0; i < gf.eneryList.size(); i++) {Enery enery = gf.eneryList.get(i);if(dir.equals("Left")){rect = new Rectangle(enery.x+2,enery.y,enery.width,enery.height);}else if(dir.equals("Right")){rect = new Rectangle(enery.x-2,enery.y,enery.width,enery.height);}else if(dir.equals("Up")){rect = new Rectangle(enery.x,enery.y+1,enery.width,enery.height);}else if(dir.equals("Down")){rect = new Rectangle(enery.x,enery.y-2,enery.width,enery.height);}//碰撞檢測if(myrect.intersects(rect)){return true;}}return false;}//檢查是否貼地public boolean isGravity=false;public void Gravity(){new Thread(){public void run(){while(true){try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(!jumpFlag){}while(true){if(!jumpFlag){break;}if(hit(Dir_Down)){break;}if(y>=358){isGravity=false;}else{isGravity=true;y+=yspeed;}try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}}.start();} }監(jiān)聽類:
import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent;import javax.swing.ImageIcon;//鍵盤按下監(jiān)聽類 public class KeyListener extends KeyAdapter{public GameFrame gf;public boolean jumpFlag=true;public KeyListener(GameFrame gf) {this.gf=gf;}//鍵盤監(jiān)聽public void keyPressed(KeyEvent e) {int code = e.getKeyCode();switch(code){//向右走case 39:gf.mario.right=true;break;//向左走case 37:gf.mario.left=true;break;case 66:addBoom();break;//向上跳case 74:gf.mario.up=true;break;}}//添加子彈public void addBoom() { Boom b = new Boom(gf.mario.x,gf.mario.y+5,10);if(gf.mario.left) b.speed=-2;if(gf.mario.right) b.speed=2;gf.boomList.add(b);}//鍵盤釋放監(jiān)聽public void keyReleased(KeyEvent e) {int code=e.getKeyCode();if(code==39){gf.mario.right=false;gf.mario.img=new ImageIcon("image/mari1.png").getImage();}if(code==37){gf.mario.left=false;gf.mario.img=new ImageIcon("image/mari_left1.png").getImage();}if(code==74){gf.mario.up=false;}}}背景類:
import java.awt.Image;import javax.swing.ImageIcon;public class BackgroundImage {public int x=0,y=0;public int ox=0,oy=0;public Image img=new ImageIcon("image/startBack.jpg").getImage();}
子彈類:
public class Boom {//子彈的坐標,大小,速度int x,y;int width;int speed=1;public Boom(int x, int y, int width) {super();this.x = x;this.y = y;this.width = width;}}
主函數(shù)類,作為整個程序的入口
public class Test {//主函數(shù),程序入口public static void main(String[] args) throws Exception {GameFrame gf = new GameFrame();gf.initFrame();} }
enery包:
import java.awt.Image;//障礙物的抽象父類 public abstract class Enery {public int x,y;public int width,height;public Image img;public Enery(int x, int y, int width, int height,Image img) {this.x = x;this.y = y;this.width = width;this.height = height;this.img=img;} }
import java.awt.Image;//金幣類 public class Coin extends Enery{public Coin(int x, int y, int width, int height, Image img) {super(x, y, width, height, img);}}
磚頭類:
import java.awt.Image;//磚頭類 public class Brick extends Enery {public Brick(int x, int y, int width, int height, Image img) {super(x, y, width, height, img);} }
水管類:
import java.awt.Image;//水管類 public class Pipe extends Enery {public Pipe(int x, int y, int width, int height, Image img) {super(x, y, width, height, img);} }
package Util;import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStreamReader; import java.util.ArrayList;//地圖配置類 public class Map {//數(shù)據(jù)容器public ArrayList<String> list = new ArrayList<String>();public int [][] map=null;public int[][] readMap() throws Exception {// 構(gòu)造文件輸入流FileInputStream fis = new FileInputStream("map.txt");InputStreamReader isr = new InputStreamReader(fis);BufferedReader br = new BufferedReader(isr);//直接讀取一行數(shù)據(jù)String value =br.readLine();while(value!=null){//將讀取到的一行數(shù)據(jù)加入到容器中l(wèi)ist.add(value);value =br.readLine();}br.close();//得到多少行多少列int row=list.size();int cloum=0;for (int i = 0; i < 1; i++) {String str=list.get(i);String [] values=str.split(",");cloum=values.length;}map = new int [row][cloum];//將讀到的字符創(chuàng)轉(zhuǎn)換成整數(shù),并賦值給二位數(shù)組mapfor (int i = 0; i < list.size(); i++) {String str=list.get(i);String [] values=str.split(",");for (int j = 0; j < values.length; j++) {map[i][j]=Integer.parseInt(values[j]);}}return map;}}
五、項目總結(jié):
這個小項目看起來挺簡單的,其實里面也有很多功能需要仔細去思考的,以前覺得游戲人物在窗體走的時候,覺得一直是人在走,其實,人物走到中間或者走到某一位置的時候,人物已經(jīng)是在原地踏步了,取而代之的是背后那張長度很長的背景的圖片在移動,任務(wù)的左右移動相對而言比較簡答實現(xiàn),跳躍功能就不是那么簡單了,需要永達線程,跟后面障礙物碰撞檢測又有關(guān)系,當(dāng)沒有碰到的時候,人物要往下掉,一不注意就會出現(xiàn)各種bug,比如,可以一直跳,在跳的同時還能再跳,還有就是下降可能不會落地面的同一高度,可能會高于地面的高度,可能會低于地面的高度;障礙物的添加,我們是通過配置地圖的方式,配置地圖有時通過讀入文件的操作,大致的原理是將后面的那張的背景圖片劃分成很多的小格子,將這些小格子用代碼轉(zhuǎn)換為二位數(shù)組,二維數(shù)組可以存入不同數(shù)字,代表不同的障礙物,通過操作文件就可以輕易配置地圖;首先通過文件輸入流將文件數(shù)據(jù)讀入,將字符轉(zhuǎn)換為數(shù)字,并存儲在二維數(shù)組中,后面,通過遍歷二維數(shù)組的不同位置的值,在相應(yīng)的格子填充相應(yīng)的障礙物;地圖就這樣配置好了;覺得配地圖很炫酷,因為以前有位學(xué)長在演示的時候,覺得好難,現(xiàn)在自己掌握了覺得也不是很難了,當(dāng)然了,這里離不開老師的指導(dǎo);碰撞檢測類似之前小球的碰撞檢測,這里主要需要處理碰撞之后的一些邏輯,如何避免一直碰撞(人物貼著障礙物不能動)等;發(fā)射子彈的話,也比較簡單了,利用容器裝子彈,不過需要注意的是要及時將容器中子彈移除,不然內(nèi)存會很快被吃完的;
寫程序,一定要按照思路一步一步來,一點一點來實現(xiàn)!不要太過急于求成!以前老想著自己做一個小東西出來,可是自己總是很急,希望很快做出來,結(jié)果,思路沒有理清,寫起來一團糟!前車之鑒!
好吧,就先寫到這吧!共勉之 !
總結(jié)
以上是生活随笔為你收集整理的【Java】游戏小程序-超级玛丽(代码渗入)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: moment的使用在vue项目中的使用
- 下一篇: String字符串中数字排序(Java)