L
liguowei
Unregistered / Unconfirmed
GUEST, unregistred user!
/*
多人版的改好了,源程序如下.
限于单机版键盘的限制,现在可以使用最多三个人.
F1键开始第一个player,操作键为:左、右、下光标键,上光标键顺时针旋转,回车键逆时针旋转
F2键开始第二个player,操作键为A、S、D、E和空格键
F3键开始第三个player,操作键为J、K、L、I
*/
public class Game extends java.awt.Frame
{
//Game()构造函数开始点
public Game()
{
setTitle("俄罗斯方块 - By Ghost Valley");
// 加载一个监听接口开始点
addWindowListener(
new java.awt.event.WindowAdapter()
{
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
public void windowClosed(java.awt.event.WindowEvent e)
{
System.exit(0);
}
}
);
// 加载一个监听接口结束点
GameServer gameServer = new GameServer(this);
setLayout(new java.awt.BorderLayout());
add(gameServer,"Center");
setResizable(false);
setLocation((java.awt.Toolkit.getDefaultToolkit().getScreenSize().width-gameServer.getPreferredSize().width)/2,(java.awt.Toolkit.getDefaultToolkit().getScreenSize().height-gameServer.getPreferredSize().height)/2);
pack();
show();
}// Game()构造函数结束点
public static void main(String args[]){ new Game();
}
}
////////////// class GameServer //////////////
class GameServer extends java.awt.Panel implements Runnable
{
////// Inner class Block////////
public static class Block
{
public static final int BKSIZE = 5;
public boolean bkdata[][] = new boolean[BKSIZE][BKSIZE];
public int rpos,cpos;
public Block(boolean bkdata1[][],int rpos,int cpos)
{
//this.bkdata = (boolean[][])bkdata1.clone();
for(int i=0;
i<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
this.bkdata[j] = bkdata1[j];
this.rpos = rpos;
this.cpos = cpos;
}
public Block(Block bk) //unused
{
//this.bkdata = (boolean[][])bk.bkdata.clone();
for(int i=0;
i<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
this.bkdata[j] = bk.bkdata[j];
this.rpos = bk.rpos;
this.cpos = bk.cpos;
}
public voiddo
Action(int action) //action∈{MOVE_UP,MOVE_DOWN,MOVE_LEFT,MOVE_RIGHT,ROTATE_CLOCKWISE,ROTATE_ANTICLOCKWISE}
{
switch(action)
{
//case Message.ACT_NULL: //deprecated,never carried out
// break;
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<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
bkdata1[j] = this.bkdata[j];
//rotate
for(int x=0;
x<BKSIZE;
x++)
for(int y=0;
y<BKSIZE;
y++)
this.bkdata[y][-x+2*y0] = bkdata1[x][y];
break;
}
case Message.ROTATE_ANTICLOCKWISE:
{
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<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
bkdata1[j] = this.bkdata[j];
//rotate
for(int x=0;
x<BKSIZE;
x++)
for(int y=0;
y<BKSIZE;
y++)
this.bkdata[-y+2*x0][x] = bkdata1[x][y];
break;
}
}
}
public void undoAction(int action)
{
switch(action){
//case Message.ACT_NULL:
// break;
case Message.MOVE_DOWN:
this.doAction(Message.MOVE_UP);
break;
case Message.MOVE_LEFT:
this.doAction(Message.MOVE_RIGHT);
break;
case Message.MOVE_RIGHT:
this.doAction(Message.MOVE_LEFT);
break;
case Message.MOVE_UP:
this.doAction(Message.MOVE_DOWN);
break;
case Message.ROTATE_ANTICLOCKWISE:
this.doAction(Message.ROTATE_CLOCK);
break;
case Message.ROTATE_CLOCK:
this.doAction(Message.ROTATE_ANTICLOCKWISE);
break;
}
}
}
public static class Board
{
public boolean bddata[][] = new boolean[BDHEIGHT][BDWIDTH];
public Board()
{
clear();
}
public void clear()
{
for(int i=0;
i<BDHEIGHT;
i++)
for(int j=0;
j<BDWIDTH;
j++)
bddata[j] = false;
}
}
////// Inner class Message /////////
public static class Message
{
public static final int ACT_NULL = 0;
//means "this block shoulddo
something(notify it only)
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_ANTICLOCKWISE = 6;//rotate anticlock-wise
public Message(String playerName,int action)
{
this.playerName = playerName;
this.action = action;
}
public String getPlayerName()
{
return this.playerName;
}
public int getAction()
{
return this.action;
}
private String playerName;
private int action;
}
/////// Inner class Player ///////
public static class Player
{
public Player(String playerName,int state0,java.awt.Color playerColor,int delayTime)
{
this.playerName = playerName;
this.playerState = state0;
this.playerColor = playerColor;
this.delayTime = delayTime;
}
public String getPlayerName()
{
return this.playerName;
}
public java.awt.Color getPlayerColor()
{
return this.playerColor;
}
public boolean equals(Object obj)
{
if(obj instanceof Player)
if(this.getPlayerName().equals(((Player)obj).getPlayerName()))
return true;
return false;
}
public int playerState;
public Block block = null;
private String playerName;
private java.awt.Color playerColor;
private int delayTime;
public static final int S_INIT = 0;
public static final int S_TO_GENERATE_BLOCK = 1;
public static final int S_DROPPING = 2;
public static final int S_DEAD = 3;
}
/////// Inner class PlayersVector ///////
private class PlayersVector
{
private Player players[];
private int currentLen = 0;
public PlayersVector(int maxplayers)
{
this.players = new Player[maxplayers];
}
public PlayersVector()
{
this(256);
}
public boolean contains(Player p) //使用Player.equals()方法进行比较
{
for(int i=0;
i<this.currentLen;
i++)
if(this.players.equals(p))
return true;
return false;
}
public Player forPlayerName(String playerName) //if a player named playerName is contained,then
return it,otherwise return null
{
for(int i=0;
i<this.currentLen;
i++)
if(this.players.getPlayerName().equals(playerName))
return this.players;
return null;
}
public void addPlayer(Player player)
{
//_ASSERT(this.currentLen<this.players.length-1
this.players[this.currentLen++] = player;
}
public boolean removePlayer(Player player) //使用Player.equals()方法进行比较
{
for(int i=0;
i<this.currentLen;
i++){
if(this.players.equals(player)){
for(int j=i+1;
j<this.currentLen;
j++)
this.players[j-1] = this.players[j];
this.currentLen--;
return true;
}
}
return false;
}
public Player[] allPlayers()
{
Player ps[] = new Player[this.currentLen];
for(int i=0;
i<this.currentLen;
i++)
ps = this.players;
return ps;
}
public boolean empty()
{
return this.currentLen==0;
}
public int playersNumber()
{
return this.currentLen;
}
public void clear()
{
this.currentLen = 0;
}
}
/////// Inner class MessageQueue //////
private class MessageQueue extends Queue
{
public void enMessage(Message msg)
{
super.en(msg);
}
public Message dlMessage()
{
return empty() ? null : (Message)super.dl();
}
public Message peekMessage()
{
return empty()? null : (Message)super.peek();
}
}
//Inner class BlockDataPoolQueue
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 BoardCanvas extends java.awt.Canvas
{
private String currentPlayer = "Tom";
public BoardCanvas()
{
setBackground(java.awt.Color.black);
addKeyListener(new java.awt.event.KeyAdapter(){
public void keyPressed(java.awt.event.KeyEvent evt)
{
switch(evt.getKeyCode()){
case java.awt.event.KeyEvent.VK_LEFT:
postMessage(new Message("Tom",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_RIGHT:
postMessage(new Message("Tom",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_UP:
postMessage(new Message("Tom",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_DOWN:
postMessage(new Message("Tom",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_ENTER:
postMessage(new Message("Tom",Message.ROTATE_ANTICLOCKWISE));
break;
case java.awt.event.KeyEvent.VK_F1:
playerStartGame("Tom");
break;
case java.awt.event.KeyEvent.VK_A:
postMessage(new Message("Mike",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_D:
postMessage(new Message("Mike",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_S:
postMessage(new Message("Mike",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_W:
postMessage(new Message("Mike",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_SPACE:
postMessage(new Message("Mike",Message.ROTATE_ANTICLOCKWISE));
break;
case java.awt.event.KeyEvent.VK_F2:
playerStartGame("Mike");
break;
case java.awt.event.KeyEvent.VK_J:
postMessage(new Message("Jerry",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_L:
postMessage(new Message("Jerry",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_K:
postMessage(new Message("Jerry",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_I:
postMessage(new Message("Jerry",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_F3:
playerStartGame("Jerry");
break;
case java.awt.event.KeyEvent.VK_PAUSE:
gamePaused = !gamePaused;
}
}
});
}
public java.awt.Dimension getPreferredSize()
{
return new java.awt.Dimension(2*X0+CELLSIZE*BDWIDTH,2*Y0+CELLSIZE*BDHEIGHT);
}
public void repaintBoardRequest()
{
this.repaint();
}
public void update(java.awt.Graphics g)
{
paint(g);
}
public void paint(java.awt.Graphics g0)
{
//draw m_board
java.awt.Image imgOff = createImage(this.getSize().width,this.getSize().height);
if(imgOff != null){
java.awt.Graphics g = imgOff.getGraphics();
g.setColor(java.awt.Color.lightGray);
g.drawRect(X0,Y0,CELLSIZE*BDWIDTH,CELLSIZE*BDHEIGHT);
for(int i=0,y=Y0;
i<BDHEIGHT;
i++,y+=CELLSIZE){
for(int j=0,x=X0;
j<BDWIDTH;
j++,x+=CELLSIZE){
if(m_board.bddata[j])
g.fill3DRect(x,y,CELLSIZE-1,CELLSIZE-1,true);
}
}
synchronized(m_players)
{
//draw all m_players.block
Player ps[] = m_players.allPlayers();
for(int k=0;
k<ps.length;
k++){
if(ps[k].playerState == Player.S_DROPPING){
g.setColor(ps[k].getPlayerColor());
for(int i=0,y=Y0+ps[k].block.rpos*CELLSIZE;
i<Block.BKSIZE;
i++,y+=CELLSIZE){
for(int j=0,x=X0+ps[k].block.cpos*CELLSIZE;
j<Block.BKSIZE;
j++,x+=CELLSIZE){
if(ps[k].block.bkdata[j])
g.fill3DRect(x,y,CELLSIZE-1,CELLSIZE-1,true);
}
}
}
}
}
}
g0.drawImage(imgOff,0,0,this);
}
}
private class ControlPanel extends java.awt.Panel
{
private class ShowNextBlockCanvas extends java.awt.Canvas
{
public ShowNextBlockCanvas()
{
setBackground(java.awt.Color.blue);
}
public java.awt.Dimension getPreferredSize()
{
return new java.awt.Dimension(X0*2+CELLSIZE*Block.BKSIZE,Y0*2+CELLSIZE*Block.BKSIZE);
}
public void paint(java.awt.Graphics g)
{
g.setColor(java.awt.Color.lightGray);
g.drawString("NEXT",X0,Y0);
g.drawRect(X0,Y0,Block.BKSIZE*CELLSIZE,Block.BKSIZE*CELLSIZE);
synchronized(m_blockDataPoolQueue){
boolean bkd[][] = m_blockDataPoolQueue.peekNextBlockData();
g.setColor(java.awt.Color.lightGray);
for(int i=0;
i<Block.BKSIZE;
i++)
for(int j=0;
j<Block.BKSIZE;
j++)
if(bkd[j])
g.fillRect(X0+i*CELLSIZE,Y0+j*CELLSIZE,CELLSIZE-1,CELLSIZE-1);
}
}
}
private class PlayersControlPanel extends java.awt.Panel
{
private java.awt.Button m_buttonAddNewPlayer = new java.awt.Button("Add New Player");
private class DialogAddNewPlayer extends java.awt.Dialog
{
private class MessageDialog extends java.awt.Dialog
{
private java.awt.Label labelMsg = new java.awt.Label();
private java.awt.Button buttonOk = new java.awt.Button("Close");
public MessageDialog(java.awt.Dialog owner,String title,String msg)
{
super(owner,title,true);
this.labelMsg.setText(msg);
this.addWindowListener(new java.awt.event.WindowAdapter(){
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
});
this.setLayout(new java.awt.BorderLayout(10,10));
this.add(labelMsg,"Center");
buttonOk.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
dispose();
}
});
java.awt.Panel panel1 = new java.awt.Panel(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
panel1.add(buttonOk);
this.add(panel1,"South");
this.pack();
this.setLocation(getOwner().getLocation().x+(getOwner().getSize().width-getSize().width)/2,getOwner().getLocation().y+(getOwner().getSize().height-getSize().height)/2);
}
}
private java.awt.Label labelName = new java.awt.Label("Name");
private java.awt.TextField textFieldName = new java.awt.TextField(12);
private java.awt.Label labelColor = new java.awt.Label("Color");
private java.awt.Choice choiceColor = new java.awt.Choice();
private java.awt.Button buttonOk = new java.awt.Button("Ok");
private java.awt.Button buttonCancel = new java.awt.Button("Cancel");
public DialogAddNewPlayer(java.awt.Frame frame)
{
super(frame,"Add a new player",true);
this.addWindowListener(new java.awt.event.WindowAdapter(){
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
});
this.setLayout(new java.awt.BorderLayout(5,30));
java.awt.Panel panel1 = new java.awt.Panel(new java.awt.GridLayout(2,2,5,10));
panel1.add(labelName);
panel1.add(textFieldName);
panel1.add(labelColor);
choiceColor.addItem("Red");
choiceColor.addItem("Green");
choiceColor.addItem("Blue");
choiceColor.addItem("Yellow");
panel1.add(choiceColor);
this.add(panel1,"Center");
java.awt.Panel panel2 = new java.awt.Panel(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER,5,10));
panel2.add(buttonOk);
panel2.add(buttonCancel);
this.add(panel2,"South");
this.pack();
this.setLocation(frame.getLocation().x+(frame.getSize().width-this.getSize().width)/2,frame.getLocation().y+(frame.getSize().height-this.getSize().height)/2);
buttonCancel.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
dispose();
}
});
buttonOk.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
if(textFieldName.getText().equals(""))
new MessageDialog(DialogAddNewPlayer.this,"Information","名字不能为空!").show();
else
{
java.awt.Color playerColor;
switch(choiceColor.getSelectedIndex()){
case 0: playerColor = java.awt.Color.red;
break;
case 1: playerColor = java.awt.Color.green;
break;
case 2: playerColor = java.awt.Color.blue;
break;
case 3: playerColor = java.awt.Color.yellow;
break;
default: playerColor = java.awt.Color.white;
}
boolean succ;
synchronized(m_players){
succ = addNewPlayer(textFieldName.getText(),Player.S_INIT,playerColor);
}
if(! succ){
new MessageDialog(DialogAddNewPlayer.this,"Information","该名字已经存在,请换一个名字重试!").show();
textFieldName.setText("");
}else
dispose();
}
}
});
}
}
public PlayersControlPanel()
{
setBackground(java.awt.Color.gray);
this.setLayout(new java.awt.FlowLayout());
this.m_buttonAddNewPlayer.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
DialogAddNewPlayer dialog = new DialogAddNewPlayer(gameFrame);
dialog.show();
}
});
this.add(m_buttonAddNewPlayer);
}
}
private ShowNextBlockCanvas m_showNextBlockCanvas = new ShowNextBlockCanvas();
private PlayersControlPanel m_playersControlPanel = new PlayersControlPanel();
public ControlPanel()
{
setBackground(java.awt.Color.gray);
this.setLayout(new java.awt.BorderLayout());
this.add(m_showNextBlockCanvas,"North");
//
//TODO: this.add(m_playersControlPanel,"Center");
}
public void repaintNextBlockRequest()
{
this.m_showNextBlockCanvas.repaint();
}
}
private final int X0 = 10, Y0 = 15;
private final int CELLSIZE = 12;
private BoardCanvas m_boardCanvas = new BoardCanvas();
private ControlPanel m_controlPanel = new ControlPanel();
private java.awt.Frame gameFrame;
//constructor GamePanel
public GameServer(java.awt.Frame gameFrame)
{
this.gameFrame = gameFrame;
this.setLayout(new java.awt.BorderLayout());
this.add(m_boardCanvas,"Center");
//
this.add(m_controlPanel,"East");
m_players.addPlayer(new Player("Tom",Player.S_INIT,java.awt.Color.red,300));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Tom",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(400);
}catch (InterruptedException ex){
}
}
}
}.start();
m_players.addPlayer(new Player("Mike",Player.S_INIT,java.awt.Color.green,550));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Mike",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(700);
}catch (InterruptedException ex){
}
}
}
}.start();
m_players.addPlayer(new Player("Jerry",Player.S_INIT,java.awt.Color.blue,600));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Jerry",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(400);
}catch (InterruptedException ex){
}
}
}
}.start();
new Thread(this).start();
//消息处理线程
m_boardCanvas.requestFocus();
}
/////////main message-handler method
public void run()
{
java.util.Random ran = new java.util.Random();
while(true){
Message msg;
synchronized(m_msgQueue){
while(m_msgQueue.empty()){
try{
m_msgQueue.wait();
}catch (InterruptedException ex){
}
}
msg = m_msgQueue.dlMessage();
//synchronized
}
//处理消息
synchronized(m_players){
Player player = m_players.forPlayerName(msg.getPlayerName());
if(player != null){ //该消息所指的player还存在于players中
switch(player.playerState){
case Player.S_INIT:
//player.state = Player.S_TO_GENERATE_BLOCK;
//postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
break;
case Player.S_TO_GENERATE_BLOCK:
synchronized(m_blockDataPoolQueue){
for(int times=0;
times<12;
times++){
player.block = new Block(m_blockDataPoolQueue.getNextBlockData(),0,ran.nextInt(BDWIDTH-Block.BKSIZE));
repaintNextBlockRequest();
if(! isCollided(m_board,player.block) &&
!isCollidedWithAnyOtherPlayer(player))
break;
else
System.out.println("retry generate new block");
}
}
if( isCollided(m_board,player.block) || isCollidedWithAnyOtherPlayer(player)){
player.block = null;//undo generate block
player.playerState = Player.S_DEAD;
postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_TO_GENERATE_BLOCK,Player.S_DEAD);
}else
{
player.playerState = Player.S_DROPPING;
postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_TO_GENERATE_BLOCK,Player.S_DROPPING);
}
repaintBoardRequest();
break;
case Player.S_DROPPING:
if(msg.getAction() != Message.ACT_NULL){
PlayersVector playersAffected = new PlayersVector();
playersAffected.addPlayer(player);
PlayersVector playersUnableToDo = new PlayersVector();
if(playerDoAction(player,msg.getAction(),playersAffected,playersUnableToDo)){
onAction(playersAffected,msg.getAction());
repaintBoardRequest();
}else
{
Player ps1[] = playersAffected.allPlayers();
for(int i=0;
i<ps1.length;
i++)
ps1.block.undoAction(msg.getAction());
//undo all players affected
if(msg.getAction()==Message.MOVE_DOWN){
Player ps2[] = playersUnableToDo.allPlayers();
for(int i=0;
i<ps2.length;
i++){
merge(m_board,ps2.block);
ps2.block = null;
ps2.playerState = Player.S_TO_GENERATE_BLOCK;
postMessage(new Message(ps2.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_DROPPING,Player.S_TO_GENERATE_BLOCK);
}
int n = packUpBoard(m_board);
repaintBoardRequest();
}
}
}
break;
case Player.S_DEAD:
//System.out.println("Player "+player.getPlayerName()+" Dead!");
//m_players.remove(player);
break;
}
}
}
}
}
//_ASSERT(player.state==Player.S_DROPPING)
private boolean isCollidedWithAnyOtherPlayer(Player player0) //player is collided with any player in m_players-{player}
{
Player ps[] = m_players.allPlayers();
for(int i=0;
i<ps.length;
i++){
if(ps != player0 &&
ps.playerState==Player.S_DROPPING){
if(isCollided(player0.block,ps.block))
return true;
}
}
return false;
}
//如果player0可以执行action,则player及其相affected的players(在m_players中)执行action,
//已经执行action的players(包括player0)放在playerAffected中,并返回true;
//否则,阻塞player0的其他players(包括player0)放在playersAffected中,并返回false
private boolean playerDoAction(Player player0,int action,PlayersVector playersAffected,PlayersVector playersUnableToDo)
{
player0.block.doAction(action);
boolean canDo = true;
if(isCollided(m_board,player0.block)) //叶子
canDo = false;
Player ps[] = m_players.allPlayers();
for(int i=0;
i<ps.length;
i++)
if(! playersAffected.contains(ps))
if(ps.playerState==Player.S_DROPPING)
if(isCollided(player0.block,ps.block)){
if((action==Message.MOVE_UP)||(action==Message.MOVE_DOWN)||(action==Message.MOVE_LEFT)||(action==Message.MOVE_RIGHT)){
playersAffected.addPlayer(ps);
if(! playerDoAction(ps,action,playersAffected,playersUnableToDo))
canDo = false;
}else
canDo = false;
}
if(!canDo)
playersUnableToDo.addPlayer(player0);
return canDo;
}
/////// method isClllided
private boolean isCollided(Block bk1,Block bk2) //判断两方块是否重叠
{
if(bk1.rpos-bk2.rpos>=0 &&
bk1.rpos-bk2.rpos<Block.BKSIZE){
for(int r1=0;
r1<Block.BKSIZE-(bk1.rpos-bk2.rpos);
r1++){
int r2 = r1+bk1.rpos-bk2.rpos;
if(bk1.cpos-bk2.cpos>=0 &&
bk1.cpos-bk2.cpos<Block.BKSIZE){
for(int c1=0;
c1<Block.BKSIZE-(bk1.cpos-bk2.cpos);
c1++){
int c2=c1+bk1.cpos-bk2.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}else
if(bk2.cpos-bk1.cpos>=0 &&
bk2.cpos-bk1.cpos<Block.BKSIZE){
for(int c2=0;
c2<Block.BKSIZE-(bk2.cpos-bk1.cpos);
c2++){
int c1=c2+bk2.cpos-bk1.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}
}
}else
if(bk2.rpos-bk1.rpos>=0 &&
bk2.rpos-bk1.rpos<Block.BKSIZE){
for(int r2=0;
r2<Block.BKSIZE-(bk2.rpos-bk1.rpos);
r2++){
int r1 = r2+bk2.rpos-bk1.rpos;
if(bk1.cpos-bk2.cpos>=0 &&
bk1.cpos-bk2.cpos<Block.BKSIZE){
for(int c1=0;
c1<Block.BKSIZE-(bk1.cpos-bk2.cpos);
c1++){
int c2=c1+bk1.cpos-bk2.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}else
if(bk2.cpos-bk1.cpos>=0 &&
bk2.cpos-bk1.cpos<Block.BKSIZE){
for(int c2=0;
c2<Block.BKSIZE-(bk2.cpos-bk1.cpos);
c2++){
int c1=c2+bk2.cpos-bk1.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}
}
}
return false;
}
/////// method isCollided
private boolean isCollided(Board board,Block block) //判断某方块与某底板是否重叠
{
for(int i=0;
i<Block.BKSIZE;
i++){
for(int j=0;
j<Block.BKSIZE;
j++){
if(block.rpos+i>=0 &&
block.rpos+i<BDHEIGHT &&
block.cpos+j>=0 &&
block.cpos+j<BDWIDTH){
if(block.bkdata[j] &&
board.bddata[i+block.rpos][j+block.cpos])
return true;
}else
if(block.bkdata[j])
return true;
}
}
return false;
}
/////// method merge
private void merge(Board board,Block block) //合并board <=== block
{
for(int i=0;
i<Block.BKSIZE;
i++)
for(int j=0;
j<Block.BKSIZE;
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[j];
}
/////// method packUpBoard
private int packUpBoard(Board board) //消去满行
{
int linesDeleted = 0;
for(int i=BDHEIGHT-1;
i>=0{ //检测第i行
boolean full = true;
for(int j=0;
j<BDWIDTH;
j++){
if(! board.bddata[j]){
full = false;
break;
}
}
if(full){ //第i行为满行
for(int k=i-1;
k>=0;
k--){
for(int c=0;
c<BDWIDTH;
c++)
board.bddata[k+1][c] = board.bddata[k][c];
}
for(int c=0;
c<BDWIDTH;
c++)
board.bddata[0][c] = false;
linesDeleted++;
}else
i--;
}
return linesDeleted;
}
/////// method playerStartGame,change the state of player
public boolean playerStartGame(final String playerName)
{
synchronized(m_players){
Player p = m_players.forPlayerName(playerName);
if(p != null){
if((p.playerState==Player.S_INIT) || (p.playerState==Player.S_DEAD)){
p.playerState = Player.S_TO_GENERATE_BLOCK;
postMessage(new Message(playerName,Message.ACT_NULL));
//onPlayerStateChanged();
return true;
}
}
return false;
}
}
public boolean addNewPlayer(String playerName,int state0,java.awt.Color playerColor)
{
if(m_players.forPlayerName(playerName)== null){ //no same name player existed!
m_players.addPlayer(new Player(playerName,state0,playerColor,900));
return true;
}else
return false;
}
/////// method postMessage
private boolean gamePaused = false;
public void postMessage(Message msg)
{
if(! gamePaused){
synchronized(m_msgQueue){
m_msgQueue.enMessage(msg);
m_msgQueue.notify();
}
}
}
///////mehtod repaintRequest
public void repaintBoardRequest()
{
this.m_boardCanvas.repaintBoardRequest();
}
public void repaintNextBlockRequest()
{
this.m_controlPanel.repaintNextBlockRequest();
}
//callback method
public void onPlayerStateChanged(String playerName,int stateOld,int stateNow)
{
}
public void onAction(PlayersVector psv,int action)
{
/*
System.out.println("On Action: "+action+" of players:");
Player ps[] = psv.allPlayers();
for(int i=0;
i<ps.length;
i++)
System.out.println(" "+ps.getPlayerName());
*/
}
///////// Fields of class GameCanvas //////////
private Board m_board = new Board();
//仅由消息处理器线程访问
private PlayersVector m_players = new PlayersVector();
private MessageQueue m_msgQueue = new MessageQueue();
//由消息处理器和awt线程访问
private BlockDataPoolQueue m_blockDataPoolQueue = new BlockDataPoolQueue();
public static final int BDWIDTH = 20;
public static final int BDHEIGHT = 30;
}
class Queue extends Object
{
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() //应先使用empty来检查
{
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;
}
}
class List_ChainImp //数据结构-链表,指针链表实现
{
protected Node head = new Node();
public List_ChainImp()
{
head.prev = head.next =null;
}
public boolean contains(Object item) //使用Object.equals()方法进行比较
{
for(Node q=head.next;
q!=null;
q=q.next)
if(q.equals(item))
return true;
return false;
}
public void add(Object item)
{
Node q = new Node();
q.objdata = item;
q.next = head.next;
q.prev = head;
if(head.next != null)
head.next.prev = q;
head.next = q;
}
public boolean remove(Object item) //使用Object.equals()进行比较
{
for(Node q=head.next;
q!=null;
q=q.next){
if(q.objdata.equals(item)){
q.prev.next = q.next;
if(q.next != null)
q.next.prev = q.prev;
return true;
}
}
return false;
}
public Object[] allElements()
{
Object objs[] = new Object[elementsNumber()];
Node q = head.next;
for(int i=0;
i<objs.length;
i++,q=q.next)
objs = q.objdata;
return objs;
}
public boolean empty()
{
return head.next==null;
}
public int elementsNumber()
{
int elemNum = 0;
Node q = head.next;
while(q != null){
elemNum++;
q = q.next;
}
return elemNum;
}
public void clear()
{
head.next = null;
}
protected class Node
{
Object objdata;
Node prev;
Node next;
}
}
class List_ArrayImp //数据结构-链表,数组实现
{
protected Object datas[];
protected int currentLen = 0;
public List_ArrayImp(int maxnum)
{
this.datas = new Object[maxnum];
}
public boolean contains(Object obj)
{
for(int i=0;
i<this.currentLen;
i++)
if(this.datas.equals(obj))
return true;
return false;
}
public void add(Object obj)
{
if(this.currentLen<this.datas.length-1)
this.datas[this.currentLen++] = obj;
else
throw new RuntimeException("List elements excced space!");
}
public boolean remove(Object obj)
{
for(int i=0;
i<this.currentLen;
i++){
if(this.datas.equals(obj)){
for(int j=i+1;
j<this.currentLen;
j++)
this.datas[j-1] = this.datas[j];
this.currentLen--;
return true;
}
}
return false;
}
public Object[] allElements()
{
Object objs[] = new Object[this.currentLen];
for(int i=0;
i<this.currentLen;
i++)
objs = this.datas;
return objs;
}
public boolean empty()
{
return this.currentLen==0;
}
public int elementsNumber()
{
return this.currentLen;
}
public void clear()
{
this.currentLen = 0;
}
}
多人版的改好了,源程序如下.
限于单机版键盘的限制,现在可以使用最多三个人.
F1键开始第一个player,操作键为:左、右、下光标键,上光标键顺时针旋转,回车键逆时针旋转
F2键开始第二个player,操作键为A、S、D、E和空格键
F3键开始第三个player,操作键为J、K、L、I
*/
public class Game extends java.awt.Frame
{
//Game()构造函数开始点
public Game()
{
setTitle("俄罗斯方块 - By Ghost Valley");
// 加载一个监听接口开始点
addWindowListener(
new java.awt.event.WindowAdapter()
{
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
public void windowClosed(java.awt.event.WindowEvent e)
{
System.exit(0);
}
}
);
// 加载一个监听接口结束点
GameServer gameServer = new GameServer(this);
setLayout(new java.awt.BorderLayout());
add(gameServer,"Center");
setResizable(false);
setLocation((java.awt.Toolkit.getDefaultToolkit().getScreenSize().width-gameServer.getPreferredSize().width)/2,(java.awt.Toolkit.getDefaultToolkit().getScreenSize().height-gameServer.getPreferredSize().height)/2);
pack();
show();
}// Game()构造函数结束点
public static void main(String args[]){ new Game();
}
}
////////////// class GameServer //////////////
class GameServer extends java.awt.Panel implements Runnable
{
////// Inner class Block////////
public static class Block
{
public static final int BKSIZE = 5;
public boolean bkdata[][] = new boolean[BKSIZE][BKSIZE];
public int rpos,cpos;
public Block(boolean bkdata1[][],int rpos,int cpos)
{
//this.bkdata = (boolean[][])bkdata1.clone();
for(int i=0;
i<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
this.bkdata[j] = bkdata1[j];
this.rpos = rpos;
this.cpos = cpos;
}
public Block(Block bk) //unused
{
//this.bkdata = (boolean[][])bk.bkdata.clone();
for(int i=0;
i<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
this.bkdata[j] = bk.bkdata[j];
this.rpos = bk.rpos;
this.cpos = bk.cpos;
}
public voiddo
Action(int action) //action∈{MOVE_UP,MOVE_DOWN,MOVE_LEFT,MOVE_RIGHT,ROTATE_CLOCKWISE,ROTATE_ANTICLOCKWISE}
{
switch(action)
{
//case Message.ACT_NULL: //deprecated,never carried out
// break;
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<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
bkdata1[j] = this.bkdata[j];
//rotate
for(int x=0;
x<BKSIZE;
x++)
for(int y=0;
y<BKSIZE;
y++)
this.bkdata[y][-x+2*y0] = bkdata1[x][y];
break;
}
case Message.ROTATE_ANTICLOCKWISE:
{
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<BKSIZE;
i++)
for(int j=0;
j<BKSIZE;
j++)
bkdata1[j] = this.bkdata[j];
//rotate
for(int x=0;
x<BKSIZE;
x++)
for(int y=0;
y<BKSIZE;
y++)
this.bkdata[-y+2*x0][x] = bkdata1[x][y];
break;
}
}
}
public void undoAction(int action)
{
switch(action){
//case Message.ACT_NULL:
// break;
case Message.MOVE_DOWN:
this.doAction(Message.MOVE_UP);
break;
case Message.MOVE_LEFT:
this.doAction(Message.MOVE_RIGHT);
break;
case Message.MOVE_RIGHT:
this.doAction(Message.MOVE_LEFT);
break;
case Message.MOVE_UP:
this.doAction(Message.MOVE_DOWN);
break;
case Message.ROTATE_ANTICLOCKWISE:
this.doAction(Message.ROTATE_CLOCK);
break;
case Message.ROTATE_CLOCK:
this.doAction(Message.ROTATE_ANTICLOCKWISE);
break;
}
}
}
public static class Board
{
public boolean bddata[][] = new boolean[BDHEIGHT][BDWIDTH];
public Board()
{
clear();
}
public void clear()
{
for(int i=0;
i<BDHEIGHT;
i++)
for(int j=0;
j<BDWIDTH;
j++)
bddata[j] = false;
}
}
////// Inner class Message /////////
public static class Message
{
public static final int ACT_NULL = 0;
//means "this block shoulddo
something(notify it only)
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_ANTICLOCKWISE = 6;//rotate anticlock-wise
public Message(String playerName,int action)
{
this.playerName = playerName;
this.action = action;
}
public String getPlayerName()
{
return this.playerName;
}
public int getAction()
{
return this.action;
}
private String playerName;
private int action;
}
/////// Inner class Player ///////
public static class Player
{
public Player(String playerName,int state0,java.awt.Color playerColor,int delayTime)
{
this.playerName = playerName;
this.playerState = state0;
this.playerColor = playerColor;
this.delayTime = delayTime;
}
public String getPlayerName()
{
return this.playerName;
}
public java.awt.Color getPlayerColor()
{
return this.playerColor;
}
public boolean equals(Object obj)
{
if(obj instanceof Player)
if(this.getPlayerName().equals(((Player)obj).getPlayerName()))
return true;
return false;
}
public int playerState;
public Block block = null;
private String playerName;
private java.awt.Color playerColor;
private int delayTime;
public static final int S_INIT = 0;
public static final int S_TO_GENERATE_BLOCK = 1;
public static final int S_DROPPING = 2;
public static final int S_DEAD = 3;
}
/////// Inner class PlayersVector ///////
private class PlayersVector
{
private Player players[];
private int currentLen = 0;
public PlayersVector(int maxplayers)
{
this.players = new Player[maxplayers];
}
public PlayersVector()
{
this(256);
}
public boolean contains(Player p) //使用Player.equals()方法进行比较
{
for(int i=0;
i<this.currentLen;
i++)
if(this.players.equals(p))
return true;
return false;
}
public Player forPlayerName(String playerName) //if a player named playerName is contained,then
return it,otherwise return null
{
for(int i=0;
i<this.currentLen;
i++)
if(this.players.getPlayerName().equals(playerName))
return this.players;
return null;
}
public void addPlayer(Player player)
{
//_ASSERT(this.currentLen<this.players.length-1
this.players[this.currentLen++] = player;
}
public boolean removePlayer(Player player) //使用Player.equals()方法进行比较
{
for(int i=0;
i<this.currentLen;
i++){
if(this.players.equals(player)){
for(int j=i+1;
j<this.currentLen;
j++)
this.players[j-1] = this.players[j];
this.currentLen--;
return true;
}
}
return false;
}
public Player[] allPlayers()
{
Player ps[] = new Player[this.currentLen];
for(int i=0;
i<this.currentLen;
i++)
ps = this.players;
return ps;
}
public boolean empty()
{
return this.currentLen==0;
}
public int playersNumber()
{
return this.currentLen;
}
public void clear()
{
this.currentLen = 0;
}
}
/////// Inner class MessageQueue //////
private class MessageQueue extends Queue
{
public void enMessage(Message msg)
{
super.en(msg);
}
public Message dlMessage()
{
return empty() ? null : (Message)super.dl();
}
public Message peekMessage()
{
return empty()? null : (Message)super.peek();
}
}
//Inner class BlockDataPoolQueue
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 BoardCanvas extends java.awt.Canvas
{
private String currentPlayer = "Tom";
public BoardCanvas()
{
setBackground(java.awt.Color.black);
addKeyListener(new java.awt.event.KeyAdapter(){
public void keyPressed(java.awt.event.KeyEvent evt)
{
switch(evt.getKeyCode()){
case java.awt.event.KeyEvent.VK_LEFT:
postMessage(new Message("Tom",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_RIGHT:
postMessage(new Message("Tom",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_UP:
postMessage(new Message("Tom",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_DOWN:
postMessage(new Message("Tom",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_ENTER:
postMessage(new Message("Tom",Message.ROTATE_ANTICLOCKWISE));
break;
case java.awt.event.KeyEvent.VK_F1:
playerStartGame("Tom");
break;
case java.awt.event.KeyEvent.VK_A:
postMessage(new Message("Mike",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_D:
postMessage(new Message("Mike",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_S:
postMessage(new Message("Mike",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_W:
postMessage(new Message("Mike",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_SPACE:
postMessage(new Message("Mike",Message.ROTATE_ANTICLOCKWISE));
break;
case java.awt.event.KeyEvent.VK_F2:
playerStartGame("Mike");
break;
case java.awt.event.KeyEvent.VK_J:
postMessage(new Message("Jerry",Message.MOVE_LEFT));
break;
case java.awt.event.KeyEvent.VK_L:
postMessage(new Message("Jerry",Message.MOVE_RIGHT));
break;
case java.awt.event.KeyEvent.VK_K:
postMessage(new Message("Jerry",Message.MOVE_DOWN));
break;
case java.awt.event.KeyEvent.VK_I:
postMessage(new Message("Jerry",Message.ROTATE_CLOCK));
break;
case java.awt.event.KeyEvent.VK_F3:
playerStartGame("Jerry");
break;
case java.awt.event.KeyEvent.VK_PAUSE:
gamePaused = !gamePaused;
}
}
});
}
public java.awt.Dimension getPreferredSize()
{
return new java.awt.Dimension(2*X0+CELLSIZE*BDWIDTH,2*Y0+CELLSIZE*BDHEIGHT);
}
public void repaintBoardRequest()
{
this.repaint();
}
public void update(java.awt.Graphics g)
{
paint(g);
}
public void paint(java.awt.Graphics g0)
{
//draw m_board
java.awt.Image imgOff = createImage(this.getSize().width,this.getSize().height);
if(imgOff != null){
java.awt.Graphics g = imgOff.getGraphics();
g.setColor(java.awt.Color.lightGray);
g.drawRect(X0,Y0,CELLSIZE*BDWIDTH,CELLSIZE*BDHEIGHT);
for(int i=0,y=Y0;
i<BDHEIGHT;
i++,y+=CELLSIZE){
for(int j=0,x=X0;
j<BDWIDTH;
j++,x+=CELLSIZE){
if(m_board.bddata[j])
g.fill3DRect(x,y,CELLSIZE-1,CELLSIZE-1,true);
}
}
synchronized(m_players)
{
//draw all m_players.block
Player ps[] = m_players.allPlayers();
for(int k=0;
k<ps.length;
k++){
if(ps[k].playerState == Player.S_DROPPING){
g.setColor(ps[k].getPlayerColor());
for(int i=0,y=Y0+ps[k].block.rpos*CELLSIZE;
i<Block.BKSIZE;
i++,y+=CELLSIZE){
for(int j=0,x=X0+ps[k].block.cpos*CELLSIZE;
j<Block.BKSIZE;
j++,x+=CELLSIZE){
if(ps[k].block.bkdata[j])
g.fill3DRect(x,y,CELLSIZE-1,CELLSIZE-1,true);
}
}
}
}
}
}
g0.drawImage(imgOff,0,0,this);
}
}
private class ControlPanel extends java.awt.Panel
{
private class ShowNextBlockCanvas extends java.awt.Canvas
{
public ShowNextBlockCanvas()
{
setBackground(java.awt.Color.blue);
}
public java.awt.Dimension getPreferredSize()
{
return new java.awt.Dimension(X0*2+CELLSIZE*Block.BKSIZE,Y0*2+CELLSIZE*Block.BKSIZE);
}
public void paint(java.awt.Graphics g)
{
g.setColor(java.awt.Color.lightGray);
g.drawString("NEXT",X0,Y0);
g.drawRect(X0,Y0,Block.BKSIZE*CELLSIZE,Block.BKSIZE*CELLSIZE);
synchronized(m_blockDataPoolQueue){
boolean bkd[][] = m_blockDataPoolQueue.peekNextBlockData();
g.setColor(java.awt.Color.lightGray);
for(int i=0;
i<Block.BKSIZE;
i++)
for(int j=0;
j<Block.BKSIZE;
j++)
if(bkd[j])
g.fillRect(X0+i*CELLSIZE,Y0+j*CELLSIZE,CELLSIZE-1,CELLSIZE-1);
}
}
}
private class PlayersControlPanel extends java.awt.Panel
{
private java.awt.Button m_buttonAddNewPlayer = new java.awt.Button("Add New Player");
private class DialogAddNewPlayer extends java.awt.Dialog
{
private class MessageDialog extends java.awt.Dialog
{
private java.awt.Label labelMsg = new java.awt.Label();
private java.awt.Button buttonOk = new java.awt.Button("Close");
public MessageDialog(java.awt.Dialog owner,String title,String msg)
{
super(owner,title,true);
this.labelMsg.setText(msg);
this.addWindowListener(new java.awt.event.WindowAdapter(){
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
});
this.setLayout(new java.awt.BorderLayout(10,10));
this.add(labelMsg,"Center");
buttonOk.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
dispose();
}
});
java.awt.Panel panel1 = new java.awt.Panel(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER));
panel1.add(buttonOk);
this.add(panel1,"South");
this.pack();
this.setLocation(getOwner().getLocation().x+(getOwner().getSize().width-getSize().width)/2,getOwner().getLocation().y+(getOwner().getSize().height-getSize().height)/2);
}
}
private java.awt.Label labelName = new java.awt.Label("Name");
private java.awt.TextField textFieldName = new java.awt.TextField(12);
private java.awt.Label labelColor = new java.awt.Label("Color");
private java.awt.Choice choiceColor = new java.awt.Choice();
private java.awt.Button buttonOk = new java.awt.Button("Ok");
private java.awt.Button buttonCancel = new java.awt.Button("Cancel");
public DialogAddNewPlayer(java.awt.Frame frame)
{
super(frame,"Add a new player",true);
this.addWindowListener(new java.awt.event.WindowAdapter(){
public void windowClosing(java.awt.event.WindowEvent e)
{
dispose();
}
});
this.setLayout(new java.awt.BorderLayout(5,30));
java.awt.Panel panel1 = new java.awt.Panel(new java.awt.GridLayout(2,2,5,10));
panel1.add(labelName);
panel1.add(textFieldName);
panel1.add(labelColor);
choiceColor.addItem("Red");
choiceColor.addItem("Green");
choiceColor.addItem("Blue");
choiceColor.addItem("Yellow");
panel1.add(choiceColor);
this.add(panel1,"Center");
java.awt.Panel panel2 = new java.awt.Panel(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER,5,10));
panel2.add(buttonOk);
panel2.add(buttonCancel);
this.add(panel2,"South");
this.pack();
this.setLocation(frame.getLocation().x+(frame.getSize().width-this.getSize().width)/2,frame.getLocation().y+(frame.getSize().height-this.getSize().height)/2);
buttonCancel.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
dispose();
}
});
buttonOk.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
if(textFieldName.getText().equals(""))
new MessageDialog(DialogAddNewPlayer.this,"Information","名字不能为空!").show();
else
{
java.awt.Color playerColor;
switch(choiceColor.getSelectedIndex()){
case 0: playerColor = java.awt.Color.red;
break;
case 1: playerColor = java.awt.Color.green;
break;
case 2: playerColor = java.awt.Color.blue;
break;
case 3: playerColor = java.awt.Color.yellow;
break;
default: playerColor = java.awt.Color.white;
}
boolean succ;
synchronized(m_players){
succ = addNewPlayer(textFieldName.getText(),Player.S_INIT,playerColor);
}
if(! succ){
new MessageDialog(DialogAddNewPlayer.this,"Information","该名字已经存在,请换一个名字重试!").show();
textFieldName.setText("");
}else
dispose();
}
}
});
}
}
public PlayersControlPanel()
{
setBackground(java.awt.Color.gray);
this.setLayout(new java.awt.FlowLayout());
this.m_buttonAddNewPlayer.addActionListener(new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent e)
{
DialogAddNewPlayer dialog = new DialogAddNewPlayer(gameFrame);
dialog.show();
}
});
this.add(m_buttonAddNewPlayer);
}
}
private ShowNextBlockCanvas m_showNextBlockCanvas = new ShowNextBlockCanvas();
private PlayersControlPanel m_playersControlPanel = new PlayersControlPanel();
public ControlPanel()
{
setBackground(java.awt.Color.gray);
this.setLayout(new java.awt.BorderLayout());
this.add(m_showNextBlockCanvas,"North");
//
//TODO: this.add(m_playersControlPanel,"Center");
}
public void repaintNextBlockRequest()
{
this.m_showNextBlockCanvas.repaint();
}
}
private final int X0 = 10, Y0 = 15;
private final int CELLSIZE = 12;
private BoardCanvas m_boardCanvas = new BoardCanvas();
private ControlPanel m_controlPanel = new ControlPanel();
private java.awt.Frame gameFrame;
//constructor GamePanel
public GameServer(java.awt.Frame gameFrame)
{
this.gameFrame = gameFrame;
this.setLayout(new java.awt.BorderLayout());
this.add(m_boardCanvas,"Center");
//
this.add(m_controlPanel,"East");
m_players.addPlayer(new Player("Tom",Player.S_INIT,java.awt.Color.red,300));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Tom",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(400);
}catch (InterruptedException ex){
}
}
}
}.start();
m_players.addPlayer(new Player("Mike",Player.S_INIT,java.awt.Color.green,550));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Mike",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(700);
}catch (InterruptedException ex){
}
}
}
}.start();
m_players.addPlayer(new Player("Jerry",Player.S_INIT,java.awt.Color.blue,600));
new Thread(){
public void run()
{
while(true){
postMessage(new Message("Jerry",Message.MOVE_DOWN));
try{
Thread.currentThread().sleep(400);
}catch (InterruptedException ex){
}
}
}
}.start();
new Thread(this).start();
//消息处理线程
m_boardCanvas.requestFocus();
}
/////////main message-handler method
public void run()
{
java.util.Random ran = new java.util.Random();
while(true){
Message msg;
synchronized(m_msgQueue){
while(m_msgQueue.empty()){
try{
m_msgQueue.wait();
}catch (InterruptedException ex){
}
}
msg = m_msgQueue.dlMessage();
//synchronized
}
//处理消息
synchronized(m_players){
Player player = m_players.forPlayerName(msg.getPlayerName());
if(player != null){ //该消息所指的player还存在于players中
switch(player.playerState){
case Player.S_INIT:
//player.state = Player.S_TO_GENERATE_BLOCK;
//postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
break;
case Player.S_TO_GENERATE_BLOCK:
synchronized(m_blockDataPoolQueue){
for(int times=0;
times<12;
times++){
player.block = new Block(m_blockDataPoolQueue.getNextBlockData(),0,ran.nextInt(BDWIDTH-Block.BKSIZE));
repaintNextBlockRequest();
if(! isCollided(m_board,player.block) &&
!isCollidedWithAnyOtherPlayer(player))
break;
else
System.out.println("retry generate new block");
}
}
if( isCollided(m_board,player.block) || isCollidedWithAnyOtherPlayer(player)){
player.block = null;//undo generate block
player.playerState = Player.S_DEAD;
postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_TO_GENERATE_BLOCK,Player.S_DEAD);
}else
{
player.playerState = Player.S_DROPPING;
postMessage(new Message(player.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_TO_GENERATE_BLOCK,Player.S_DROPPING);
}
repaintBoardRequest();
break;
case Player.S_DROPPING:
if(msg.getAction() != Message.ACT_NULL){
PlayersVector playersAffected = new PlayersVector();
playersAffected.addPlayer(player);
PlayersVector playersUnableToDo = new PlayersVector();
if(playerDoAction(player,msg.getAction(),playersAffected,playersUnableToDo)){
onAction(playersAffected,msg.getAction());
repaintBoardRequest();
}else
{
Player ps1[] = playersAffected.allPlayers();
for(int i=0;
i<ps1.length;
i++)
ps1.block.undoAction(msg.getAction());
//undo all players affected
if(msg.getAction()==Message.MOVE_DOWN){
Player ps2[] = playersUnableToDo.allPlayers();
for(int i=0;
i<ps2.length;
i++){
merge(m_board,ps2.block);
ps2.block = null;
ps2.playerState = Player.S_TO_GENERATE_BLOCK;
postMessage(new Message(ps2.getPlayerName(),Message.ACT_NULL));
onPlayerStateChanged(player.getPlayerName(),Player.S_DROPPING,Player.S_TO_GENERATE_BLOCK);
}
int n = packUpBoard(m_board);
repaintBoardRequest();
}
}
}
break;
case Player.S_DEAD:
//System.out.println("Player "+player.getPlayerName()+" Dead!");
//m_players.remove(player);
break;
}
}
}
}
}
//_ASSERT(player.state==Player.S_DROPPING)
private boolean isCollidedWithAnyOtherPlayer(Player player0) //player is collided with any player in m_players-{player}
{
Player ps[] = m_players.allPlayers();
for(int i=0;
i<ps.length;
i++){
if(ps != player0 &&
ps.playerState==Player.S_DROPPING){
if(isCollided(player0.block,ps.block))
return true;
}
}
return false;
}
//如果player0可以执行action,则player及其相affected的players(在m_players中)执行action,
//已经执行action的players(包括player0)放在playerAffected中,并返回true;
//否则,阻塞player0的其他players(包括player0)放在playersAffected中,并返回false
private boolean playerDoAction(Player player0,int action,PlayersVector playersAffected,PlayersVector playersUnableToDo)
{
player0.block.doAction(action);
boolean canDo = true;
if(isCollided(m_board,player0.block)) //叶子
canDo = false;
Player ps[] = m_players.allPlayers();
for(int i=0;
i<ps.length;
i++)
if(! playersAffected.contains(ps))
if(ps.playerState==Player.S_DROPPING)
if(isCollided(player0.block,ps.block)){
if((action==Message.MOVE_UP)||(action==Message.MOVE_DOWN)||(action==Message.MOVE_LEFT)||(action==Message.MOVE_RIGHT)){
playersAffected.addPlayer(ps);
if(! playerDoAction(ps,action,playersAffected,playersUnableToDo))
canDo = false;
}else
canDo = false;
}
if(!canDo)
playersUnableToDo.addPlayer(player0);
return canDo;
}
/////// method isClllided
private boolean isCollided(Block bk1,Block bk2) //判断两方块是否重叠
{
if(bk1.rpos-bk2.rpos>=0 &&
bk1.rpos-bk2.rpos<Block.BKSIZE){
for(int r1=0;
r1<Block.BKSIZE-(bk1.rpos-bk2.rpos);
r1++){
int r2 = r1+bk1.rpos-bk2.rpos;
if(bk1.cpos-bk2.cpos>=0 &&
bk1.cpos-bk2.cpos<Block.BKSIZE){
for(int c1=0;
c1<Block.BKSIZE-(bk1.cpos-bk2.cpos);
c1++){
int c2=c1+bk1.cpos-bk2.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}else
if(bk2.cpos-bk1.cpos>=0 &&
bk2.cpos-bk1.cpos<Block.BKSIZE){
for(int c2=0;
c2<Block.BKSIZE-(bk2.cpos-bk1.cpos);
c2++){
int c1=c2+bk2.cpos-bk1.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}
}
}else
if(bk2.rpos-bk1.rpos>=0 &&
bk2.rpos-bk1.rpos<Block.BKSIZE){
for(int r2=0;
r2<Block.BKSIZE-(bk2.rpos-bk1.rpos);
r2++){
int r1 = r2+bk2.rpos-bk1.rpos;
if(bk1.cpos-bk2.cpos>=0 &&
bk1.cpos-bk2.cpos<Block.BKSIZE){
for(int c1=0;
c1<Block.BKSIZE-(bk1.cpos-bk2.cpos);
c1++){
int c2=c1+bk1.cpos-bk2.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}else
if(bk2.cpos-bk1.cpos>=0 &&
bk2.cpos-bk1.cpos<Block.BKSIZE){
for(int c2=0;
c2<Block.BKSIZE-(bk2.cpos-bk1.cpos);
c2++){
int c1=c2+bk2.cpos-bk1.cpos;
if(bk1.bkdata[r1][c1] &&
bk2.bkdata[r2][c2])
return true;
}
}
}
}
return false;
}
/////// method isCollided
private boolean isCollided(Board board,Block block) //判断某方块与某底板是否重叠
{
for(int i=0;
i<Block.BKSIZE;
i++){
for(int j=0;
j<Block.BKSIZE;
j++){
if(block.rpos+i>=0 &&
block.rpos+i<BDHEIGHT &&
block.cpos+j>=0 &&
block.cpos+j<BDWIDTH){
if(block.bkdata[j] &&
board.bddata[i+block.rpos][j+block.cpos])
return true;
}else
if(block.bkdata[j])
return true;
}
}
return false;
}
/////// method merge
private void merge(Board board,Block block) //合并board <=== block
{
for(int i=0;
i<Block.BKSIZE;
i++)
for(int j=0;
j<Block.BKSIZE;
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[j];
}
/////// method packUpBoard
private int packUpBoard(Board board) //消去满行
{
int linesDeleted = 0;
for(int i=BDHEIGHT-1;
i>=0{ //检测第i行
boolean full = true;
for(int j=0;
j<BDWIDTH;
j++){
if(! board.bddata[j]){
full = false;
break;
}
}
if(full){ //第i行为满行
for(int k=i-1;
k>=0;
k--){
for(int c=0;
c<BDWIDTH;
c++)
board.bddata[k+1][c] = board.bddata[k][c];
}
for(int c=0;
c<BDWIDTH;
c++)
board.bddata[0][c] = false;
linesDeleted++;
}else
i--;
}
return linesDeleted;
}
/////// method playerStartGame,change the state of player
public boolean playerStartGame(final String playerName)
{
synchronized(m_players){
Player p = m_players.forPlayerName(playerName);
if(p != null){
if((p.playerState==Player.S_INIT) || (p.playerState==Player.S_DEAD)){
p.playerState = Player.S_TO_GENERATE_BLOCK;
postMessage(new Message(playerName,Message.ACT_NULL));
//onPlayerStateChanged();
return true;
}
}
return false;
}
}
public boolean addNewPlayer(String playerName,int state0,java.awt.Color playerColor)
{
if(m_players.forPlayerName(playerName)== null){ //no same name player existed!
m_players.addPlayer(new Player(playerName,state0,playerColor,900));
return true;
}else
return false;
}
/////// method postMessage
private boolean gamePaused = false;
public void postMessage(Message msg)
{
if(! gamePaused){
synchronized(m_msgQueue){
m_msgQueue.enMessage(msg);
m_msgQueue.notify();
}
}
}
///////mehtod repaintRequest
public void repaintBoardRequest()
{
this.m_boardCanvas.repaintBoardRequest();
}
public void repaintNextBlockRequest()
{
this.m_controlPanel.repaintNextBlockRequest();
}
//callback method
public void onPlayerStateChanged(String playerName,int stateOld,int stateNow)
{
}
public void onAction(PlayersVector psv,int action)
{
/*
System.out.println("On Action: "+action+" of players:");
Player ps[] = psv.allPlayers();
for(int i=0;
i<ps.length;
i++)
System.out.println(" "+ps.getPlayerName());
*/
}
///////// Fields of class GameCanvas //////////
private Board m_board = new Board();
//仅由消息处理器线程访问
private PlayersVector m_players = new PlayersVector();
private MessageQueue m_msgQueue = new MessageQueue();
//由消息处理器和awt线程访问
private BlockDataPoolQueue m_blockDataPoolQueue = new BlockDataPoolQueue();
public static final int BDWIDTH = 20;
public static final int BDHEIGHT = 30;
}
class Queue extends Object
{
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() //应先使用empty来检查
{
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;
}
}
class List_ChainImp //数据结构-链表,指针链表实现
{
protected Node head = new Node();
public List_ChainImp()
{
head.prev = head.next =null;
}
public boolean contains(Object item) //使用Object.equals()方法进行比较
{
for(Node q=head.next;
q!=null;
q=q.next)
if(q.equals(item))
return true;
return false;
}
public void add(Object item)
{
Node q = new Node();
q.objdata = item;
q.next = head.next;
q.prev = head;
if(head.next != null)
head.next.prev = q;
head.next = q;
}
public boolean remove(Object item) //使用Object.equals()进行比较
{
for(Node q=head.next;
q!=null;
q=q.next){
if(q.objdata.equals(item)){
q.prev.next = q.next;
if(q.next != null)
q.next.prev = q.prev;
return true;
}
}
return false;
}
public Object[] allElements()
{
Object objs[] = new Object[elementsNumber()];
Node q = head.next;
for(int i=0;
i<objs.length;
i++,q=q.next)
objs = q.objdata;
return objs;
}
public boolean empty()
{
return head.next==null;
}
public int elementsNumber()
{
int elemNum = 0;
Node q = head.next;
while(q != null){
elemNum++;
q = q.next;
}
return elemNum;
}
public void clear()
{
head.next = null;
}
protected class Node
{
Object objdata;
Node prev;
Node next;
}
}
class List_ArrayImp //数据结构-链表,数组实现
{
protected Object datas[];
protected int currentLen = 0;
public List_ArrayImp(int maxnum)
{
this.datas = new Object[maxnum];
}
public boolean contains(Object obj)
{
for(int i=0;
i<this.currentLen;
i++)
if(this.datas.equals(obj))
return true;
return false;
}
public void add(Object obj)
{
if(this.currentLen<this.datas.length-1)
this.datas[this.currentLen++] = obj;
else
throw new RuntimeException("List elements excced space!");
}
public boolean remove(Object obj)
{
for(int i=0;
i<this.currentLen;
i++){
if(this.datas.equals(obj)){
for(int j=i+1;
j<this.currentLen;
j++)
this.datas[j-1] = this.datas[j];
this.currentLen--;
return true;
}
}
return false;
}
public Object[] allElements()
{
Object objs[] = new Object[this.currentLen];
for(int i=0;
i<this.currentLen;
i++)
objs = this.datas;
return objs;
}
public boolean empty()
{
return this.currentLen==0;
}
public int elementsNumber()
{
return this.currentLen;
}
public void clear()
{
this.currentLen = 0;
}
}