效果:
1. 概述
随着时代的发展,电子游戏逐渐出现,早起的一些桌面小游戏风靡全球,其中就有《俄罗斯方块》,《俄罗斯方块》(Tetris)是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏。该游戏曾经被多家公司代理过。经过多轮诉讼后,该游戏的代理权最终被任天堂获得。任天堂对于俄罗斯方块来说意义重大,因为将它与GB搭配在一起后,获得了巨大的成功。《俄罗斯方块》的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分,上手简单、老少皆宜、家喻户晓。本文将详述我个人开发的一款基于这款游戏的简易俄罗斯方块,实现该游戏基本功能,如自动出方块,可翻转、左移、右移、下降,暂停,增加难度,降低难度并且达到消行加分的功能。
2. 系统分析
系统分为两大板块,一个是方块工厂,另一个是游戏显示画板,方块工厂用来生成方、翻转、移动和固定,游戏画板用于绘画,并加上定时器和监听器,用于反馈用户按键事件,传递到方块工厂来控制方块,并且检查方块是否碰撞或消行等状态
3. 系统设计,
3.1系统目标
①在顶部生成方块
②方块反转、左移、右移、下降
③方块在特定的游戏区域内运动
④定时器定一特定长时间作为时间间隔来触发ActionEvent使方块定时下落一格
⑤检测是否碰撞(包括与围墙,底部,已固定方块),碰撞则停止并生成新的方块下落
⑥检查是否能消行,且消行要加分记录并显示在界面上,并且放出beep音效
⑦生成方块前检查最顶行有没有方块,有则弹框提示结束游戏并显示所得分数,
按确认后重新开始游戏。
⑧游戏区域中,围墙隐藏起来,方块可运动区域有网格,右边有分数显示且有操作方法提示,方块下落时蓝色,固定时为绿色,便于区分。
⑨开始运行时弹对话框是否开始游戏
⑩可以暂停游戏
⑪增加难度(下落速度增加)
⑫降低难度(下落速度减少)
⑬难度范围为0-10
3.2系统功能结构
3.3 系统预览
代码:
TetrisGame.java
package MyTetris2;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
/**
* 游戏主程序
* @author LEUNG
*
*/
public class TetrisGame extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
private GamePanel t ;
private static int flag=0;
/**
* 构造方法
*/
TetrisGame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(800,100);
setTitle("俄罗斯方块");
setSize(600,750);
setResizable(true); //不可缩放
}
/**
* 添加画板
* 开始跑Timer
*/
public void startGame(){
t = new GamePanel();
add(t);
addKeyListener(t);
t.timer.start();
}
public static void main(String[] args){
TetrisGame tetris = new TetrisGame();
tetris.setVisible(true);
flag = JOptionPane.showConfirmDialog(tetris, //开始选择对话框
"按【是】开始新游戏\n按【否】退出游戏", "new Game", JOptionPane.YES_NO_OPTION);
if(flag==JOptionPane.YES_OPTION){
tetris.startGame();
tetris.setVisible(true);
}
else{
tetris.dispose();
System.exit(0);
}
}
}
Block.java
package MyTetris2;
/**
* 方块类
* 内含方块的基本方法(方块固定、新建、翻转、左移、右移、下移)
* @author LEUNG
*
*/
public class Block {
/**
* 方块用一个三维数组来存,分别是形状,形态,坐标(在4×4方格中,1表示要填充,0表示不填充)
*7种图形分别是J,L,S,Z,T,O,I
*4种形态,旋转得到的
*/
public final int shapes[][][] = new int[][][]{
//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}},
//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}},
//S
{{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}},
//T
{{0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
{1,0,0,0,1,1,0,0,1,0,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,1,1,0,0,0,1,0,0,0,0,0,0}},
//O
{{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}},
//I
{{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}}, };
/**
* x,y用来记录方块4×4区域中的(0,0)点的位置,x,y中的(0,0)相对于map中是(1,0)
*/
public int x;
public int y;
public int blockType=0; //方块类型
public int blockState=0; //方块状态
public int initX = 4; //初始位置的X,Y值
public int initY = 0;
GamePanel game;
/**
* 构造方法
*/
Block(GamePanel game){ //引用游戏画板
this.game = game;
}
/**
* 新建方块(初始化)
*/
public void newblock(){
blockType = (int)(Math.random()*1000)%7; //范围0-6
blockState = (int)(Math.random()*1000)%4; //范围0-3
x=initX;
y=initY;
}
/**
* 把需要固定的方块固定
* 存放在map数组中
*/
public void add(){
int i=0;
for(int a=0;a<4;a++){
for(int b=0;b<4;b++){
if(game.map[x+1+b][y+a]==0){ // map[列][行]
game.map[x+1+b][y+a]=shapes[blockType][blockState][i];
}
i++;
}
}
}
/**
* 右移
*/
public void right() {
if(!game.isCollied(x+1,y)){
x++;
}
game.repaint();
}
/**
* 下移
*/
public void down() {
if(!game.isCollied(x,y+1)){
y++;
}else{
add(); //碰撞到底部后,把方块添加到画布上去
game.deleteLine();
newblock();
}
game.repaint();
}
/**
* 左移
*/
public void left() {
if(!game.isCollied(x-1,y)){
x--;
}
game.repaint();
}
/**
* 转换状态
*/
public void turnState() {
int temp = blockState; //首先记录本状态
blockState = (blockState+1)%4;
if(game.isCollied(x,y)){
blockState = temp;
}
game.repaint();
}
}
GamePanel.java
package MyTetris2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* 游戏界面画板
* @author LEUNG
*
*/
public class GamePanel extends JPanel implements KeyListener{
/**
*
*/
private static final long serialVersionUID = 1L;
public int MAPCOL=13; //游戏画布的列数
public int MAPROW=23; //游戏画布的行数
public int PIXEL=30; //像素,单位格子的长、宽
public int score;
public int map[][]=new int[MAPCOL][MAPROW];
public Timer timer ;
private int Level=5; //初始难度5
private Block block; //引用Block类
private TimerListener timerlistener;
/**
* 内部类,被timer触发
* @author LEUNG
*
*/
private class TimerListener implements ActionListener{ //实现接口
@Override
public void actionPerformed(ActionEvent e) {
if(!isCollied(block.x,block.y+1)){
block.y++;
}else{
block.add(); //碰撞到底部后,把方块添加到画布上去
deleteLine();
if(true==isGameover()){
JOptionPane.showMessageDialog(null, "Game Over\n你的分数是:"+score);
cleanMap();
drawWall();
score=0;
}
block.newblock();
}
repaint(); //重画
}
}
/**
* 构造方法
*/
GamePanel(){
block = new Block(this); //引用Block类,参数是GamePanel类
cleanMap();
drawWall();
block.newblock();
timerlistener=new TimerListener();
timer = new Timer(800, timerlistener); //计时器,在指定时间间隔触发TimerListener()
}
/**
* 增加难度
*/
private void upLevel(){
if(Level<10){
Level++;
timer.setDelay(1300-100*Level);
repaint();
}
}
/**
* 降低难度
*/
private void downLevel(){
if(Level>0){
Level--;
timer.setDelay(1300-100*Level);
repaint();
}
}
/**
* 围墙内的画面置零,相当于清除画面
*/
private void cleanMap(){
for(int i=1;i0;a--){ //从第i行开始
for(int b=1;b