Java俄罗斯方块目录:

* Java俄罗斯方块 ---(一)游戏场景篇
<https://blog.csdn.net/qq_40521205/article/details/80540901>
* Java俄罗斯方块 ---(二)游戏操作与逻辑篇
<https://blog.csdn.net/qq_40521205/article/details/80544017>
简要分析:

俄罗斯方块的规则在这里就不细说了,大家都知道,控制方块的移动,到底即停,当方块能填满一行时,便消除那一行的方块,并计分...

我们将用JPanel来完成整个游戏的制作。

首先我们来看看游戏运行时的图片。

 

(游戏图片 )

 

上图是游戏制作过程中我截的一张图片,从上图中,我们可以把游戏分为多个区域:

1)正在下落的四格方块

2)下一个下落的四格方块

3)游戏有一个主场景区,即左边的网格线区域

4)计分区,暂时还没绘制

根据俄罗斯方块的规则,我们知道,一个四格方块,是可以左右和往下移动的,并且还能变换形状。

然后我们在来看一张图片:

 

(经典俄罗斯方块的方块形状)

 


从上图我们可以看出来,每个方块都由四个小方格通过不同的排列组成,并且,我们可以把游戏主场景区想象成用二维数组来表示的区域,事实上,确实是用二维数组来制作游戏主区域。

在这里,我们暂且把这个区域称为------墙(Wall)

把每个小方格称为------单元格(Cell)

每个不同的形状其实就是4个单元格按不同顺序组合而来,所以,我们可以用不同的坐标来表示不同的形状。

我们可以根据四格方块的不同形状,给他们一个名字:I,T,L,J,S,Z,O

所以,在这里我们用面向对象的思想,分别定义Cell类,和七个四格方块类。

Cell()类:

    共同特征:行号,列号,图片

    共同行为:向左,向右,向下移动,提供JavaBean相关规范,JavaBean规范就是程序员在定义类时,默认遵守的一种规范如:

*     添加两个构造器,无参,全参
* 属性一般都是私有化(封装)
* 提供公有(public)的get/set方法
* 重写toString()方法,toString方法默认返回地址信息,重写后用来描述属性的信息
* 重写equals方法和hashCode方法 import java.awt.image.BufferedImage; /* *
俄罗斯方块中的最小单位:方格(细胞) * 特征(属性): * row--行号 * col--列号 * image--对应的图片 * 行为(方法) *
left() * right() * drop() */ public class Cell { private int row; private int
col; private BufferedImage image; @Override public String toString() { return
"(" + row + ", " + col + ")"; } 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;
} public Cell() {} public Cell(int row, int col, BufferedImage image) {
this.row = row; this.col = col; this.image = image; } /*向左移动*/ public void
left() { col--; } /*向右移动*/ public void right() { col++; } /*向下移动*/ public void
drop() { row++; } }
 

根据每个四格方块的共性,即移动等。我们可以让七个四格方块继承一个父类------Tetromino类,用于描述四格方块的行为,左移,右移,下落,生成一个方块。

 

Tetromino()类代码:

共同特征:cells--四个小方块(用数组表示)--权限修饰词protected

共同行为:向左,向右,向下移动,提供JavaBean规范

添加randomOne()方法---用来随机生成一个四格方块
import java.util.Arrays; /* * 四格方块 * 属性: * --cells----四个方块 * 行为: * moveLeft()
* moveRight() * softDrop() */ public class Tetromino { protected Cell[]
cells=new Cell[4]; /*四格方块向左移动 * 实际上:就是每个方块向左移动 */ /*四格方块向左移动*/ public void
moveLeft() { for(Cell c:cells) c.left(); } /*四格方块向右移动*/ public void moveRight()
{ for(Cell c:cells) c.right(); } /*四格方块向下移动*/ public void softDrop() { for(Cell
c:cells) c.drop(); } @Override public String toString() { return "[" +
Arrays.toString(cells) + "]"; } /*随机生成一个四格方块*/ public static Tetromino
randomOne() { Tetromino t = null; int
num=(int)(Math.random()*7);//random的范围是0.00-0.99(即包含0不包含1) 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; } return t; } }
 

然后在创建7个小方块的类,来继承Tetromino类,也就是把他们的共同点写到一个父类中,子类在描述各自的特性。

 

根据父类Tetromino,定义出七种子类,给属性赋具体元素。

L类代码:
public class L extends Tetromino{ /* * 提供构造器进行初始化 * L型的四格方块的位置 */ 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,3,Tetris.L); } }
其他6个按照方块所在的坐标编写,点击查看坐标,这样一来,便写好了最基本的类。

然后在创建一个主类,这个类就是游戏的入口,也是游戏的所有逻辑所在。

Tetris类代码:

提供静态属性,加载静态资源,游戏图片,场景等--静态代码块

 

* 面板会自动调用绘制方法paint(Graphics g)
* 重写paint方法,绘制图片背景,绘制网格和嵌入墙中的方块。
* 绘制网格和嵌入墙中的方块。paintWall(Graphics g)
    提供属性wall---是一个Cell类型的二维数组,20行,10列
    属性CELL_SIZE---一个方块的宽度
* 提供属性
    currentOne---正在下落的四格方块
    nextOne---下一个将要下落的四格方块
* 提供绘制正在下落的方块的方法
    paintCurrentOne(Graphics g)
    在重写的paint方法中取调用
* 编写start()方法,用于封装游戏主要逻辑 import java.awt.Graphics; import
java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import
java.awt.event.KeyListener; import java.awt.image.BufferedImage; import
javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; /*
* 俄罗斯方块的主类: * 前提:必须是一块面板Jpanel,可以嵌入窗口 * 面板上自带一个画笔,有一个功能:自动绘制 *
其实是调用了JPanel里的paint()方法 * * * (1)加载静态资源 */ public class Tetris extends JPanel{
/*属性:正在下落的四格方块*/ private Tetromino currentOne = Tetromino.randomOne();
/*属性:将要下落的四格方块*/ private Tetromino nextOne = Tetromino.randomOne(); /*属性:墙,20行
10列的 表格 宽度为26*/ private Cell[][] wall=new Cell[20][10]; private static final
int CELL_SIZE=26; //载入方块图片 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; public static
BufferedImage gameover; static { try { /* * getResource(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")); gameover =
ImageIO.read(Tetris.class.getResource("game-over.png")); } catch (Exception e)
{ e.printStackTrace(); } } /* * 重写JPanel类中的paint(Graphics g)方法 * */ public void
paint(Graphics g) { //绘制背景 /* * g:画笔 * g.drawImage(image,x,y,null) *
image:绘制的图片 * x:开始绘制的横坐标 * y:开始绘制的纵坐标 */ g.drawImage(background, 0,0, null);
//平移坐标轴 g.translate(15, 15); //绘制墙 paintWall(g); //绘制正在下落的四格方块
paintCurrentOne(g); //绘制下一个将要下落的四格方块 paintNextOne(g); } /* * 绘制下一个将要下落的四格方块 *
绘制到面板的右上角的相应区域 * @param g */ public void paintNextOne(Graphics g) {
//获取nextOne对象的四个元素 Cell[] cells = nextOne.cells; for(Cell c:cells) {
//获取每一个元素的行号和列号 int row = c.getRow(); int col = c.getCol(); //横坐标 int x =
col*CELL_SIZE+260; //纵坐标 int y = row*CELL_SIZE+26;
g.drawImage(c.getImage(),x,y,null); } } /*绘制正在下落的四格方块 * 取出数组的元素 * 绘制元素的图片 *
横坐标x * 纵坐标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); } } public void
paintWall(Graphics a) { //外层循环控制行数 for(int i=0;i<20;i++) { //内层循环控制列数 for(int
j=0;j<10;j++) { int x = j*CELL_SIZE; int y = i*CELL_SIZE; Cell cell=wall[i][j];
if(cell==null) { a.drawRect(x, y, CELL_SIZE, CELL_SIZE); } else {
a.drawImage(cell.getImage(),x,y,null); } } } } /* * 封装了游戏的主要逻辑 */ public void
start() { //开启键盘监听事件 KeyListener l = new KeyAdapter() { /* * KeyPressed() *
是键盘按钮 按下去所调用的方法 */ @Override 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; case KeyEvent.VK_UP: break;
default: break; } //按一次重新绘制一次 repaint(); } }; //面板添加监听事件对象
this.addKeyListener(l); //面板对象设置成焦点 this.requestFocus(); while(true) { /* *
当程序运行到此,会进入睡眠状态, * 睡眠时间为300毫秒,单位为毫秒 * 300毫秒后,会自动执行后续代码 */ try {
Thread.sleep(300); } catch (InterruptedException e) { // 抓取打断异常
e.printStackTrace(); } if(canDrop()) { currentOne.softDrop(); } else {
landToWall(); //将下一个下落的四格方块赋值给正在下落的变量 currentOne = nextOne; nextOne =
Tetromino.randomOne(); } /* * 下落之后,要重新进行绘制,才会看到下落后的位置 * repaint方法,也是JPanel类中提供的
* 此方法中调用了paint方法 */ repaint(); elimination(); } } /* * 使用Right键控制四格方块右移 */
public void moveRightAction() { currentOne.moveRight();
if(outOfBounds()||coincide()) currentOne.moveLeft(); } /* * 使用Left键控制四格方块左移 */
public void moveLeftAction() { currentOne.moveLeft();
if(outOfBounds()||coincide()) { currentOne.moveRight(); } } private 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 outOfBounds() { Cell[] cells = currentOne.cells;
for(Cell c:cells) { int col = c.getCol(); if(col<0||col>9) return true; }
return false; } /* * 使用Down键控制四格方块的下落 */ public void softDropAction() {
if(canDrop()) { currentOne.softDrop(); } else { landToWall(); currentOne =
nextOne; nextOne = Tetromino.randomOne(); } } public boolean canDrop() { Cell[]
cells = currentOne.cells; /* * */ for(Cell c:cells) { /* 获取每个元素的行号,列号 * 判断: *
只要有一个元素的下一行上有方块 * 或者只要有一个元素到达最后一行 * 就不能再下落了 */ int row = c.getRow(); int col =
c.getCol(); if (row==19) {//判断是否到达底部 return false; } else
if(wall[row+1][col]!=null) {//判断下方是否有方块 return false; } } return true; } /* *
当不能再下落时,需要将四格方块嵌入到墙中 * 也就是存储到二维数组中相应的位置上 */ public void landToWall() { Cell[]
cells = currentOne.cells; for(Cell c:cells) { //获取最终的行号和列号 int row =
c.getRow(); int col = c.getCol(); wall[row][col] = c; } } /*启动游戏的入口 游戏开始*/
public static void main(String[] args) { //1:创建一个窗口对象 JFrame frame=new
JFrame("玩玩俄罗斯方块"); //创建游戏界面,即画板(面板) Tetris panel = new Tetris(); //将面板嵌入窗口
frame.add(panel); //2:设置为可见 frame.setVisible(true); //3:设置窗口的尺寸
frame.setSize(535, 595); //4:设置窗口居中 frame.setLocationRelativeTo(null);
//5:设置窗口关闭,即程序中止 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//游戏的主要逻辑封装在start方法中 panel.start(); } }

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信