1.效果图
2. 实现的过程
Step1:先画面板
主要是三个方法:initWindow()初始化窗口,initGameInit()初始化面板;initExplainPanel()初始化解释面板,init()初始化参数
public void initWindow(){ this.setSize(600, 850); this.setLocationRelativeTo(null); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); this.setTitle("俄罗斯方块"); } public void initGameInit(){ JPanel game_main=new JPanel(); game_main.setLayout(new GridLayout(game_x,game_y,1,1)); for(int i=0;i<text.length;i++){ for(int j=0;j<text[i].length;j++){ text[i][j]=new JTextArea(game_x,game_y); text[i][j].setBackground(Color.WHITE); text[i][j].addKeyListener(this); if((j==0) || (j==text[i].length-1) || (i==text.length-1)){ text[i][j].setBackground(Color.MAGENTA); data[i][j]=1; } text[i][j].setEditable(false); game_main.add(text[i][j]); } } this.setLayout(new BorderLayout()); this.add(game_main,BorderLayout.CENTER); } public void initExplainPanel(){ JPanel explain_left=new JPanel(); JPanel explain_right=new JPanel(); explain_left.setLayout(new GridLayout(4,1)); explain_right.setLayout(new GridLayout(2,1)); explain_left.add(new JLabel("按空格键,方块变形")); explain_left.add(new JLabel("按左箭头,方块左移")); explain_left.add(new JLabel("按右箭头,方块右移")); explain_left.add(new JLabel("按下箭头,方块下落")); // explain_left.add(new JLabel("按'P',游戏暂停")); label1.setForeground(Color.red); explain_right.add(label); explain_right.add(label1); this.add(explain_left,BorderLayout.WEST); this.add(explain_right,BorderLayout.EAST); } /*** * 初始化 */ private void init() { text=new JTextArea[game_x][game_y]; data=new int[game_x][game_y]; label1=new JLabel("游戏状态:正在游戏中"); label=new JLabel("游戏分数为:0"); isRunning=true; allRect=new int[]{0x00cc,0x8888,0x000f,0x888f,0xf8888,0xf111,0x111f,0x0eee,0xffff,0x0008,0x0888,0x000e,0x0088,0x000c ,0x08c8,0x00e4,0x04c4,0x004e,0x08c4,0x006c,0x04c8,0x00c6}; }
Step2:参数设定以及生成方块
参数:
private static final int game_x=26; private static final int game_y=12; JTextArea[][] text; int[][] data; JLabel label1; JLabel label; boolean isRunning; int[] allRect;//存放所有方块 int rect;//存储当前方块的变量 //当前方块的坐标 int x,y; //线程休眠时间 int time=1000; int score=0; boolean game_pause=false; int pause_time=0;
方块:
方块的表示方法我是用十六进制数进行表示
首先看一下一个方块:
其他的方块都可以这样表示:
/**8 * 生成一个随机的方块 */ public void ranRect(){ Random random=new Random(); rect=allRect[random.nextInt(22)]; }
Step3:设置游戏开始:
其中包括的方法主要是:game_run(),先随机生成方块,再判断方块是否可以下落,如果可以下落,先改变data的值表示这里有方块,再判断移除的条件,最后判断游戏失败的条件
public void game_begin(){ while(true){ if(!isRunning){ break; } game_run(); } label1.setText("游戏状态:游戏结束!"); } /*** * 游戏run */ private void game_run() { ranRect(); x=0; y=5; for(int i=0;i<game_x;i++){ try { Thread.sleep(time); if(game_pause){ i--; }else{ //判断方块是否可以下落 if(!canFall(x,y)){ //将data置为1,表示有方块占用 changData(x,y); //4是表示方块是4*4的方块 for(int j=x;j<x+4;j++){ int sum=0; for(int k=1;k<=(game_y-2);k++){ /*** * 表示这里有方块 * sum+1 */ if(data[j][k]==1){ sum++; } } /*** * 如果sum为game_y-2 * 说明这行可以消除 */ if(sum==(game_y-2)){ removeRow(j); } } /**8 * 游戏失败的条件是: * 前四行有方块 * 只需要第四行有方块就游戏结束 */ for(int j=1;j<=(game_y-2);j++){ if(data[3][j]==1){ isRunning=false; break; } } break; }else{ x++; //方块下落一格 fall(x,y); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
方块是否可以下落:直接通过data数组进行判断,之间在下落的时间会将data数组的i,j位置置于1,如果此时该位置的data数组不为1就可以下落
private boolean canFall(int x, int y) { int temp=0x8000; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp& rect) !=0){ //判断该位置的下一行是否有方块 if(data[x+1][y]==1){ return false; } } y++; temp = temp >> 1; } x++; y=y-4; } return true; }
下落的方法:直接清除掉上一层的方块,再重新绘制下一层的方块
/** * 方块下落 * @param m * @param n */ private void fall(int m,int n) { if(m>0){ //清除上一层的方块 clear(m-1,n); } //重新绘制 draw(m,n); } /*** * 绘制方块 * @param m * @param n */ private void draw(int m, int n) { int temp=0x8000; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp& rect) !=0){ text[m][n].setBackground(Color.BLUE); } n++; temp = temp >> 1; } m++; n=n-4; } } /** * 清除这行 * 就是将文本域的颜色设为白色就可 * @param m * @param n */ private void clear(int m, int n) { int temp=0x8000; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp& rect) !=0){ text[m][n].setBackground(Color.WHITE); } n++; temp = temp >> 1; } m++; n=n-4; } }
当有一行可以消除时,移除某一行方法:主要是通过改变文本块颜色进行移除
/*** * 移除某一行 * @param row */ private void removeRow(int row) { int temp=100; for(int i=row;i>=1;i--){ for(int j=1;j<(game_y-2);j++){ data[i][j]=data[i-1][j]; } } //刷新游戏区域 reflesh(row); //游戏加速 if(time>temp){ time-=temp; } score+=temp; label.setText("游戏得分: "+score); } private void reflesh(int row) { for(int i=row;i>=1;i--){ for(int j=1;j<(game_y-2);j++){ if(data[i][j]>=1){ text[i][j].setBackground(Color.BLUE); }else{ text[i][j].setBackground(Color.WHITE); } } } }
改变data值:
private void changData(int x, int y) { int temp=0x8000; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp& rect) !=0){ data[x][y]=1; } y++; temp = temp >> 1; } x++; y=y-4; } }
Step4:鼠标监听事件:
通过进行鼠标的左移、右移、下移、变形进行操作,主要是继承KeyListener重写三个方法
这里主要是进行变形的时候需要注意
@Override public void keyTyped(KeyEvent e) { if(e.getKeyChar()=='p'){ if(! isRunning){ return; } pause_time++; if(pause_time==1){ game_pause=true; label1.setText("游戏暂停"); } if(pause_time==2){ game_pause=false; pause_time=0; label1.setText("游戏继续"); } } if(e.getKeyChar()==KeyEvent.VK_SPACE){ if(! isRunning){ return; } if(game_pause){ return; } int old; for(old=0;old<allRect.length;old++){ if(rect==allRect[old]){ break; } } int next; if(old==0||old==7||old==8||old==9){ return; } clear(x,y); if(old==1 || old==2){ next=allRect[old==1 ?2:1]; if(canTurn(next,x,y)){ rect =next; } } if(old>=3 && old<=6){ next=allRect[old+1>6 ? 3:old+1]; if(canTurn(next,x,y)){ rect =next; } } if(old==10 || old==11){ next=allRect[old==10 ?11:10]; if(canTurn(next,x,y)){ rect =next; } } if(old==12 || old==13){ next=allRect[old==12 ?13:12]; if(canTurn(next,x,y)){ rect =next; } } if(old>=14 && old<=17){ next=allRect[old+1>17 ? 14:old+1]; if(canTurn(next,x,y)){ rect =next; } } if(old==18 || old==19){ next=allRect[old==18 ?19:18]; if(canTurn(next,x,y)){ rect =next; } } if(old==20 || old==21){ next=allRect[old==20 ?21:20]; if(canTurn(next,x,y)){ rect =next; } } draw(x,y); } } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if(keyCode==KeyEvent.VK_LEFT){ if(!isRunning){ return; } if(y<=1){ return; } if(game_pause){ return; } int temp=0x8000; for(int i=x;i<x+4;i++){ for(int j=y;j<y+4;j++){ if((temp&rect)!=0){ if(data[i][j-1]!=0){ return; } } temp>>=1; } } clear(x,y); y--; draw(x,y); } if(keyCode==KeyEvent.VK_RIGHT){ if(!isRunning){ return; } if(game_pause){ return; } int temp=0x8000; int m=x; int n=y; int num=1; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp&rect)!=0){ if(n>num){ num=n; } } n++; temp>>=1; } m++; n=n-4; } if(num>=(game_y-2)){ return; } temp=0x8000; for(int i=x;i<x+4;i++){ for(int j=y;j<y+4;j++){ //temp&rect为1表示这里有方块 if((temp&rect)!=0){ if(data[i][j+1]!=0){ return; } } temp>>=1; } } clear(x,y); y++; draw(x,y); } if(keyCode==KeyEvent.VK_DOWN){ System.out.println("down"); if(!isRunning){ return; } if(!canFall(x,y)){ return; } if(game_pause){ return; } clear(x,y); x++; draw(x,y); } } private boolean canTurn(int next, int x, int y) { int temp=0x8000; for(int i=0;i<4;i++){ for(int j=0;j<4;j++){ if((temp&next)!=0){ if(data[x][y]==1){ return false; } } y++; temp>>=1; } x++; y=y-4; } System.out.println("ttur"); return true; } @Override public void keyReleased(KeyEvent e) { }
Step5:主函数调用
public static void main(String[] args) {
MyTertris myTertris=new MyTertris();
myTertris.game_begin();
}
3.完整代码
package com.tetris.study;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class MyTertris extends JFrame implements KeyListener{
private static final int game_x=26;
private static final int game_y=12;
JTextArea[][] text;
int[][] data;
JLabel label1;
JLabel label;
boolean isRunning;
int[] allRect;//存放所有方块
int rect;//存储当前方块的变量
//当前方块的坐标
int x,y;
//线程休眠时间
int time=1000;
int score=0;
boolean game_pause=false;
int pause_time=0;
public MyTertris() {
init();
initGameInit();
initExplainPanel();
initWindow();
}
public void initWindow(){
this.setSize(600, 850);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle("俄罗斯方块");
}
public void initGameInit(){
JPanel game_main=new JPanel();
game_main.setLayout(new GridLayout(game_x,game_y,1,1));
for(int i=0;i<text.length;i++){
for(int j=0;j<text[i].length;j++){
text[i][j]=new JTextArea(game_x,game_y);
text[i][j].setBackground(Color.WHITE);
text[i][j].addKeyListener(this);
if((j==0) || (j==text[i].length-1) || (i==text.length-1)){
text[i][j].setBackground(Color.MAGENTA);
data[i][j]=1;
}
text[i][j].setEditable(false);
game_main.add(text[i][j]);
}
}
this.setLayout(new BorderLayout());
this.add(game_main,BorderLayout.CENTER);
}
public void initExplainPanel(){
JPanel explain_left=new JPanel();
JPanel explain_right=new JPanel();
explain_left.setLayout(new GridLayout(4,1));
explain_right.setLayout(new GridLayout(2,1));
explain_left.add(new JLabel("按空格键,方块变形"));
explain_left.add(new JLabel("按左箭头,方块左移"));
explain_left.add(new JLabel("按右箭头,方块右移"));
explain_left.add(new JLabel("按下箭头,方块下落"));
// explain_left.add(new JLabel("按'P',游戏暂停"));
label1.setForeground(Color.red);
explain_right.add(label);
explain_right.add(label1);
this.add(explain_left,BorderLayout.WEST);
this.add(explain_right,BorderLayout.EAST);
}
/***
* 初始化
*/
private void init() {
text=new JTextArea[game_x][game_y];
data=new int[game_x][game_y];
label1=new JLabel("游戏状态:正在游戏中");
label=new JLabel("游戏分数为:0");
isRunning=true;
allRect=new int[]{0x00cc,0x8888,0x000f,0x888f,0xf8888,0xf111,0x111f,0x0eee,0xffff,0x0008,0x0888,0x000e,0x0088,0x000c
,0x08c8,0x00e4,0x04c4,0x004e,0x08c4,0x006c,0x04c8,0x00c6};
}
public void game_begin(){
while(true){
if(!isRunning){
break;
}
game_run();
}
label1.setText("游戏状态:游戏结束!");
}
/***
* 游戏run
*/
private void game_run() {
ranRect();
x=0;
y=5;
for(int i=0;i<game_x;i++){
try {
Thread.sleep(time);
if(game_pause){
i--;
}else{
//判断方块是否可以下落
if(!canFall(x,y)){
//将data置为1,表示有方块占用
changData(x,y);
//4是表示方块是4*4的方块
for(int j=x;j<x+4;j++){
int sum=0;
for(int k=1;k<=(game_y-2);k++){
/***
* 表示这里有方块
* sum+1
*/
if(data[j][k]==1){
sum++;
}
}
/***
* 如果sum为game_y-2
* 说明这行可以消除
*/
if(sum==(game_y-2)){
removeRow(j);
}
}
/**8
* 游戏失败的条件是:
* 前四行有方块
* 只需要第四行有方块就游戏结束
*/
for(int j=1;j<=(game_y-2);j++){
if(data[3][j]==1){
isRunning=false;
break;
}
}
break;
}else{
x++;
//方块下落一格
fall(x,y);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 方块下落
* @param m
* @param n
*/
private void fall(int m,int n) {
if(m>0){
//清除上一层的方块
clear(m-1,n);
}
//重新绘制
draw(m,n);
}
/***
* 绘制方块
* @param m
* @param n
*/
private void draw(int m, int n) {
int temp=0x8000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp& rect) !=0){
text[m][n].setBackground(Color.BLUE);
}
n++;
temp = temp >> 1;
}
m++;
n=n-4;
}
}
/**
* 清除这行
* 就是将文本域的颜色设为白色就可
* @param m
* @param n
*/
private void clear(int m, int n) {
int temp=0x8000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp& rect) !=0){
text[m][n].setBackground(Color.WHITE);
}
n++;
temp = temp >> 1;
}
m++;
n=n-4;
}
}
/***
* 移除某一行
* @param row
*/
private void removeRow(int row) {
int temp=100;
for(int i=row;i>=1;i--){
for(int j=1;j<(game_y-2);j++){
data[i][j]=data[i-1][j];
}
}
//刷新游戏区域
reflesh(row);
//游戏加速
if(time>temp){
time-=temp;
}
score+=temp;
label.setText("游戏得分: "+score);
}
private void reflesh(int row) {
for(int i=row;i>=1;i--){
for(int j=1;j<(game_y-2);j++){
if(data[i][j]>=1){
text[i][j].setBackground(Color.BLUE);
}else{
text[i][j].setBackground(Color.WHITE);
}
}
}
}
private void changData(int x, int y) {
int temp=0x8000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp& rect) !=0){
data[x][y]=1;
}
y++;
temp = temp >> 1;
}
x++;
y=y-4;
}
}
private boolean canFall(int x, int y) {
int temp=0x8000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp& rect) !=0){
//判断该位置的下一行是否有方块
if(data[x+1][y]==1){
return false;
}
}
y++;
temp = temp >> 1;
}
x++;
y=y-4;
}
return true;
}
/**8
* 生成一个随机的方块
*/
public void ranRect(){
Random random=new Random();
rect=allRect[random.nextInt(22)];
}
public static void main(String[] args) {
MyTertris myTertris=new MyTertris();
myTertris.game_begin();
}
@Override
public void keyTyped(KeyEvent e) {
if(e.getKeyChar()=='p'){
if(! isRunning){
return;
}
pause_time++;
if(pause_time==1){
game_pause=true;
label1.setText("游戏暂停");
}
if(pause_time==2){
game_pause=false;
pause_time=0;
label1.setText("游戏继续");
}
}
if(e.getKeyChar()==KeyEvent.VK_SPACE){
if(! isRunning){
return;
}
if(game_pause){
return;
}
int old;
for(old=0;old<allRect.length;old++){
if(rect==allRect[old]){
break;
}
}
int next;
if(old==0||old==7||old==8||old==9){
return;
}
clear(x,y);
if(old==1 || old==2){
next=allRect[old==1 ?2:1];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old>=3 && old<=6){
next=allRect[old+1>6 ? 3:old+1];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old==10 || old==11){
next=allRect[old==10 ?11:10];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old==12 || old==13){
next=allRect[old==12 ?13:12];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old>=14 && old<=17){
next=allRect[old+1>17 ? 14:old+1];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old==18 || old==19){
next=allRect[old==18 ?19:18];
if(canTurn(next,x,y)){
rect =next;
}
}
if(old==20 || old==21){
next=allRect[old==20 ?21:20];
if(canTurn(next,x,y)){
rect =next;
}
}
draw(x,y);
}
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode==KeyEvent.VK_LEFT){
if(!isRunning){
return;
}
if(y<=1){
return;
}
if(game_pause){
return;
}
int temp=0x8000;
for(int i=x;i<x+4;i++){
for(int j=y;j<y+4;j++){
if((temp&rect)!=0){
if(data[i][j-1]!=0){
return;
}
}
temp>>=1;
}
}
clear(x,y);
y--;
draw(x,y);
}
if(keyCode==KeyEvent.VK_RIGHT){
if(!isRunning){
return;
}
if(game_pause){
return;
}
int temp=0x8000;
int m=x;
int n=y;
int num=1;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp&rect)!=0){
if(n>num){
num=n;
}
}
n++;
temp>>=1;
}
m++;
n=n-4;
}
if(num>=(game_y-2)){
return;
}
temp=0x8000;
for(int i=x;i<x+4;i++){
for(int j=y;j<y+4;j++){
//temp&rect为1表示这里有方块
if((temp&rect)!=0){
if(data[i][j+1]!=0){
return;
}
}
temp>>=1;
}
}
clear(x,y);
y++;
draw(x,y);
}
if(keyCode==KeyEvent.VK_DOWN){
System.out.println("down");
if(!isRunning){
return;
}
if(!canFall(x,y)){
return;
}
if(game_pause){
return;
}
clear(x,y);
x++;
draw(x,y);
}
}
private boolean canTurn(int next, int x, int y) {
int temp=0x8000;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((temp&next)!=0){
if(data[x][y]==1){
return false;
}
}
y++;
temp>>=1;
}
x++;
y=y-4;
}
System.out.println("ttur");
return true;
}
@Override
public void keyReleased(KeyEvent e) {
}
}