45fan.com - 路饭网

搜索: 您的位置主页 > 网络频道 > 阅读资讯:俄罗斯方块游戏介绍

俄罗斯方块游戏介绍

2016-09-04 10:46:18 来源:www.45fan.com 【

俄罗斯方块游戏介绍

public class Game extends java.awt.Frame

{

public Game()

{

setTitle("俄罗斯方块游戏 - Ghost Valley");

addWindowListener(new java.awt.event.WindowAdapter(){

public void windowClosing(java.awt.event.WindowEvent e){

dispose();

System.exit(0);

}

});

GameCanvas gameCanvas = new GameCanvas();

setLayout(new java.awt.BorderLayout());

add(gameCanvas,"Center");

setResizable(false);

setLocation((java.awt.Toolkit.getDefaultToolkit().getScreenSize().width-gameCanvas.getPreferredSize().width)/2,(java.awt.Toolkit.getDefaultToolkit().getScreenSize().height-gameCanvas.getPreferredSize().height)/2);

pack();

show();

}

public static void main(String args[]){ new Game(); }

}

class GameCanvas extends java.awt.Canvas implements Runnable

{

public static final int BKSIZE = 5;

public static final int BDWIDTH = 20;

public static final int BDHEIGHT = 30;

////// Inner class Block////////

private class Block

{

public boolean bkdata[][] = new boolean[BKSIZE][BKSIZE];

public int rpos,cpos;

public Block(final boolean bkdata1[][],int rpos,int cpos)

{

//this.bkdata = (boolean[][])bkdata1.clone();

for(int i=0; i for(int j=0; j this.bkdata[i][j] = bkdata1[i][j];

this.rpos = rpos;

this.cpos = cpos;

}

public Block(final Block bk)

{

//this.bkdata = (boolean[][])bk.bkdata.clone();

for(int i=0; i for(int j=0; j this.bkdata[i][j] = bk.bkdata[i][j];

this.rpos = bk.rpos;

this.cpos = bk.cpos;

}

public void doAction(int action)

{

switch(action)

{

case Message.MOVE_UP:

this.rpos--;

break;

case Message.MOVE_DOWN:

this.rpos++;

break;

case Message.MOVE_LEFT:

this.cpos--;

break;

case Message.MOVE_RIGHT:

this.cpos++;

break;

case Message.ROTATE_CLOCK:

{

final int x0 = BKSIZE/2;

final int y0 = BKSIZE/2;

//boolean bkdata1[][] = (boolean[][])this.bkdata.clone();

boolean bkdata1[][] = new boolean[BKSIZE][BKSIZE];

for(int i=0; i for(int j=0; j bkdata1[i][j] = this.bkdata[i][j];

for(int x=0; x for(int y=0; y this.bkdata[y][-x+2*y0] = bkdata1[x][y];

break;

}

case Message.ROTATE_ANTICLOCK:

{

final int x0 = BKSIZE/2;

final int y0 = BKSIZE/2;

//boolean bkdata1[][] = (boolean[][])this.bkdata.clone();

boolean bkdata1[][] = new boolean[BKSIZE][BKSIZE];

for(int i=0; i for(int j=0; j bkdata1[i][j] = this.bkdata[i][j];

for(int x=0; x for(int y=0; y this.bkdata[-y+2*x0][x] = bkdata1[x][y];

break;

}

}

}

}

////// Inner class Board /////

private class Board

{

public boolean bddata[][] = new boolean[BDHEIGHT][BDWIDTH];

public Board()

{

clear();

}

public Board(final Board board)

{

//this.bddata = (boolean[][])board.bddata.clone();

for(int i=0; i for(int j=0; j this.bddata[i][j] = board.bddata[i][j];

}

public void clear()

{

for(int i=0; i for(int j=0; j bddata[i][j] = false;

}

}

////// Inner class Message /////////

private class Message

{

public static final int MOVE_UP = 1;

public static final int MOVE_DOWN = 2;

public static final int MOVE_LEFT = 3;

public static final int MOVE_RIGHT = 4;

public static final int ROTATE_CLOCK = 5; //rotate clock-wise

public static final int ROTATE_ANTICLOCK = 6;//rotate anticlock-wise

public Message(int action)

{

this.action = action;

}

public int getAction()

{

return this.action;

}

private int action;

}

////// Inner class Queue ///////

//////////// fields of class Game ////////////////

private Board m_board = new Board(); //仅由消息处理器线程访问

private Block m_block = null; //当前存在的块

private MessageQueue m_msgQueue = new MessageQueue(); //由消息处理器和awt线程访问

private BlockDataPoolQueue m_blockDataPoolQueue = new BlockDataPoolQueue();

private int m_S = 0;

///// method run 主消息处理处理线程

public void run()

{

boolean bkdataPool[][][] ={

{{false,false,true,false,false},

{false,false,true,false,false},

{false,false,true,false,false},

{false,false,true,false,false},

{false,false,true,false,false}},

{{false,false,false,false,false},

{false,true,true,true,false},

{false,false,true,false,false},

{false,false,true,false,false},

{false,false,true,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,true,false,false},

{false,true,true,true,false},

{false,false,true,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,false,false,false},

{false,true,true,true,false},

{false,true,false,true,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,false,false,false},

{false,true,true,true,false},

{false,false,true,false,false},

{false,false,false,false,false}}};

repaintRequest();

while(true)

{

switch(m_S)

{

case 0:

try

{

Thread.currentThread().sleep(50);

}

catch (InterruptedException ex)

{

}

break;

case 1:

Block bk1 = new Block(m_blockDataPoolQueue.getNextBlockData(),0,(BDWIDTH-BKSIZE)/2);

if( ! isCollided(m_board,bk1)){

m_block = bk1;

m_S = 2;

}else

m_S = 3;

repaintRequest();

break;

case 2:

Message msg;

synchronized(m_msgQueue) //等待新的消息

{

while(m_msgQueue.empty()){

try{

m_msgQueue.wait();

}catch(InterruptedException e){

}

}

msg = (Message)m_msgQueue.dl();

}

Block bk2 = new Block(m_block);

bk2.doAction(msg.getAction());

if(! isCollided(m_board,bk2)){ //动作可以执行

m_block.doAction(msg.getAction());

m_S = 2;

repaintRequest();

}else if(msg.getAction()==Message.MOVE_DOWN){ //向下移动的动作不能执行

merge(m_board,m_block);

m_block = null;

packUpBoard(m_board);

m_S = 1;

repaintRequest();

}

break;

case 3:

try

{

Thread.currentThread().sleep(50);

}

catch (Exception ex)

{

}

break;

}

}

}

///// method isClllided /////

private boolean isCollided(final Block bk1,final Block bk2) //判断两方块是否重叠

{

for(int r1=0; r1 {

int r2 = r1+bk1.rpos-bk2.rpos;

if(r2>=0 && r2 {

for(int c1=0; c1 {

int c2 = c1+bk1.cpos-bk2.cpos;

if(c2>=0 && c2 if(bk1.bkdata[r1][c1] && bk2.bkdata[r2][c2])

return true;

}

}

}

return false;

}

private boolean isCollided(final Board board,final Block block) //判断某方块与某底板是否重叠

{

for(int i=0; i for(int j=0; j if(block.rpos+i>=0 && block.rpos+i=0 && block.cpos+j if(block.bkdata[i][j] && board.bddata[i+block.rpos][j+block.cpos])

return true;

}else if(block.bkdata[i][j])

return true;

}

}

return false;

}

private void merge(Board board,final Block block) //合并board <=== block

{

for(int i=0; i for(int j=0; j if(block.rpos+i>=0 && block.rpos+i<=BDHEIGHT-1 && block.cpos+j>=0 && block.cpos+j<=BDWIDTH-1)

board.bddata[block.rpos+i][block.cpos+j] |= block.bkdata[i][j];

}

private int packUpBoard(Board board) //消去满行

{

int linesDeleted = 0;

for(int i=BDHEIGHT-1; i>=0;){ //检测第i行

boolean full = true;

for(int j=0; j if(! board.bddata[i][j]){

full = false;

break;

}

}

if(full){ //第i行为满行

for(int k=i-1; k>=0; k--){

for(int c=0; c board.bddata[k+1][c] = board.bddata[k][c];

}

for(int c=0; c board.bddata[0][c] = false;

linesDeleted++;

}else

i--;

}

return linesDeleted;

}

//Constructor

final int X0 = 10, Y0 = 15;

final int CELLSIZE = 12;

public java.awt.Dimension getPreferredSize()

{

return new java.awt.Dimension(2*X0+CELLSIZE*BDWIDTH,2*Y0+CELLSIZE*BDHEIGHT);

}

public GameCanvas()

{

setBackground(java.awt.Color.black);

addKeyListener(new java.awt.event.KeyAdapter(){

public void keyPressed(java.awt.event.KeyEvent e)

{

switch(e.getKeyCode()){

case java.awt.event.KeyEvent.VK_LEFT:

postMessage(new Message(Message.MOVE_LEFT));

break;

case java.awt.event.KeyEvent.VK_RIGHT:

postMessage(new Message(Message.MOVE_RIGHT));

break;

case java.awt.event.KeyEvent.VK_DOWN:

postMessage(new Message(Message.MOVE_DOWN));

break;

case java.awt.event.KeyEvent.VK_UP:

postMessage(new Message(Message.ROTATE_CLOCK));

break;

case java.awt.event.KeyEvent.VK_ENTER:

postMessage(new Message(Message.ROTATE_ANTICLOCK));

break;

case java.awt.event.KeyEvent.VK_PAGE_UP:

postMessage(new Message(Message.MOVE_UP));

break;

case java.awt.event.KeyEvent.VK_SPACE:

if(m_S==0)

m_S = 1;

break;

case java.awt.event.KeyEvent.VK_F1:

if(m_S==3){

m_board.clear();

m_S = 0;

repaintRequest();

}

}

}

});

new Thread(){

public void run()

{

while(true){

try{

sleep(500);

}catch(InterruptedException e){

}

postMessage(new Message(Message.MOVE_DOWN));

}

}

}.start();

new Thread(this).start(); //消息处理线程

}

public void postMessage(Message msg)

{

if(m_S==1 || m_S==2){

synchronized(m_msgQueue){

m_msgQueue.en(msg);

m_msgQueue.notify();

}

}

}

public void repaintRequest()

{

repaint();

}

public void paint(java.awt.Graphics g)

{

//draw m_board

g.setColor(java.awt.Color.blue);

g.drawRect(X0,Y0,CELLSIZE*BDWIDTH-1,CELLSIZE*BDHEIGHT-1);

switch(m_S){

case 1:

case 2:

g.setColor(java.awt.Color.yellow);

break;

case 3:

g.setColor(java.awt.Color.lightGray);

break;

}

for(int i=0,y=Y0; i for(int j=0,x=X0; j if(m_board.bddata[i][j])

g.fillRect(x,y,CELLSIZE-1,CELLSIZE-1);

}

}

//draw next block show

g.setColor(java.awt.Color.lightGray);

boolean nextBlockData[][] = m_blockDataPoolQueue.peekNextBlockData();

for(int i=0,y=Y0; i for(int j=0,x=X0+(BDWIDTH-BKSIZE)*CELLSIZE; j if(nextBlockData[i][j])

g.drawRect(x+1,y+1,CELLSIZE-1,CELLSIZE-1);

}

}

//draw m_block

if(m_S==2){

g.setColor(java.awt.Color.red);

for(int i=0,y=Y0+m_block.rpos*CELLSIZE; i for(int j=0,x=X0+m_block.cpos*CELLSIZE; j if(m_block.bkdata[i][j])

g.fillRect(x,y,CELLSIZE-1,CELLSIZE-1);

}

}

}

g.setColor(java.awt.Color.red);

g.setFont(new java.awt.Font(g.getFont().getFontName(),g.getFont().getStyle(),16));

switch(m_S){

case 0:

g.drawString("按空格键开始游戏!",50,100);

break;

case 3:

g.drawString("游戏结束,按F1键重新开始!",20,100);

break;

}

}

private class BlockDataPoolQueue extends Queue

{

public BlockDataPoolQueue(){ this.currentBlockData = bkdataPool[ran.nextInt(bkdataPool.length)]; }

public boolean[][] peekNextBlockData()

{

return this.currentBlockData;

}

public boolean[][] getNextBlockData()

{

boolean[][] bkd = this.currentBlockData;

this.currentBlockData = bkdataPool[ran.nextInt(bkdataPool.length)];

return bkd;

}

private boolean[][] currentBlockData = null;

private java.util.Random ran = new java.util.Random();

private boolean bkdataPool[][][] ={

{{false,false,true,true,false},

{false,false,true,false,false},

{false,false,true,false,false},

{false,true,true,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,true,true,false,false},

{false,false,true,false,false},

{false,false,true,true,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,true,false,false},

{false,true,true,true,false},

{false,false,true,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,false,false,false},

{false,true,true,true,false},

{false,false,false,true,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,true,false,false,false},

{false,false,true,false,false},

{false,false,false,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,false,false,false},

{false,false,true,false,false},

{false,false,false,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,true,true,false,false},

{false,true,true,false,false},

{false,false,false,false,false},

{false,false,false,false,false}},

{{false,false,false,false,false},

{false,false,false,false,false},

{false,true,true,true,false},

{false,false,true,false,false},

{false,false,false,false,false}}};

}

private class Queue

{

private Node head;

private Node tail;

public Queue()

{

head = new Node();

tail = new Node();

head.prev = tail.next = null;

head.next = tail;

tail.prev = head;

}

public void en(Object item)

{

Node q = new Node();

q.data = item;

q.next = tail;

q.prev = tail.prev;

tail.prev.next = q;

tail.prev = q;

}

public Object dl()

{

if(! empty()){

Node p = head.next;

head.next.next.prev = head;

head.next = head.next.next;

return p.data;

}else

return null;

}

public Object peek()

{

if(! empty())

return head.next.data;

else

return null;

}

public boolean empty()

{

return (head.next==tail) || (tail.prev==head);

}

public void clear()

{

head.next = tail;

tail.prev = head;

}

public int elemNum()

{

int num = 0;

for(Node q=head.next; q!=tail; q=q.next)

num++;

return num;

}

private class Node

{

Object data;

Node prev;

Node next;

}

}

//inner class MessageQueue

private class MessageQueue

{

private Node head;

private Node tail;

public MessageQueue()

{

head = new Node();

tail = new Node();

head.prev = tail.next = null;

head.next = tail;

tail.prev = head;

}

public void en(Message msg)

{

Node p = new Node();

p.message = msg;

p.next = tail;

p.prev = tail.prev;

tail.prev.next = p;

tail.prev = p;

}

public Message dl()

{

if(! empty()){

Node p = head.next;

head.next.next.prev = head;

head.next = head.next.next;

return p.message;

}else

return null;

}

public Message peek() //应先使用empty来检查

{

if(! empty())

return head.next.message;

else

return null;

}

public boolean empty()

{

return (head.next==tail) || (tail.prev==head);

}

public void clear()

{

head.next = tail;

tail.prev = head;

}

private class Node

{

Message message;

Node prev;

Node next;

}

}

}

最主要的两个类是Board和Block

Board就是"底板",就是每个block落不下去时合并到的对象

Block就是每个"方块"

程序大体上是两个线程在运行,一个是awt-thread(系统线程),另一个是消息处理线程(运行在run())方法.

程序中设立了一个消息队列(MessageQueue m_msgQueue = new MessageQueue()).

awt-thread将player的输入动作(如向上动作(光标上键生成),向下动作(光标下键生成),旋转(Enter键生成))生成的动作封装成Message的对象,推入消息队列m_msgQueue中.

消息处理线程负责不断的从消息队列(m_msgQueue)中取得消息和处理消息,没有消息时就wait().

player的生存周期分为四个阶段(用有限状态自动机描述): 0(S_INIT)状态为初始状态,代表活动还未开始; 1(S_TO_GENERATE_BLOCK)代表要生成一个block了; 2(S_DROPPING)代表block处于下落状态; 3(S_DEAD)代表player已经"game over"了.

在S_TO_GENERATE_BLOCK时,尝试生成一个新的block,如果能生成的话(就是生成的block和"底板"不重叠),就赋值到m_block,代表一个新的block生成来,状态就转为下落状态(S_DROPPING),否则状态就转为S_DEAD.

在S_DROPPING状态时,对于每一个动作(Message对象的action),判断该动作能否执行,能执行就执行该动作.如果动作是MOVE_DOWN时如果不能执行就把该block合并到"底板"中,消去底板满行,状态转为S_TO_GENERATE_BLOCK.

我还有一个多人版的,本来不想公布出来的,但看到大家的学习兴趣这么好,就忍不住要公布出来.对初学者可能能学习一些多线程之间的同步与互斥的例子.

和传统的多人版的不同,这个多人版的俄罗斯方块游戏是所有人在一个"底板"中进行的(传统的是每个player是分开独立的的,大家比赛看是谁得分高),每个player都可以用自己的block推动别的player的block一起移动,players之间可以可以互相"捣乱",也可以互相配合(经常需要自己的block和别人的block合并在一起来动作).程序说明我就一并贴在这里吧:

interlace(player-p,action):

FOR action of player-p:

FOR ALL block of players i except player-p whick interlaced with block of player-p

interlace(player-i,action);

when all playerp-i is actable:

all block of player-i . perform action

使用递归的方法来处理.

目前网络部分还没有作完,所以只能在单机上多人玩.

先把单人版的源码看完多人版的就容易了.

程序太长了,在这里贴太麻烦,需要的留下email.

 

本文地址:http://www.45fan.com/a/question/72068.html
Tags: Java 俄罗斯 方块
编辑:路饭网
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部