Java實現(xiàn)簡易俄羅斯方塊
本文實例為大家分享了Java實現(xiàn)簡易俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
一、將對象抽象為類
首先考慮俄羅斯方塊游戲中含有哪些具體的對象,對象中含有哪些具體屬性和方法,然后用代碼來實現(xiàn)。
建立如下類:
Cell類:代表最小的方格單位,構(gòu)成7種圖形的最基本圖形。
含有row(行號),col(列號),image(對應(yīng)的圖片)屬性,
含有l(wèi)eft(左移),right(右移),drop(下落)方法。
Tetromino類:代表由4個最小方格構(gòu)成的7種圖形的合集。
含有cells(四個方塊)屬性,
含有moveLeft(四格方塊向左移動),moveRight(四格方塊向右移動),softDrop(軟下落),randomOne(隨機(jī)生成一個四格方格)方法。
T類繼承于Tetromino類:

I類繼承于Tetromino類:

L類繼承于Tetromino類:

S類繼承于Tetromino類:

Z類繼承于Tetromino類:

O類繼承于Tetromino類:

J類繼承于Tetromino類:

Tetris類:俄羅斯方塊的主方法類,包括了游戲運行過程中所需要的眾多方法。
含有currentOne(正在下落的四格方塊),nextOne(即將下落的四格方塊),Cell[][]wall(二維數(shù)組的表格,代表墻)屬性。
二、類的實現(xiàn)
Notes:各類實現(xiàn)過程中要符合Javabean規(guī)范。
Cell類:
package com.tetris;
import java.awt.image.BufferedImage;
/*
* 俄羅斯方塊中的最小單位:方格
* 特征(屬性):
* row--行號
* col--列號
* image--對應(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 + ")";
}
//向左移動
public void left(){
col--;
}
//向右移動
public void right(){
col++;
}
//向下移動
public void drop(){
row++;
}
}
Tetromino類:
package com.tetris;
import java.util.Arrays;
import javax.xml.transform.Templates;
/*
* 四格方塊
* 屬性:
* ---cells,----四個方塊
*
* 行為:
* moveLeft()
* moveRight()
* softDrop()
*/
public class Tetromino {
protected Cell[] cells=new Cell[4];
//四格方塊向左移動
//實際上:就是每個方塊向左移動
public void moveLeft(){
for (int i = 0; i < cells.length; i++) {
cells[i].left();
}
}
//四格方塊向右移動
//實際上:就是每個方塊向右移動
public void moveRight(){
for (int i = 0; i < cells.length; i++) {
cells[i].right();
}
}
//四格方塊向下移動
//實際上:就是每個方塊向下移動
public void softDrop(){
for (int i = 0; i < cells.length; i++) {
cells[i].drop();
}
}
@Override
public String toString() {
return "[" + Arrays.toString(cells) + "]";
}
//隨機(jī)生成一個四格方塊
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];
三、繪制俄羅斯方塊圖形
個人理解,這個過程就是顯現(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:加載圖片的路徑
* 相對位置是同包下
*/
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)方法,具體代碼實現(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);
//繪制下一個即將下落的四格方塊
paintNextOne(g);
}
/*
* 繪制下一個即將下落的四格方塊
* 繪制到面板的右上角的相應(yīng)區(qū)域
*/
public void paintNextOne(Graphics g){
//獲取nextOne對象的四個元素
Cell[] cells=nextOne.cells;
for (Cell c:cells) {
//獲取每一個元素的行號和列號
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列的表格
* 是一個二維數(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);
}
}
}
}
實現(xiàn)效果如下:

3.讓四格方塊動起來
光有靜態(tài)的畫面是不能夠稱為游戲的,還有要動態(tài)效果和接收鍵盤指令并響應(yīng)的能力。
(1)動態(tài)效果
俄羅斯方塊中的動態(tài)效果主要指7種四格方塊擁有自動下降,軟下降,左移,右移,旋轉(zhuǎn)的能力,分別使用canDrop(),softDropAction(),moveLeftAction(),moveRightAction(),spinCellAction()方法來實現(xiàn),與此同時,還需根據(jù)游戲規(guī)則注意四格方塊可能遇到觸碰到左右邊界,方塊覆蓋等錯誤,在此使用outOfBounds(),coincide()方法來避免。當(dāng)不能下落時,需要將四格方塊,嵌入到墻中,使用landToWall()方法。
具體代碼實現(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) {
//獲取每個元素的行號
/*
* 判斷:
* 只要有一個元素的下一行上有方塊
* 或者只要有一個元素到達(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ù)組中相應(yīng)的位置上
*/
public void landToWall(){
Cell[] cells=currentOne.cells;
for (Cell c : cells) {
//獲取最終的行號和列號
int row=c.getRow();
int col=c.getCol();
wall[row][col]=c;
}
}
實現(xiàn)效果如下:

(2)接收鍵盤指令并響應(yīng)
游戲和玩家緊密關(guān)聯(lián),所以接下來我們需要使玩家能夠通過鍵盤控制四格方塊移動。
因此,我們要開啟鍵盤監(jiān)聽來達(dá)到玩家實時控制游戲的目的,并且通過不同的按鍵調(diào)用四格方塊移動的不同方法。
具體代碼如下:
//開啟鍵盤監(jiān)聽事件
KeyListener l=new KeyAdapter() {
public void keyPressed(KeyEvent e){
//獲取以下鍵子的代號
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)程序運行到此,會進(jìn)入睡眠狀態(tài)
* 睡眠時間為300毫秒,單位為毫秒
* 300毫秒后會自動執(zhí)行后續(xù)代碼
*/
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(canDrop()){
currentOne.softDrop();
}else{
landToWall();
//將下一個下落的四格方塊賦值給正在下落的變量
currentOne=nextOne;
nextOne=Tetromino.randomOne();
}
/*
* 下落之后,要重新進(jìn)行繪制,才會看到下落后的位置
* repaint方法也是Jpanel類中提供的
* 此方法調(diào)用了paint方法
*/
repaint();
}
}
實現(xiàn)效果如下:

更多關(guān)于俄羅斯方塊的文章,請點擊查看專題:《俄羅斯方塊》
更多精彩游戲,請參考專題《java經(jīng)典小游戲》
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springSecurity之AuthenticationProvider用法解析
這篇文章主要介紹了springSecurity之AuthenticationProvider用法解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
使用Spring RestTemplate 詳解實踐使用及拓展增強(qiáng)
這篇文章主要介紹了使用Spring RestTemplate 詳解實踐使用及拓展增強(qiáng),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
實例講解Java的Spring框架中的控制反轉(zhuǎn)和依賴注入
這篇文章主要介紹了Java的Spring框架中的控制反轉(zhuǎn)和依賴注入,Spring是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2016-02-02

