学习Java半年有余,总想做点什么出来,而不是只纠结与语法和各种类包不可自拔。 于是我想,何不搞一个小游戏出来。 俄罗斯方块?脑海里浮现出这个名字,就它了,逻辑简单,对于我而言更可控, 在网上查找相关的规则之后,经过五天的编码和设计,终于做了出来。
我也不多说废话了,直接贴代码,注释很详细了,希望可以帮到大家~
-
主逻辑的实现:游戏流程控制
//package 俄罗斯方块;
/**俄罗斯方块
*date 14.11.17
*@version 1.0@author TaXueWWL
/
import java.awt.;
import java.awt.event.;
import javax.swing.;
import javax.swing.Timer;class Tetrisblok extends JPanel implements KeyListener{
/**
*俄罗斯方块类Tetrisblok继承JPanel,同时实现键盘事件接口KeyListener
*/
private static final long serialVersionUID = 1L;
private int blockType;//方块类型
private int turnState;//方块旋转状态
private int score = 0;//分数
private int nextblockType = -1, nextturnState = -1;//下一方块的类型和状态
private int x, y;//当前方块的位置
private Timer timer;//定时器
//游戏地图,存储已经放下的方块(1)及围墙(2),空白处为(0)
int[][] map = new int[12][21];
//方块的形状,有倒Z,Z,L,J,I,田,和T 7种p/**
*三维数组shapes存储7种方块形状及其旋转变形,代码如下
*/
private final int shapes[][][] = new int[][][]{
//长条T形 ***
// ×
{ {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0}},
//倒Z字形 **
// **
{ {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
{0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},
//Z字形 **
// **
{ {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},
//J字形 *
// ***
{ {0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},
{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},
{1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0}},
//田字形 **
// **
{ {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
//L字形 *
// *
// *×
{ {1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},
{1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},
{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},
//⊥字形 *
// ***
{ {0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
{0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
{1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0}}};/**
产生下一方块及其旋转状态
/
public void newblock(){
//没有下一方块
if(nextblockType == -1 && nextturnState == -1){
blockType = (int)(Math.random()1000)%7;
turnState = (int)(Math.random()1000)%4;
nextblockType = (int)(Math.random() * 1000)%7;
nextturnState = (int)(Math.random() * 1000)%4;
}
else{//已有下一方块
blockType = nextblockType;
turnState = nextturnState;
nextblockType = (int)(Math.random() * 1000)%7;
nextturnState = (int)(Math.random() * 1000)%4;
}
x = 4; y = 0;//屏幕上方中央
if(gameover(x, y) == 1){//游戏结束
newmap();
drawwall();
score = 0;
JOptionPane.showMessageDialog(null, "GAME OVER...");
}
}
/**
*画围墙
*/
public void drawwall(){
int i, j;
for(i = 0; i < 12; i++){
map[i][20] = 2;
}
for(j = 0; j < 21; j++){//在0列和11列
map[11][j] = 2;
map[0][j] = 2;
}}
//初始化地图
public void newmap(){
int i, j;
for(i = 0; i < 12; i++){
for(j = 0; j < 21; j++){
map[i][j] = 0;
}
}
}
/**
*Tetrisblok()构造方法产生一个新的下落方块,并启动定时器。
*定时器触发事件完成屏幕屏幕重画,判断当前方块是否可以下落
产生新的方块
/
Tetrisblok(){
newblock();
newmap();
drawwall();
timer = new Timer(500, new TimerListener());//0.5s
timer.start();
}
//定时器监听事件
class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if(blow(x, y + 1, blockType, turnState) == 1){//可以下落
y = y + 1;//当前方块下落
}
if(blow(x, y + 1, blockType, turnState) == 0){//不可以下落
add(x, y, blockType, turnState);//固定当前方块
delline();//消去满行
newblock();//产生新的方块
}
repaint();
}
}
//菜单事件,达到游戏暂停和继续
public void newGame()//新游戏
{
newblock();
newmap();
drawwall();
}
public void pauseGame()//暂停游戏
{
timer.stop();
}
public void continueGame()//继续游戏
{
timer.start();
}
/
*turn()旋转当前方块,旋转次数加一后,blow判断是否可以
*旋转,不可以则旋转次数恢复为原来的值
*///旋转当前方块 public void turn(){ int tempturnState = turnState; turnState = (turnState + 1) % 4; if(blow(x, y, blockType, turnState) == 1){//可以旋转 } if(blow(x, y, blockType, turnState) == 0){//不可旋转 turnState = tempturnState;//将旋转次数恢复为原来的值 } repaint(); } //方向移动方块,判断可移动后重画 public void left(){ if(blow(x - 1, y, blockType, turnState) == 1){ x = x - 1; } repaint(); } public void right(){ if(blow(x + 1, y, blockType, turnState) == 1){ x = x + 1; } repaint(); } public void down(){ if(blow(x, y + 1, blockType, turnState) == 1){//可以下落 y = y + 1; } if(blow(x, y + 1, blockType, turnState) == 0){//不能下落 add(x, y, blockType, turnState); newblock(); delline(); } repaint(); } //判断移动或旋转后位置是否合法,是否与墙壁碰撞 public int blow(int x, int y, int blockType, int turnState){ for(int a = 0; a < 4; a++){ for(int b = 0; b < 4; b++){ if(((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x + b + 1][y + a] == 1)) || ((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x + b + 1][y + a] == 2))){ return 0; } } } return 1; } //delline()消去满行,第d行满则上方方块下移 public void delline(){ int c = 0; for(int b = 0; b < 21; b++){ for(int a = 0; a < 12; a++){ if(map[a][b] == 1){ c += 1; if(c == 10){//该行满 score += 10; for(int d = b; d > 0; d--){ for(int e = 0; e < 12; e++){ //上方方块下移 map[e][d] = map[e][d - 1]; } } } } } c = 0; } } //gameover public int gameover(int x, int y){ if(blow(x, y, blockType, turnState) == 0){ return 1; } return 0; } //添加当前方块到地图 public void add(int x, int y, int blockType, int turnState){ int j = 0; for(int a = 0; a < 4; a++){ for(int b = 0; b < 4; b++){ if(shapes[blockType][turnState][j] == 1){ map[x + b + 1][y + a] = shapes[blockType][turnState][j]; } j++; } } } //paint()重画屏幕 public void paint(Graphics g){ super.paint(g);//调用父类的paint()方法,实现初始化清屏 int i, j; //画当前方块 for(j = 0; j < 16; j++){ if(shapes[blockType][turnState][j] == 1){ g.fillRect((j % 4 + x + 1) * 15, (j / 4 + y) * 15, 15, 15); } } //画已经固定的方块和围墙 for(j = 0; j < 21; j++){ for(i = 0; i < 12; i++){ if(map[i][j] == 1){ //画方块 g.fillRect(i * 15, j * 15, 15, 15); } if(map[i][j] == 2){ //画围墙 g.fillRect(i * 15, j * 15, 15, 15); } } } g.drawString("SCORE= " + score, 225, 15); g.drawString("nextBlockShape ", 225, 50); //在窗口右侧区域绘制下一方块 for(j = 0; j < 16; j++){ if(shapes[nextblockType][nextturnState][j] == 1){ g.fillRect(225 + (j % 4) * 15, (j / 4) * 15 + 100, 15, 15); } } } //键盘监听 public void keyPressed(KeyEvent e){ switch(e.getKeyCode()){ case KeyEvent.VK_DOWN: down(); break; case KeyEvent.VK_UP: turn(); break; case KeyEvent.VK_RIGHT: right(); break; case KeyEvent.VK_LEFT: left(); break; } } //No use to type other keys public void keyReleased(KeyEvent e){ } public void keyTyped(KeyEvent e){ }
}
2.游戏面板呈现//package 俄罗斯方块;
/**
*显示游戏面板Tetrisblok界面,加入菜单以及时间监听
*/import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//import 俄罗斯方块.Tetrisblok;
import javax.swing.*;
@SuppressWarnings("serial")
public class TetrisFrame extends JFrame implements ActionListener{
static JMenu game = new JMenu("游戏");
JMenuItem newgame = game.add("新游戏");
JMenuItem pause = game.add("暂停");
JMenuItem goon = game.add("继续");
JMenuItem exit = game.add("退出");
static JMenu help = new JMenu("帮助");
JMenuItem about = help.add("关于");
Tetrisblok a = new Tetrisblok();
public TetrisFrame(){
addKeyListener(a);
this.add(a);
newgame.addActionListener(this);//"新游戏"菜单项
pause.addActionListener(this);//"暂停"菜单项
goon.addActionListener(this);//"继续"菜单项
about.addActionListener(this);//"关于"菜单项
exit.addActionListener(this);//"退出"菜单项
}public void actionPerformed(ActionEvent e){ if(e.getSource() == newgame)//"新游戏"菜单项 { a.newGame(); } else if(e.getSource() == pause)//"暂停"菜单项 { a.pauseGame(); } else if(e.getSource() == goon)//"继续"菜单项 { a.continueGame(); } else if(e.getSource() == about)//"关于"菜单项 { DisplayToast("按左右键移动\n上键进行方块旋转~\n\r\rMade_by_WWL\nFor SSR_LSC_LWW_CYD_XM"); } else if(e.getSource() == exit)//"退出"菜单项 { System.exit(0); } } public void DisplayToast(String str){ JOptionPane.showMessageDialog(null, str, "游戏提示", JOptionPane.ERROR_MESSAGE); } //Main Method public static void main(String[] args){ TetrisFrame frame = new TetrisFrame(); JMenuBar menu = new JMenuBar(); frame.setJMenuBar(menu); menu.add(game); menu.add(help); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//"结束"按钮可使用 frame.setSize(320, 380); frame.setTitle("俄罗斯方块V1.0--for XM"); //frame.setUndecorated(true); frame.setVisible(true); frame.setResizable(false); }
}
鸣谢:
感谢一直支持我的父亲,默默地爱着我的母亲,还有9102的小伙伴们,以及316的兄弟们。
也感谢努力着的自己,多年以后回头看到现在的自己,会笑着说声:“谢谢你,曾经这样的努力~”