A simple implement of the Tetris in JAVA
OK, This is an implement of the game Tetris by using JAVA.
1. Model
(1) Blocks
As we all know, Tetris has some blocks with different shapes , but how to store this different kinds of the blocks in the computer, or how to express the shapes by data?
We use arrays. different arrays to show different blocks.
For example, the shape "I" , we can use a two dimensional array
public class ShapI extends Component {
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>private int[][] components = {
<span style="white-space:pre"> </span>{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },// state one init
<span style="white-space:pre"> </span>{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },// state two turn once
<span style="white-space:pre"> </span>{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
<span style="white-space:pre"> </span>{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 }, };
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public ShapI(){
<span style="white-space:pre"> </span>super.components = components;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void draw(Graphics g, int x, int y) {
<span style="white-space:pre"> </span>g.fillRect(x, y, 10, 10);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
}
to show the block, and different state.
The other blocks are same.
(2)The rest blocks on the canvas。
Then, we still use an array to describe it.
public class ShapAll extends Component {
private int[][] components = new int[28][30];
public ShapAll() {
for (int i = 0; i < 30; i++) {
components[0][i] = 2;
components[27][i] = 2;
}
for (int i = 0; i < 27; i++) {
components[i][29] = 2;
}
}
@Override
public void drawShap(Graphics g) {
for (int i = 0; i < 28; i++) {
for (int j = 0; j < 30; j++) {
if (components[i][j] == 2) {
g.drawRect(10 * i, 10 * j, 10, 10);
}
if (components[i][j] == 1) {
g.fillRect(10 * i, 10 * j, 10, 10);
}
}
}
}
<span style="white-space:pre"> </span>// check if there is a block.
public int getValue(int i, int x, int y) {
if (components[i % 4 + x / 10][i / 4 + y / 10 + 1] != 0) // down
return 1;
if (components[i % 4 + x / 10 + 1][i / 4 + y / 10] != 0) // right
return 2;
if (components[i % 4 + x / 10 - 1][i / 4 + y / 10] != 0) // left
return 3;
return 0;
}
<span style="white-space:pre"> </span>// add a new Shape on it (after the shape is down)
public void addOne(Component comp) {
for (int i = 0; i < 16; i++) {
if (comp.getValue(i)) {
components[i % 4 + comp.getX() / 10][i / 4 + comp.getY() / 10] = 1;
removeLine();
}
}
for (int i = 0; i < 28; i++) {
for (int j = 0; j < 30; j++) {
System.out.print(components[i][j]);
}
System.out.println();
}
System.out.println();
removeLine();
}
<span style="white-space:pre"> </span>// of course remve on
public void removeLine() {
int result = 1;
for (int i = 0; i < 29; i++) {
for (int j = 1; j < 27; j++) {
result = result * components[j][i];
}
if (result == 1) {
// 消除后 所有行下移 预留
for(int l=i;l>=1;l--){
for (int k = 26; k > 0; k--) {
components[k][l] = components[k][l-1];
}
}
for (int x = 0; x < 28; x++) {
for (int z= 0; z < 30; z++) {
System.out.print(components[x][z]);
}
System.out.println();
}
}
result = 1;
}
}
}
And all the shapes and shapAll are extends from the component.
public class Component {
protected int x = 130;
protected int y = 0;
protected int[][] components = new int[4][16];
protected int state = 0;
public void draw(Graphics g, int x, int y) {
g.fillRect(x, y, 10, 10);
}
public void drawShap(Graphics g) {
for (int i = 0; i < components[0].length; i++) {
if (components[state][i] == 1) {
Component comp = new Component();
comp.draw(g, x + i % 4 * 10, y + i / 4 * 10);
}
}
}
public boolean getValue(int i){
if(components[state][i] != 0)
return true;
return false;
}
public void turn() {
state++;
if (state == 4)
state = 0;
}
public void down() {
y += 10;
}
public void move(int xx, int yy) {
this.x = x + xx;
this.y = y + yy;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
}
2. Canvas
Of course we need a canvas to show all the blocks on it.
public class Canvas extends JPanel {
private static Canvas instance;
private ArrayList<Component> al_Components;
private Canvas() {
this.addKeyListener(new KeyController());
}
public static Canvas getInstance() {
if (instance == null) {
instance = new Canvas();
}
return instance;
}
public void setComponents(ArrayList<Component> al_Components){
this.al_Components = al_Components;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(Component comp: al_Components){
comp.drawShap(g);
}
}
}
3. Controllers
We create a KeyController to implements the KeyListener interface to listen the user's action.
and in the KeyController we add a callback interface to response to the user's action.
public class KeyController implements KeyListener {
private KeyControllCallBack cb;
public void setContext(KeyControllCallBack cb) {
this.cb = cb;
}
@Override
public void keyTyped(KeyEvent e) {
System.out.println(e.getKeyChar());
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_SPACE:
cb.keySpace();
break;
case KeyEvent.VK_LEFT:
cb.keyLeft();
break;
case KeyEvent.VK_RIGHT:
cb.keyRight();
break;
case KeyEvent.VK_DOWN:
cb.keyDown();
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
public interface KeyControllCallBack {
public void keySpace();
public void keyLeft();
public void keyRight();
public void keyDown();
}
}
And the ShapController which implements the Callback interface we mentioned to control the game.
public class ShapController implements KeyControllCallBack {
private ArrayList<Component> al_component = new ArrayList<Component>();
private Component comp_Now;
private ShapAll shapAll;
private void createNewShap() {
al_component.remove(comp_Now);
int i = (int)(Math.random()*1000)%3;
switch(i){
case 0:
comp_Now = new ShapL();
break;
case 1:
comp_Now = new ShapO();
break;
case 2:
comp_Now = new ShapI();
break;
}
al_component.add(comp_Now);
}
public ShapController() {
Canvas.getInstance().setComponents(al_component);
createNewShap();
createShapAll();
Timer timer = new Timer();
timer.schedule(new TimerTaskGame(), 1000, 1000);
}
public void createShapAll() {
shapAll = new ShapAll();
al_component.add(shapAll);
}
// collision detected
public int isCollision() {
int result = 0;
for (int i = 0; i < 16; i++) {
if (comp_Now.getValue(i)&& shapAll.getValue(i, comp_Now.getX(), comp_Now.getY())==1){
result = 1;
}
if (comp_Now.getValue(i)&& shapAll.getValue(i, comp_Now.getX(), comp_Now.getY())==2)
result = 2;
if (comp_Now.getValue(i)&& shapAll.getValue(i, comp_Now.getX(), comp_Now.getY())==3)
result = 3;
}
return result;
}
public void turn() {
if (isCollision() == 0){
comp_Now.turn();
}
}
public void down() {
if (isCollision() != 1) {
comp_Now.down();
}else{
shapAll.addOne(comp_Now);
createNewShap();
}
}
public void left() {
if (isCollision() != 3 && isCollision()!=1) {
comp_Now.move(-10, 0);
}
}
public void right() {
if (isCollision() != 2 && isCollision()!=1) {
comp_Now.move(10, 0);
}
}
private class TimerTaskGame extends TimerTask {
@Override
public void run() {
down();
Canvas.getInstance().repaint();
}
}
@Override
public void keySpace() {
turn();
Canvas.getInstance().repaint();
}
@Override
public void keyLeft() {
left();
Canvas.getInstance().repaint();
}
@Override
public void keyRight() {
right();
Canvas.getInstance().repaint();
}
@Override
public void keyDown() {
down();
Canvas.getInstance().repaint();
}
}
That's all!