package tetris;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris
{
public static void main(String[] args)
{
long[] shapes = {0x88c002e06220e80l, 0x8e02260e200c88l, 0x8c8004e02620e40l, 0xcc00cc00cc00ccl,
0x6c08c4006c08c4l, 0xc604c800c604c8l, 0x8888000f8888000fl};
GameFrame frame = new GameFrame();
Shape player = new Shape(shapes[0]);
GameRound round = new GameRound(shapes, player, (byte)32, (byte)15, (byte)20, (byte) 20);
GamePanel panel = new GamePanel(round, player);
frame.add(panel);
frame.setVisible(true);
frame.repaint();
}
@SuppressWarnings("serial")
private static class GameFrame extends JFrame
{
public GameFrame()
{
setIgnoreRepaint(true);
setUndecorated(true);
setBounds(0, 0, 800, 480);
setLocationRelativeTo(null);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
@SuppressWarnings("serial")
private static class GamePanel extends JPanel implements Runnable
{
private GameRound round;
private Shape player;
public GamePanel(GameRound round, Shape player)
{
this.round = round;
this.player = player;
setBounds(0, 0, 800, 480);
setLayout(null);
setFocusable(true);
requestFocus();
addKeyListener(new KeyHandle());
new Thread(this).start();
}
@Override
public void paint(Graphics g)
{
//清屏
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 480);
g.setColor(Color.BLACK);
g.drawRect(0, 0, 799, 479);
round.show(g);
player.show(g);
}
public void run()
{
int num = 0;
while(true)
{
if(num++ > 1000000)
num = 0;
if(num % 1000 == 0)
processKeyEvent(new KeyEvent(GamePanel.this, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, KeyEvent.VK_DOWN, (char)KeyEvent.VK_DOWN));
repaint();
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
private class KeyHandle extends KeyAdapter
{
@Override
public void keyPressed(KeyEvent e)
{
switch(e.getKeyCode())
{
case KeyEvent.VK_DOWN:
round.moveDown();
break;
case KeyEvent.VK_LEFT:
round.moveLeft();
break;
case KeyEvent.VK_RIGHT:
round.moveRight();
break;
case KeyEvent.VK_UP:
round.moveUp();
break;
case KeyEvent.VK_ENTER:
byte oldleft = player.getBoundsLeft();
byte oldright = player.getBoundsRight();
player.nextFrame();
if(round.collide(0, 0))
{
player.prevFrame();
}
else
{
if(player.getX() < 0)
{
player.setX((byte)(player.getX() + (oldleft - player.getBoundsLeft())));
}
else if(player.getX() > 31- 3)
{
player.setX((byte)(player.getX() - (oldright - player.getBoundsRight())));
}
}
break;
case KeyEvent.VK_ESCAPE:
System.exit(0);
break;
}
}
}
}
private static class GameRound
{
private final byte GAME_ROUND_WIDTH;
private final byte GAME_ROUND_HEIGHT;
private final byte GAME_TILE_WIDTH;
private final byte GAME_TILE_HEIGHT;
private final long[] SHAPES;
private final int[] GAME_DATA;
private Shape player;
private Random ran = new Random();
public GameRound(long[] shapes, Shape player, byte width, byte height, byte twidth, byte theight)
{
//初始化游戏区域的宽和高
//该宽高并不是实际的宽高
//而是指横、纵格子的数量
GAME_ROUND_WIDTH = width;
GAME_ROUND_HEIGHT = height;
//初始化每个格子的宽和高
GAME_TILE_WIDTH = twidth;
GAME_TILE_HEIGHT = theight;
SHAPES = shapes;
this.player = player;
GAME_DATA = new int[GAME_ROUND_HEIGHT];
GAME_DATA[GAME_ROUND_HEIGHT - 2] = 0xaaaaaaaa;
GAME_DATA[GAME_ROUND_HEIGHT - 1] = -1;
}
public void show(Graphics g)
{
g.setColor(Color.WHITE);
g.fillRect(0, 0, 800, 480);
g.setColor(Color.RED);
g.drawRect(0, 0, 799, 479);
//渲染数据区
for (int i = 0; i < GAME_ROUND_WIDTH; i++)
{
for (int j = 0; j < GAME_ROUND_HEIGHT; j++)
{
if(((GAME_DATA[j] >> GAME_ROUND_WIDTH-1-i) & 1) == 1)
g.setColor(Color.RED);
else
g.setColor(Color.GREEN);
g.fillRect(i * GAME_TILE_WIDTH, j * GAME_TILE_HEIGHT, GAME_TILE_WIDTH, GAME_TILE_HEIGHT);
g.setColor(Color.BLACK);
g.drawRect(i * GAME_TILE_WIDTH, j * GAME_TILE_HEIGHT, GAME_TILE_WIDTH, GAME_TILE_HEIGHT);
}
}
}
public void moveDown()
{
if(player.getY() < 14 - 3 + player.getBoundsButtom())
{
if(!collide(0,1))
player.y++;
else
shapeDown();
}
else
shapeDown();
}
public void moveUp()
{
if(!collide(0, -1))
{
player.y--;
}
}
public void moveLeft()
{
if(player.getX() > 0 - player.getBoundsLeft())
{
if(!collide(-1,0))
player.x--;
}
}
public void moveRight()
{
if(player.getX() < 31 - 3 + player.getBoundsRight())
{
if(!collide(+1,0))
player.x++;
}
}
public boolean collide(int x, int y)
{
int a,b;
for (int shift = player.getBoundsButtom(); shift < 4; shift++)
{
if(player.getX() < 0)
a = (((((int)player.getFrameData() << (16 + ((3 - shift) << 2) - (player.getX() + x)))) & 0xf0000000));
else
a = (((((int)player.getFrameData() << (16 + ((3 - shift) << 2)))) & 0xf0000000) >>> player.getX() + x);
b = (GAME_DATA[player.getY() + 3 - shift + y]);
if( (a & b) != 0)
{
return true;
}
}
return false;
}
public void shapeDown()
{
int down = 0;
if(player.getY() >= 12)
down = player.getY()+3;
else
down = player.getY() + 3;
for (int shift = player.getBoundsButtom(); shift < 4; shift++)
{
if(player.getX() > -1)
GAME_DATA[down-shift] |= (((((int)player.getFrameData() << (16 + ((3 - shift) << 2)))) & 0xf0000000) >>> player.getX());
else
GAME_DATA[down-shift] |= (((((int)player.getFrameData() << (16 + ((3 - shift) << 2) - player.getX()))) & 0xf0000000));
}
for (int i = GAME_DATA.length - 1; i >= 0; i--)
{
if(GAME_DATA[i] == -1)
{
int[] tmp = new int[i];
System.arraycopy(GAME_DATA, 0, tmp, 0, tmp.length);
System.arraycopy(tmp, 0, GAME_DATA, 1, tmp.length);
}
}
randomShape();
}
public void randomShape()
{
player.initShape(SHAPES[Math.abs(ran.nextInt() % 7)], (byte)(Math.abs(ran.nextInt() % 4)));
}
}
private static class Shape
{
private long data;
private byte curr_frame;
private short frame_data;
private byte bounds_left;
private byte bounds_right;
private byte bounds_buttom;
private byte x;
private byte y;
public Shape(long data)
{
this(data, (byte)0);
}
public Shape(long data, byte curr_frame)
{
initShape(data, curr_frame);
}
public void initShape(long data, byte curr_frame)
{
this.data = data;
setCurrentFrame(curr_frame);
initBounds();
setX((byte)14);
setY((byte)0);
}
public short getFrameData()
{
return this.frame_data;
}
public void show(Graphics g)
{
for (int shift = 0; shift < 4; shift++)
{
for (int bit = 0; bit < 4; bit++)
{
if((((frame_data >> ((3 - shift) << 2)) >> (3 - bit)) & 1) == 1)
{
g.setColor(Color.BLUE);
g.fillRect((x + bit) * 20, (y+shift) * 20, 20, 20);
}
}
}
g.setColor(Color.YELLOW);
g.drawRect(x * 20 + 1, y * 20 + 1, 79, 79);
}
public void nextFrame()
{
setCurrentFrame(++curr_frame > 3 ? 0 : curr_frame);
initBounds();
}
public void prevFrame()
{
setCurrentFrame(--curr_frame < 0 ? 3 : curr_frame);
initBounds();
}
private void setCurrentFrame(byte curr_frame)
{
this.curr_frame = curr_frame;
this.frame_data = (short) (data >> ((3 - curr_frame) << 4));
}
private void initBounds()
{
bounds_left = 0;
if((frame_data & 0x8888) == 0)
{
if((frame_data & 0x4444) == 0)
{
if((frame_data & 0x2222) == 0)
bounds_left = 3;
else
bounds_left = 2;
}
else
bounds_left = 1;
}
bounds_right = 0;
A:if((frame_data & 0x1111) == 0)
{
if((frame_data & 0x2222) == 0)
{
if((frame_data & 0x4444) == 0)
{
bounds_right = 3;
break A;
}
bounds_right = 2;
break A;
}
bounds_right = 1;
}
bounds_buttom = 0;
A:if((frame_data & 0x000f) == 0)
{
if((frame_data & 0x00f0) == 0)
{
if((frame_data & 0x0f00) == 0)
{
bounds_buttom = 3;
break A;
}
bounds_buttom = 2;
break A;
}
bounds_buttom = 1;
}
}
public byte getBoundsLeft()
{
return bounds_left;
}
public byte getBoundsRight()
{
return bounds_right;
}
public byte getBoundsButtom()
{
return bounds_buttom;
}
public byte getX()
{
return x;
}
public void setX(byte x)
{
this.x = x;
}
public byte getY()
{
return y;
}
public void setY(byte y)
{
this.y = y;
}
}
}