一个写得非常不错的俄罗斯广场的实现。
原文:点击打开链接
import sun.audio.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
/**
* Description:a simple tetric game
*
Program Name:Tetric Game
*
Date:2012.08.24
* @author Garth http://xiaojia.me
* @version 1.0
*/
@SuppressWarnings("serial")
public class TetricGame extends JFrame{
public static void main(String[] args){
final TetricBlock tetricBlock = new TetricBlock();
final TetricGame tetricGame = new TetricGame();
//工具栏按钮动作
Action startAction = new AbstractAction("start" ,
new ImageIcon(TetricGame.class.getClassLoader().getResource("res/start.png"))) {
public void actionPerformed(ActionEvent e) {
tetricBlock.setIsGaming(true);
tetricGame.requestFocus();
}
};
Action pauseAction = new AbstractAction("pause" ,
new ImageIcon(TetricGame.class.getClassLoader().getResource("res/pause.png"))) {
public void actionPerformed(ActionEvent a) {
tetricBlock.setIsGaming(false);
tetricGame.requestFocus();
}
};
Action aboutAction = new AbstractAction("about" ,
new ImageIcon(TetricGame.class.getClassLoader().getResource("res/about.png"))) {
public void actionPerformed(ActionEvent e) {
tetricBlock.setIsGaming(false);
JOptionPane.showMessageDialog(null , "Java新手练习项目:俄罗斯方块\n" +
"作者:Garth\n" +
"博客:http://xiaojia.me");
tetricBlock.setIsGaming(true);
tetricGame.requestFocus();
}
};
Action closeAction = new AbstractAction("close" ,
new ImageIcon(TetricGame.class.getClassLoader().getResource("res/close.png"))) {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
JToolBar jtb = new JToolBar();
//工具栏垂直并不可拖动
jtb.setOrientation(JToolBar.VERTICAL);
jtb.setFloatable(false);
jtb.add(startAction);
jtb.add(pauseAction);
jtb.add(aboutAction);
jtb.add(closeAction);
tetricGame.add(jtb , BorderLayout.EAST);
tetricGame.add(tetricBlock);
tetricGame.addKeyListener(tetricBlock);
tetricGame.setSize( 323 , 474);
tetricGame.setLocationRelativeTo(null);
tetricGame.setTitle("俄罗斯方块");
tetricGame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tetricGame.setVisible(true);
//必不可少的一句,让主窗口获得焦点以监听键盘
tetricGame.requestFocus();
}
}
//方块类,继承JPanel类,实现KeyListener接口
@SuppressWarnings("serial")
class TetricBlock extends JPanel implements KeyListener{
//游戏得分
private int score = 0;
//方块下落的时间触发器
private Timer timer;
//方块下落速度值,值越小,速度越快
private int speed = 1000;
//游戏状态
private boolean isGaming = true;
//背景音乐
private MusicPlayer bkMusic;
//正在移动的方块坐标
private int x , y;
//方块类型与状态
private int blockType , blockState;
private int i = 0 , j = 0;
//已经下落固定的方块map,0-11 ,0-21
private int[][] map = new int[13][23];
//方块,一维代表类型,二维代表状态,三维代表组成方块矩阵
private final int[][][] block = new int[][][] {
{ //一横一竖
{ 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 }
},
{ //S型
{ 0,0,1,1 , 0,1,1,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,0,1,1 , 0,1,1,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 }
},
{ //L型
{ 1,0,0,0 , 1,0,0,0 , 1,1,0,0 , 0,0,0,0 },
{ 0,0,1,0 , 1,1,1,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 },
{ 1,1,1,0 , 1,0,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 },
{ 1,1,0,0 , 1,1,0,0 , 0,0,0,0 , 0,0,0,0 }
},
{ //T型
{ 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 },
{ 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 }
}
};
public TetricBlock() {
newBlock();
newMap();
drawWall();
timer = new Timer( speed , new TimerListener() );
timer.start();
}
//设置游戏状态
public void setIsGaming(boolean is) {
isGaming = is;
}
//画围墙
public void drawWall(){
//底部围墙
for(i = 0 ; i < 12 ; i ++) {
map[i][21] = 2;
}
//两边的围墙
for(i = 0 ; i < 22 ; i++) {
map[0][i] = 2;
map[11][i] = 2;
}
}
//初始化数组
public void newMap(){
for(i = 0 ; i < 12 ; i++) {
for(j = 0 ; j < 22 ; j++) {
map[i][j] = 0;
}
}
//循环播放背景音乐
try {
bkMusic = new MusicPlayer(TetricGame.class.getClassLoader().getResource("res/background.wav"));
bkMusic.loop();
}
catch(Exception e) {
}
}
//产生新的方块
public void newBlock(){
blockType = (int) (( Math.random() * 1000 ) % 7 );
blockState = (int) (( Math.random() * 1000) % 4 );
x = 4;
y = 0;
if(gameOver(x , y)){
JOptionPane.showMessageDialog(null, "Game Over! Score: " + score);
newMap();
drawWall();
score = 0;
speed = 1000;
timer.setDelay(speed);
isGaming = true;
}
}
//判断移动方块是否合法
public boolean canMove( int x , int y , int blockType , int blockState ) {
for( i = 0 ; i < 4 ; i++)
for( j = 0 ; j < 4 ; j++)
if(( block[blockType][blockState][ i * 4 + j ] == 1 &&
map[ j + x + 1][ i + y ] == 1 ) ||
( block[blockType][blockState][ i * 4 + j ] == 1 &&
map[ j + x + 1][ i + y ] == 2 ))
return false;
return true;
}
//判断游戏是否结束
public boolean gameOver( int x , int y ) {
if( !canMove( x , y , blockType , blockState ) ) {
isGaming = false;
//播放音乐
try {
bkMusic.stopLoop();
new MusicPlayer(TetricGame.class.getClassLoader().getResource("res/gameover.wav")).start();
}
catch(Exception e) {
}
return true;
}
return false;
}
//方块左移
public void moveLeft() {
if( isGaming && canMove( x - 1 , y , blockType , blockState ))
x--;
repaint();
}
//方块向右移
public void moveRight() {
if( isGaming && canMove( x + 1 , y , blockType , blockState ))
x++;
repaint();
}
//方块向下移
public void moveDown() {
if( isGaming ) {
if( canMove( x , y + 1 , blockType , blockState) ) {
y++;
dellLine();
}
else {
addBlock( x , y , blockType , blockState );
dellLine();
newBlock();
}
repaint();
}
}
//改变方块状态
public void turnState() {
if( isGaming ) {
int tempState = blockState;
blockState = ( blockState + 1 ) % 4;
if( !canMove( x , y , blockType , blockState ) )
blockState = tempState;
repaint();
}
}
//把不能再继续下落的方块加到固定方块里
public void addBlock( int x , int y , int blockType , int blockState ) {
try {
new MusicPlayer(TetricGame.class.getClassLoader().getResource("res/addblock.wav")).start();
}
catch(Exception e){
}
int k = 0;
for( i = 0 ; i < 4 ; i++){
for( j = 0 ; j < 4 ; j++) {
if(map[ j + x + 1 ][ i + y ] == 0) {
map[ j + x + 1 ][ i + y ] = block[blockType][blockState][k];
}
k++;
}
}
}
//消行
public void dellLine() {
int k = 0;
for( i = 0 ; i < 22 ; i++ ) {
for( j = 0 ; j < 12 ; j++ ) {
if( map[j][i] == 1) {
k++;
if( k >= 10 ) {
//播放声音
try {
new MusicPlayer(TetricGame.class.getClassLoader().getResource("res/delline.wav")).start();
}
catch(Exception e) {
}
//游戏分数添加分数
score += 10;
//速度越来越快
speed -= 15;
timer.setDelay( speed );
//消行后,把上面固定的方块下移
for( int a = i ; a > 0 ; a--)
for( int b = 0 ; b < 11 ; b++ ) {
map[b][a] = map[b][a - 1];
}
}
}
}
k = 0;
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
//方块图像
Image blockImage = null;
try{
blockImage = ImageIO.read(TetricGame.class.getClassLoader().getResource("res/block.png"));
}
catch (IOException e){
e.printStackTrace();
}
//正在下落的方块
for(i = 0 ; i < 16 ; i++) {
if( block[blockType][blockState][i] == 1 ) {
g.drawImage(blockImage, ((i % 4) + x + 1) * 20 , ((i / 4) + y) * 20,20,20 ,null);
}
}
//已经下落的固定的方块以及围墙
for(i = 0 ; i < 22 ; i++)
for(j = 0 ; j < 12 ; j++) {
if(map[j][i] == 1)
g.drawImage(blockImage , j * 20 , i * 20 , 20 , 20 , null);
if(map[j][i] == 2) {
g.setColor(new Color(9 , 106 , 187));
g.fillRect(j * 20 , i * 20 , 20 , 20);
}
}
}
//监听键盘上下左右方向键
public void keyPressed(KeyEvent e){
switch( e.getKeyCode() ) {
case KeyEvent.VK_UP:
turnState();
break;
case KeyEvent.VK_DOWN:
moveDown();
break;
case KeyEvent.VK_LEFT:
moveLeft();
break;
case KeyEvent.VK_RIGHT:
moveRight();
break;
}
}
public void keyReleased(KeyEvent arg0){
}
public void keyTyped(KeyEvent arg0){
}
//内部类,时间监听器
class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
moveDown();
}
}
//内部类,音乐播放器
class MusicPlayer{
//单次播放的声音
private AudioStream as = null;
//循环播放的声音
private ContinuousAudioDataStream cas = null;
public MusicPlayer(URL url) {
try {
as = new AudioStream(url.openStream());
}
catch(Exception e) {
}
}
//播放单次声音
public void start() {
if(as != null) {
AudioPlayer.player.start(as);
}
}
//停止单次播放的声音
public void stop() {
if(as != null) {
AudioPlayer.player.stop(as);
}
}
//循环播放声音
public void loop() {
AudioData data = null;
try {
data = as.getData();
}
catch(Exception e) {
}
if(data != null) {
cas = new ContinuousAudioDataStream(data);
AudioPlayer.player.start(cas);
}
}
//停止循环播放的声音
public void stopLoop() {
if(cas != null) {
AudioPlayer.player.stop(cas);
}
}
}
}