Java實(shí)現(xiàn)簡(jiǎn)易俄羅斯方塊
本文實(shí)例為大家分享了Java實(shí)現(xiàn)簡(jiǎn)易俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
一、將對(duì)象抽象為類
首先考慮俄羅斯方塊游戲中含有哪些具體的對(duì)象,對(duì)象中含有哪些具體屬性和方法,然后用代碼來實(shí)現(xiàn)。
建立如下類:
Cell類:代表最小的方格單位,構(gòu)成7種圖形的最基本圖形。
含有row(行號(hào)),col(列號(hào)),image(對(duì)應(yīng)的圖片)屬性,
含有l(wèi)eft(左移),right(右移),drop(下落)方法。
Tetromino類:代表由4個(gè)最小方格構(gòu)成的7種圖形的合集。
含有cells(四個(gè)方塊)屬性,
含有moveLeft(四格方塊向左移動(dòng)),moveRight(四格方塊向右移動(dòng)),softDrop(軟下落),randomOne(隨機(jī)生成一個(gè)四格方格)方法。
T類繼承于Tetromino類:
I類繼承于Tetromino類:
L類繼承于Tetromino類:
S類繼承于Tetromino類:
Z類繼承于Tetromino類:
O類繼承于Tetromino類:
J類繼承于Tetromino類:
Tetris類:俄羅斯方塊的主方法類,包括了游戲運(yùn)行過程中所需要的眾多方法。
含有currentOne(正在下落的四格方塊),nextOne(即將下落的四格方塊),Cell[][]wall(二維數(shù)組的表格,代表墻)屬性。
二、類的實(shí)現(xiàn)
Notes:各類實(shí)現(xiàn)過程中要符合Javabean規(guī)范。
Cell類:
package com.tetris; import java.awt.image.BufferedImage; /* * 俄羅斯方塊中的最小單位:方格 * 特征(屬性): * row--行號(hào) * col--列號(hào) * image--對(duì)應(yīng)的圖片 * * 行為(方法) * left(); * right(); * drop(); */ public class Cell { private int row; //行 private int col; //列 private BufferedImage image; public Cell(int row, int col, BufferedImage image) { super(); this.row = row; this.col = col; this.image = image; } public Cell() { super(); // TODO Auto-generated constructor stub } public int getRow() { return row; } public void setRow(int row) { this.row = row; } public int getCol() { return col; } public void setCol(int col) { this.col = col; } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } @Override public String toString() { return "(" + row + ", " + col + ")"; } //向左移動(dòng) public void left(){ col--; } //向右移動(dòng) public void right(){ col++; } //向下移動(dòng) public void drop(){ row++; } }
Tetromino類:
package com.tetris; import java.util.Arrays; import javax.xml.transform.Templates; /* * 四格方塊 * 屬性: * ---cells,----四個(gè)方塊 * * 行為: * moveLeft() * moveRight() * softDrop() */ public class Tetromino { protected Cell[] cells=new Cell[4]; //四格方塊向左移動(dòng) //實(shí)際上:就是每個(gè)方塊向左移動(dòng) public void moveLeft(){ for (int i = 0; i < cells.length; i++) { cells[i].left(); } } //四格方塊向右移動(dòng) //實(shí)際上:就是每個(gè)方塊向右移動(dòng) public void moveRight(){ for (int i = 0; i < cells.length; i++) { cells[i].right(); } } //四格方塊向下移動(dòng) //實(shí)際上:就是每個(gè)方塊向下移動(dòng) public void softDrop(){ for (int i = 0; i < cells.length; i++) { cells[i].drop(); } } @Override public String toString() { return "[" + Arrays.toString(cells) + "]"; } //隨機(jī)生成一個(gè)四格方塊 public static Tetromino randomOne(){ Tetromino t = null; int num=(int)(Math.random()*7); switch (num){ case 0:t=new T();break; case 1:t=new O();break; case 2:t=new I();break; case 3:t=new J();break; case 4:t=new L();break; case 5:t=new S();break; case 6:t=new Z();break; default: break; } return t; } }
T類繼承于Tetromino類:
package com.tetris; public class T extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public T(){ cells[0]=new Cell(0,4,Tetris.T); cells[1]=new Cell(0,3,Tetris.T); cells[2]=new Cell(0,5,Tetris.T); cells[3]=new Cell(1,4,Tetris.T); } }
I類繼承于Tetromino類:
package com.tetris; public class I extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public I(){ cells[0]=new Cell(0,4,Tetris.I); cells[1]=new Cell(0,3,Tetris.I); cells[2]=new Cell(0,5,Tetris.I); cells[3]=new Cell(0,6,Tetris.I); } }
L類繼承于Tetromino類:
package com.tetris; public class L extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public L(){ cells[0]=new Cell(0,4,Tetris.L); cells[1]=new Cell(0,3,Tetris.L); cells[2]=new Cell(0,5,Tetris.L); cells[3]=new Cell(1,5,Tetris.L); } }
S類繼承于Tetromino類:
package com.tetris; public class S extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public S(){ cells[0]=new Cell(1,4,Tetris.S); cells[1]=new Cell(0,3,Tetris.S); cells[2]=new Cell(0,4,Tetris.S); cells[3]=new Cell(1,5,Tetris.S); } }
Z類繼承于Tetromino類:
package com.tetris; public class Z extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public Z(){ cells[0]=new Cell(0,4,Tetris.Z); cells[1]=new Cell(0,5,Tetris.Z); cells[2]=new Cell(1,3,Tetris.Z); cells[3]=new Cell(1,4,Tetris.Z); } }
O類繼承于Tetromino類:
package com.tetris; public class O extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public O(){ cells[0]=new Cell(0,4,Tetris.O); cells[1]=new Cell(0,5,Tetris.O); cells[2]=new Cell(1,4,Tetris.O); cells[3]=new Cell(1,5,Tetris.O); } }
J類繼承于Tetromino類:
package com.tetris; public class J extends Tetromino { //提供構(gòu)造器,進(jìn)行初始化 //T型的四格方塊的位置 public J(){ cells[0]=new Cell(0,4,Tetris.J); cells[1]=new Cell(0,3,Tetris.J); cells[2]=new Cell(0,5,Tetris.J); cells[3]=new Cell(1,3,Tetris.J); } }
Tetris類:
//屬性:正在下落的四格方塊 private Tetromino currentOne=Tetromino.randomOne(); //屬性:將要下落的四格方塊 private Tetromino nextOne=Tetromino.randomOne(); //屬性:墻,20行10列的表格 寬度為26 private Cell[][]wall=new Cell[20][10];
三、繪制俄羅斯方塊圖形
個(gè)人理解,這個(gè)過程就是顯現(xiàn)出游戲界面的過程,當(dāng)然啦,這一步主要是加載靜態(tài)資源,諸如圖片,音頻和視頻等。
1.加載靜態(tài)資源
俄羅斯方塊主要應(yīng)用的靜態(tài)資源是圖片,所以我們用到的是IO類中的ImageIO類中的ImageIO.read方法,導(dǎo)入各類四格方塊的圖形圖片以及背景圖片,具體代碼如下:
public static BufferedImage T; public static BufferedImage I; public static BufferedImage O; public static BufferedImage J; public static BufferedImage L; public static BufferedImage S; public static BufferedImage Z; public static BufferedImage background; static{ try { /* * getResouce(String url) * url:加載圖片的路徑 * 相對(duì)位置是同包下 */ T=ImageIO.read(Tetris.class.getResource("T.png")); I=ImageIO.read(Tetris.class.getResource("I.png")); O=ImageIO.read(Tetris.class.getResource("O.png")); J=ImageIO.read(Tetris.class.getResource("J.png")); L=ImageIO.read(Tetris.class.getResource("L.png")); S=ImageIO.read(Tetris.class.getResource("S.png")); Z=ImageIO.read(Tetris.class.getResource("Z.png")); background=ImageIO.read(Tetris.class.getResource("tetris.png")); } catch (Exception e) { e.printStackTrace(); } }
2.畫游戲靜態(tài)界面
在這一部分中需要繪制三部分,用到了三種方法,分別是paintCurrentOne(正在下落的四格方塊),paintNextOne(等待進(jìn)入的四格方塊),paintWall(背景墻)。
繪制需要重寫JPanel類中的paint(Graphics g)方法,具體代碼實(shí)現(xiàn)如下:
public void paint(Graphics g){ //繪制背景 /* * g:畫筆 * g.drawImage(image,x,y,null) * x:開始繪制的橫坐標(biāo) * y:開始繪制的縱坐標(biāo) */ g.drawImage(background,0,0,null); //平移坐標(biāo)軸 g.translate(15, 15); //繪制墻 paintWall(g); //繪制正在下落的四格方塊 paintCurrentOne(g); //繪制下一個(gè)即將下落的四格方塊 paintNextOne(g); } /* * 繪制下一個(gè)即將下落的四格方塊 * 繪制到面板的右上角的相應(yīng)區(qū)域 */ public void paintNextOne(Graphics g){ //獲取nextOne對(duì)象的四個(gè)元素 Cell[] cells=nextOne.cells; for (Cell c:cells) { //獲取每一個(gè)元素的行號(hào)和列號(hào) int row=c.getRow(); int col=c.getCol(); //橫坐標(biāo)和縱坐標(biāo) int x=col*CELL_SIZE+260; int y=row*CELL_SIZE+26; g.drawImage(c.getImage(), x, y, null); } } /* * 繪制正在下落的四格方塊 * 取出數(shù)組的元素 * 繪制數(shù)組的圖片 * 橫坐標(biāo)x * 縱坐標(biāo)y */ public void paintCurrentOne(Graphics g){ Cell[] cells=currentOne.cells; for (Cell c:cells) { int x=c.getCol()*CELL_SIZE; int y=c.getRow()*CELL_SIZE; g.drawImage(c.getImage(), x, y, null); } } /* * 墻是20行,10列的表格 * 是一個(gè)二維數(shù)組 * 用雙層循環(huán) * 繪制正方形 */ public void paintWall(Graphics a){ //外層循環(huán)控制行數(shù) for (int i = 0; i < 20; i++) { //內(nèi)層循環(huán)控制列數(shù) for (int j = 0; j < 10; j++) { int x=j*CELL_SIZE; int y=i*CELL_SIZE; Cell cell=wall[i][j]; a.drawRect(x, y, CELL_SIZE, CELL_SIZE); if(wall[i][j]==null){ a.drawRect(x, y, CELL_SIZE, CELL_SIZE); }else{ a.drawImage(cell.getImage(),x,y,null); } } } }
實(shí)現(xiàn)效果如下:
3.讓四格方塊動(dòng)起來
光有靜態(tài)的畫面是不能夠稱為游戲的,還有要?jiǎng)討B(tài)效果和接收鍵盤指令并響應(yīng)的能力。
(1)動(dòng)態(tài)效果
俄羅斯方塊中的動(dòng)態(tài)效果主要指7種四格方塊擁有自動(dòng)下降,軟下降,左移,右移,旋轉(zhuǎn)的能力,分別使用canDrop(),softDropAction(),moveLeftAction(),moveRightAction(),spinCellAction()方法來實(shí)現(xiàn),與此同時(shí),還需根據(jù)游戲規(guī)則注意四格方塊可能遇到觸碰到左右邊界,方塊覆蓋等錯(cuò)誤,在此使用outOfBounds(),coincide()方法來避免。當(dāng)不能下落時(shí),需要將四格方塊,嵌入到墻中,使用landToWall()方法。
具體代碼實(shí)現(xiàn)如下:
/* * 使用left鍵控制向左的行為 */ public void moveLeftAction() { currentOne.moveLeft(); if(outOfBounds()||coincide()){ currentOne.moveRight(); } } /* * 使用right鍵控制向右的行為 */ public void moveRightAction() { currentOne.moveRight(); if(outOfBounds()||coincide()){ currentOne.moveLeft(); } } /* * 使用down鍵控制四格方塊的下落 */ public void softDropAction() { if(canDrop()){ currentOne.softDrop(); }else{ landToWall(); currentOne=nextOne; nextOne=Tetromino.randomOne(); } } public boolean outOfBounds(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { int col=c.getCol(); if(col<0||col>9){ return true; } } return false; } public boolean coincide(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { int row=c.getRow(); int col=c.getCol(); if(wall[row][col]!=null){ return true; } } return false; } public boolean canDrop(){ Cell[] cells=currentOne.cells; for (Cell c: cells) { //獲取每個(gè)元素的行號(hào) /* * 判斷: * 只要有一個(gè)元素的下一行上有方塊 * 或者只要有一個(gè)元素到達(dá)最后一行,就不能下落了 */ int row=c.getRow(); int col=c.getCol(); if(row==19){ return false; } if(wall[row+1][col]!=null){ return false; } } return true; } /* * 當(dāng)不能下落時(shí),需要將四格方塊,嵌入到墻中 * 也就是存儲(chǔ)到二維數(shù)組中相應(yīng)的位置上 */ public void landToWall(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { //獲取最終的行號(hào)和列號(hào) int row=c.getRow(); int col=c.getCol(); wall[row][col]=c; } }
實(shí)現(xiàn)效果如下:
(2)接收鍵盤指令并響應(yīng)
游戲和玩家緊密關(guān)聯(lián),所以接下來我們需要使玩家能夠通過鍵盤控制四格方塊移動(dòng)。
因此,我們要開啟鍵盤監(jiān)聽來達(dá)到玩家實(shí)時(shí)控制游戲的目的,并且通過不同的按鍵調(diào)用四格方塊移動(dòng)的不同方法。
具體代碼如下:
//開啟鍵盤監(jiān)聽事件
KeyListener l=new KeyAdapter() {
public void keyPressed(KeyEvent e){
//獲取以下鍵子的代號(hào)
int code=e.getKeyCode();
switch (code) {
case KeyEvent.VK_DOWN:
softDropAction();break;
case KeyEvent.VK_LEFT:
moveLeftAction();break;
case KeyEvent.VK_RIGHT:
moveRightAction();break;
}
repaint();
}
};
this.addKeyListener(l);
this.requestFocus();
while(true){
/*
* 當(dāng)程序運(yùn)行到此,會(huì)進(jìn)入睡眠狀態(tài)
* 睡眠時(shí)間為300毫秒,單位為毫秒
* 300毫秒后會(huì)自動(dòng)執(zhí)行后續(xù)代碼
*/
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(canDrop()){
currentOne.softDrop();
}else{
landToWall();
//將下一個(gè)下落的四格方塊賦值給正在下落的變量
currentOne=nextOne;
nextOne=Tetromino.randomOne();
}
/*
* 下落之后,要重新進(jìn)行繪制,才會(huì)看到下落后的位置
* repaint方法也是Jpanel類中提供的
* 此方法調(diào)用了paint方法
*/
repaint();
}
}
實(shí)現(xiàn)效果如下:
更多關(guān)于俄羅斯方塊的文章,請(qǐng)點(diǎn)擊查看專題:《俄羅斯方塊》
更多精彩游戲,請(qǐng)參考專題《java經(jīng)典小游戲》
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springSecurity之AuthenticationProvider用法解析
這篇文章主要介紹了springSecurity之AuthenticationProvider用法解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03JMeter中的后端監(jiān)聽器的實(shí)現(xiàn)
本文主要介紹了JMeter中的后端監(jiān)聽器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09使用Spring RestTemplate 詳解實(shí)踐使用及拓展增強(qiáng)
這篇文章主要介紹了使用Spring RestTemplate 詳解實(shí)踐使用及拓展增強(qiáng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringMVC實(shí)現(xiàn)文件上傳下載的全過程
對(duì)于上傳功能,我們?cè)陧?xiàng)目中是經(jīng)常會(huì)用到的,比如用戶注冊(cè)的時(shí)候,上傳用戶頭像,這個(gè)時(shí)候就會(huì)使用到上傳的功能,而對(duì)于下載使用場(chǎng)景也很常見,下面這篇文章主要給大家介紹了關(guān)于SpringMVC實(shí)現(xiàn)文件上傳下載的相關(guān)資料,需要的朋友可以參考下2022-01-01實(shí)例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入
這篇文章主要介紹了Java的Spring框架中的控制反轉(zhuǎn)和依賴注入,Spring是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2016-02-02關(guān)于對(duì)Java正則表達(dá)式"\\"的理解
正則表達(dá)式中,\代表轉(zhuǎn)義字符,通常是轉(zhuǎn)義一些特殊字符,下面這篇文章主要給大家介紹了關(guān)于對(duì)Java正則表達(dá)式"\\"的相關(guān)理解,需要的朋友可以參考下2022-09-09