俄罗斯方块(java)
1、俄罗斯方块简介
俄罗斯方块》(Tetris, 俄文:Тетрис)是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的
休闲游戏。
该游戏曾经被多家公司代理过。经过多轮诉讼后,该游戏的代理权最终被任天堂获得。 [1] 任天堂对于
俄罗斯方块来说意义重大,因为将它与GB搭配在一起后,获得了巨大的成功。 [1]
《俄罗斯方块》的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多
行并且消除得分。
上图是游戏制作过程中我截的一张图片,从上图中,我们可以把游戏分为多个区域:
1)左侧主游戏界面区域;
2)右侧游戏信息区域。
其中,主游戏区域主要就是我们进行游戏操作的地方;右侧游戏信息区域,可以设置下一个要下落的方
块,对应关卡,对应分数,以及游戏时长等等(都可以自行定义)。
根据俄罗斯方块的规则,我们知道,一个四格方块,是可以左右和往下移动的,并且还能变换形状。
然后我们在来看一张图片:
从上图我们可以看出来,每个方块都由四个小方格通过不同的排列组成,并且,我们可以把游戏主场景
区想象成用二维数组来表示的区域,事实上,确实是用二维数组来制作游戏主区域。
在这里,我们暂且把这个区域称为------墙(Wall)
把每个小方格称为------单元格(Cell)
每个不同的形状其实就是4个单元格按不同顺序组合而来,所以,我们可以用不同的坐标来表示不同的
形状。
我们可以根据四格方块的不同形状,给他们一个名字:I,T,L,J,S,Z,O
所以,在这里我们用面向对象的思想,分别定义Cell类,和七个四格方块类。
JavaBean实现
单元格类
根据java面向对象思想,以及前面分析的结果,最基本单元格作为一个单元格类,有行、列、背景图
片,以及左移、右移、下移方法。
import java.awt.image.BufferedImage;
/**
* 单元格类
*/
public class Cell {
// 属性
private int row; // 行 0,
private int col; // 列 0
private BufferedImage image; // 背景图片 null
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++;
}
// 普通属性的get、set方法
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;
}
}
//方块类
import java.util.Random;
public class TetrisModel {
// 单元格数组,存放4个单元格,组成俄罗斯方块
public Cell[] cells =new Cell[4];
/**
* 方块左移
*/
public void moveLeft(){
for (Cell cell : cells) {
cell.left();
}
}
/**
* 方块右移
*/
public void moveRight(){
for (Cell cell : cells) {
cell.right();
}
}
/**
* 方块下移
*/
public void moveDrop(){
for (Cell cell : cells) {
cell.drop();
}
}
/**
* 方块旋转
*/
public void moveRote(){
// TODO 后续实现方块旋转逻辑
}
}
方块类随机生成
外,在方块类TetrisModel中,需要定制一个随机生成方块类的方法。该方法使用多态的方式实现,
因为可能随机生成任意7种之一的方块,所以结合switch控制语句,返回不同类型的方块。
因此,在TetrisModel中添加一个静态方法,生成随机方块类对象。
/**
* 随机生成方块对象
* @return
*/
public static TetrisModel randomOne() {
TetrisModel t =new TetrisModel();
Random random = new Random();
int num = random.nextInt(7); // [0,6]
switch (num) {
case 0:
t = new I();
break;
case 1:
t = new J();
break;
case 2:
t = new L();
break;
case 3:
t= new O();
break;
case 4:
t = new S();
break;
case 5:
t = new T();
break;
case 6:
t = new Z();
break;
}
// 返回随机生成的俄罗斯方块对象
return t;
}
//I方块对象
/**
* I形俄罗斯方块
*/
public class I extends TetrisModel{
/**
* 对默认构造方法进行改造,进行属性变量的初始化
* 初始化方块中每一个单元格的位置,还有背景图片
*/
public I(){
//把数组的一个单元格作为后续选择的中心轴
cells[0]=new Cell(0,4, SourceUtil.iImage);
cells[1]=new Cell(0,3,SourceUtil.iImage);
cells[2]=new Cell(0,5,SourceUtil.iImage);
cells[3]=new Cell(0,6,SourceUtil.iImage);
}
}
静态工具类
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* 静态资源加载工具类
*/
public class SourceUtil {
/**
* 静态图片资源
*/
public static BufferedImage iImage;
public static BufferedImage jImage;
public static BufferedImage lImage;
public static BufferedImage oImage;
public static BufferedImage sImage;
public static BufferedImage tImage;
public static BufferedImage zImage;
public static BufferedImage backgroundImage;
public static BufferedImage tetrisLogoImage;
/**
* 静态代码块,加载一次静态资源
*/
static {
/**
* ImageIO.read()方法可以读取项目下的静态资源文件
*/
try {
iImage =
ImageIO.read(SourceUtil.class.getResource("../image/I.png"));
jImage =ImageIO.read(SourceUtil.class.getResource("../image/J.png"));
lImage =ImageIO.read(SourceUtil.class.getResource("../image/L.png"));
oImage =ImageIO.read(SourceUtil.class.getResource("../image/O.png"));
sImage =ImageIO.read(SourceUtil.class.getResource("../image/S.png"));
tImage =ImageIO.read(SourceUtil.class.getResource("../image/T.png"));
zImage =ImageIO.read(SourceUtil.class.getResource("../image/Z.png"));
backgroundImage =
ImageIO.read(SourceUtil.class.getResource("../image/background.png"));
tetrisLogoImage =
ImageIO.read(SourceUtil.class.getResource("../image/tetrisLogo.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
游戏启动类
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* 俄罗斯方块游戏入口
*/
public class TetrisMain {
public static void main(String[] args) throws IOException {
// 1、游戏窗口界面设置
// 创建游戏窗口界面
JFrame jFrame = new JFrame("经典俄罗斯方块");
// 游戏窗口加入游戏画布
TetrisPanel tetrisPanel = new TetrisPanel();
jFrame.add(tetrisPanel);
// 读取并设置游戏窗口左侧logo图标
BufferedImage logoImage =
ImageIO.read(TetrisMain.class.getResource("../image/tetrisLogo.png"));
jFrame.setIconImage(logoImage);
// 设置游戏窗口大小
jFrame.setSize(535, 595);
// 设置游戏窗口居中显示
jFrame.setLocationRelativeTo(null);
// 设置关闭窗口会默认退出程序
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setResizable(false); // 设置窗口尺寸不可拉伸改变
jFrame.setVisible(true); // 设置窗口显示可见
// 2、游戏功能启动
tetrisPanel.start();
}
}
游戏主面板区域
import com.hopu.domain.Cell;
import com.hopu.domain.TetrisModel;
import com.hopu.util.SourceUtil;
import javax.swing.*;
import java.awt.*;
/**
* 整个游戏区域的面板画布类
*/
public class TetrisPanel extends JPanel {
// 设置20行,10列的墙体表格数组
public Cell[][] wall =new Cell[20][10];
// 设置单元格对象的固定宽高
public static final int CELL_SIZE=26;
// 当前正在下落的方块
public TetrisModel currentOne = TetrisModel.randomOne();
// 下一个准备下落的方块
public TetrisModel nextOne = TetrisModel.randomOne();
/**
* 重写父类画图方法
* @param g 代表画笔
*/
@Override
public void paint(Graphics g) {
// 绘制游戏区域背景图
g.drawImage(SourceUtil.backgroundImage,0,0,null);
// 后面墙体右下方法稍微偏移一点
g.translate(15,15);
// 绘制主游戏区域的背景墙格子
paintWall(g);
// 绘制下一个要下落的方块
paintCurrentOne(g);
// 绘制当前下落的方块
paintNextOne(g);
}
/**
* 绘制当前下落的方块
* @param g
*/
private void paintNextOne(Graphics g) {
Cell[] cells = nextOne.cells;
for (Cell cell : cells) {
int x = cell.getCol() * CELL_SIZE +265;
int y = cell.getRow() * CELL_SIZE +25;
// 在对应位置绘制单元格对象
g.drawImage(cell.getImage(),x,y,null);
}
}
```/**
* 绘制当前下落的方块
*/
private void paintCurrentOne(Graphics g) {
// 获取到当前方块的每一个单元格数组对象
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int x = cell.getCol() * CELL_SIZE;
int y = cell.getRow() * CELL_SIZE;
// 在对应位置绘制单元格对象
g.drawImage(cell.getImage(),x,y,null);
}
}
/**
* 自定义一个私有的绘制墙体格子方法
* 本质:在背景下绘制20行,10列的单元格对象,然后对其中每一个单元格对象进行定位和图片
* @param g
*/
private void paintWall(Graphics g) {
// 外层循环循环行
for (int i = 0; i < 20; i++) {
// 内层循环循环列
for (int j = 0; j < 10; j++) {
// 通过行列索引,获取每一个单元格对象
Cell cell = wall[i][j];
// 开始初始化单元格对象
// drawRect()方法可以绘制矩形
int x = j*CELL_SIZE;
int y = i*CELL_SIZE;
if(cell ==null){
g.drawRect(x,y,CELL_SIZE,CELL_SIZE);
}else {
// 代表当前单元格已经被其他形状的俄罗斯方块占用
g.drawImage(cell.getImage(),x,y,null);
}
}
}
}
}