
I created a Tetris clone in Java.
These are the controls for the applet below:
← and → | Move brick left or right 1 position |
Ctrl-← and Ctrl-→ | Move brick left or right as far as possible |
Shift | Turn brick clockwise |
↑ | Turn brick counterclockwise |
↓ | Move brick down 1 position |
CTRL ↓ of Enter | Move brick down as far as possible |
Here is the source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.applet.*; @SuppressWarnings("serial") public class TetrisApplet extends Applet implements Observer { final static String startTxt = "Start!", pauseTxt = "Pause"; IntLabel score, level, lines, tetrisses; TetrisGrid g; TetrisCanvas c; AudioClip musicA, musicB, musicC; JRadioButton radioA, radioB, radioOff; public void init() { this.setLayout(new BorderLayout()); Panel panel = new Panel(); panel.setLayout(new GridLayout(2,1)); this.setBackground(Color.darkGray); this.setSize(310,400); g = new TetrisGrid(10, 20, 20); g.addObserver(this); c = new TetrisCanvas(); Panel nextPanel = new Panel(new BorderLayout()); NextViewer n = new NextViewer(g); JButton b = new JButton(new AbstractAction(startTxt) { public void actionPerformed(ActionEvent e) { c.pressStart(); } }); JButton p = new JButton(new AbstractAction(pauseTxt) { public void actionPerformed(ActionEvent e) { c.pressPause(); } }); Panel scorePanel = new Panel(new GridLayout(7,1)); score = new IntLabel("Score: ", 0); level = new IntLabel("Level: ", 0); lines = new IntLabel("Lines: ", 0); tetrisses = new IntLabel("Tetrisses: ", 0); nextPanel.add(b, BorderLayout.NORTH); nextPanel.add(n, BorderLayout.CENTER); nextPanel.add(p, BorderLayout.SOUTH); ButtonGroup bs = new ButtonGroup(); scorePanel.add(radioA = new JRadioButton(new AbstractAction("Music A"){ public void actionPerformed(ActionEvent e){ musicB.stop(); musicA.loop(); } })); scorePanel.add(radioB = new JRadioButton(new AbstractAction("Music B"){ public void actionPerformed(ActionEvent e){ musicA.stop(); musicB.loop(); } })); scorePanel.add(radioOff = new JRadioButton(new AbstractAction("No music"){ public void actionPerformed(ActionEvent e){ musicA.stop(); musicB.stop(); } })); bs.add(radioA); bs.add(radioB); bs.add(radioOff); radioOff.setSelected(true); scorePanel.add(score); scorePanel.add(level); scorePanel.add(lines); scorePanel.add(tetrisses); panel.add(nextPanel); panel.add(scorePanel); b.addKeyListener(c); p.addKeyListener(c); radioA.addKeyListener(c); radioB.addKeyListener(c); radioOff.addKeyListener(c); add(panel, BorderLayout.WEST); add(c, BorderLayout.CENTER); musicA = this.getAudioClip(this.getCodeBase(), "teta.mid"); musicB = this.getAudioClip(this.getCodeBase(), "tetb.mid"); musicC = this.getAudioClip(this.getCodeBase(), "tetc.mid"); } public void update(Observable obs, Object obj) { if (g.score!=score.getValue()) score.setValue(g.score); if (g.level!=level.getValue()) { level.setValue(g.level); c.calcDelay(); } if (g.lines!=lines.getValue()) lines.setValue(g.lines); if (g.tetrisses!=tetrisses.getValue()) tetrisses.setValue(g.tetrisses); } public class TetrisCanvas extends Canvas implements KeyListener, Observer, Runnable { Image backImg, blockImg; Graphics backG, blockG; Thread anim; boolean pause; long delay; TetrisCanvas() { try{ backImg = getImage(getCodeBase(), "back.jpg"); } catch(Exception e){System.out.println(e.toString());} MediaTracker tr = new MediaTracker(this); tr.addImage(backImg,0); try {tr.waitForAll();} catch (Exception e) {} this.addKeyListener(this); g.addObserver(this); this.setSize(g.width*g.blocksize, g.height*g.blocksize); this.setBackground(Color.black); calcDelay(); } public void calcDelay() { delay=(long)Math.max(50,550-44*g.level); } public void run() { while(!pause && !g.gameOver) { g.slideBlock(); try { Thread.sleep(delay); } catch (Exception e){} } } void pressStart() { if (g.gameOver) g.reset(); pause = false; if (anim==null) { anim=new Thread(this); anim.start(); } } void pressPause() { anim=null; pause = true; } public void update(Observable obs, Object obj) { if (g.gameOver) { anim=null; } repaint(); } public void update(Graphics g) { paint(g); } public void keyPressed(KeyEvent e) { if (!pause && !g.gameOver) switch (e.getKeyCode()) { case KeyEvent.VK_DOWN: if (e.isControlDown()) g.crashBlock(); else g.slideBlock(); break; case KeyEvent.VK_LEFT: if (e.isControlDown()) g.jumpLeftBlock(); else g.leftBlock(); break; case KeyEvent.VK_RIGHT: if (e.isControlDown()) g.jumpRightBlock(); else g.rightBlock(); break; case KeyEvent.VK_UP: g.turnLeftBlock(); break; case KeyEvent.VK_SHIFT: g.turnRightBlock(); break; case KeyEvent.VK_ENTER: g.crashBlock(); break; } } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} public void paint(Graphics gr) { if (blockImg==null) { blockImg = createImage(getSize().width, getSize().height); blockG = blockImg.getGraphics(); } blockG.drawImage(backImg, 0, 0, this); g.paint(blockG); gr.drawImage(blockImg, 0, 0, this); if (g.gameOver) { gr.setColor(Color.white); gr.drawString("G A M E O V E R",52,176); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
import java.awt.*; public abstract class Block { int currentState; State[] state; Color color; protected Block(Color c) { state=new State[4]; currentState=0; color=c; initStates(); } protected abstract void initStates(); protected Color getColor() { return color; } protected void turnLeft() { currentState++; if (currentState>3) currentState=0; } protected void turnRight() { currentState--; if (currentState<0) currentState=3; } protected State getCurrentState() { return state[currentState]; } protected State getLeftState() { if (currentState==3) return state[0]; else return state[currentState+1]; } protected State getRightState() { if (currentState==0) return state[3]; else return state[currentState-1]; } protected Point getPoint(int n) { return state[currentState].getPoint(n); } public static Block triangle() { return new Block(Color.orange) { protected void initStates() { state[0]=new State(1,1,2,1,2,2,3,1); state[1]=new State(2,0,2,1,2,2,3,1); state[2]=new State(1,1,2,1,2,0,3,1); state[3]=new State(1,1,2,0,2,1,2,2); } }; } public static Block square() { return new Block(Color.blue) { protected void initStates() { state[0]=state[1]=state[2]=state[3]=new State(1,1,2,1,1,2,2,2); } }; } public static Block bar() { return new Block(Color.red) { protected void initStates() { state[0]=state[2]=new State(0,1,1,1,2,1,3,1); state[1]=state[3]=new State(2,0,2,1,2,2,2,3); } }; } public static Block leftHook() { return new Block(Color.white) { protected void initStates() { state[0]=new State(1,1,2,1,3,1,3,2); state[1]=new State(2,0,2,1,2,2,3,0); state[2]=new State(1,0,1,1,2,1,3,1); state[3]=new State(1,2,2,2,2,1,2,0); } }; } public static Block leftZag() { return new Block(Color.cyan) { protected void initStates() { state[0]=new State(1,1,2,1,2,2,3,2); state[1]=new State(2,1,2,2,3,0,3,1); state[2]=new State(1,1,2,1,2,2,3,2); state[3]=new State(2,1,2,2,3,0,3,1); } }; } public static Block rightHook() { return new Block(Color.magenta) { protected void initStates() { state[0]=new State(1,1,2,1,3,1,1,2); state[1]=new State(2,0,2,1,2,2,3,2); state[2]=new State(1,1,2,1,3,1,3,0); state[3]=new State(1,0,2,0,2,1,2,2); } }; } public static Block rightZag() { return new Block(Color.green) { protected void initStates() { state[0]=new State(1,2,2,2,2,1,3,1); state[1]=new State(2,0,2,1,3,1,3,2); state[2]=new State(1,2,2,1,2,2,3,1); state[3]=new State(2,0,2,1,3,1,3,2); } }; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import javax.swing.JLabel; import java.awt.Color; @SuppressWarnings("serial") public class IntLabel extends JLabel { int value; String text; public IntLabel(String text, int initValue) { this.text = text; this.setForeground(Color.white); this.setAlignmentX(JLabel.RIGHT_ALIGNMENT); setValue(initValue); } public void setValue(int newValue) { value = newValue; setText(text+value); } public int getValue() { return value; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.awt.*; import java.util.*; @SuppressWarnings("serial") public class NextViewer extends Canvas implements Observer { TetrisGrid g; Block nextBlock; NextViewer(TetrisGrid g) { this.g = g; g.addObserver(this); this.nextBlock = g.nextBlock; this.setSize(5*g.blocksize,4*g.blocksize); this.setBackground(Color.black); } public void update(Observable obs, Object obj) { if (g.nextBlock!=this.nextBlock) { this.nextBlock = g.nextBlock; repaint(); } } public void paint(Graphics gr) { State s = nextBlock.getCurrentState(); for (int i=0; i<4; i++) { TetrisGrid.paintBlock(gr, s.getPoint(i).x, s.getPoint(i).y, g.blocksize, nextBlock.getColor()); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.awt.Point; public class State { Point[] point; protected State(Point p0, Point p1, Point p2, Point p3) { point = new Point[4]; point[0]=p0; point[1]=p1; point[2]=p2; point[3]=p3; } protected State(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) { point = new Point[4]; point[0]=new Point(x0, y0); point[1]=new Point(x1, y1); point[2]=new Point(x2, y2); point[3]=new Point(x3, y3); } public Point getPoint(int n) { return point[n]; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
import java.awt.*; import java.util.*; public class TetrisGrid extends Observable { protected int width, height, blocksize; protected Block block, nextBlock; protected Color[][] c; protected int blockX, blockY, score=0, level=0, lines=0, tetrisses=0; protected boolean gameOver=false; private Random rnd; public TetrisGrid(int w, int h, int s) { width = w; height = h; blocksize = s; c = new Color[width][height]; newBlock(); setChanged(); } public void reset() { gameOver=false; c = new Color[width][height]; score=level=lines=tetrisses=0; nextBlock=null; newBlock(); } public void paint(Graphics gr) { for (int l=0; l<height; l++) for (int i=0; i<width; i++) if (c[i][l]!=null) { paintBlock(gr, i, l, blocksize, c[i][l]); } State s = block.getCurrentState(); for (int i=0; i<4; i++) { paintBlock(gr, s.getPoint(i).x + blockX, s.getPoint(i).y + blockY, blocksize, block.getColor()); } } public static void paintBlock(Graphics gr, int x, int y, int s, Color c) { gr.setColor(Color.black); gr.drawRect(s*x,s*y,s,s); gr.setColor(c); gr.fillRect(s*x+1,s*y+1,s-1,s-1); } public Color c(int x,int y) { return c[x][y]; } public void notifyObservers() { super.notifyObservers(); setChanged(); } public void slideBlock() { if (isPossible(block.getCurrentState(), blockX, blockY+1)) blockY++; else dropBlock(); notifyObservers(); } public void crashBlock() { while (isPossible(block.getCurrentState(), blockX, blockY+1)) blockY++; dropBlock(); notifyObservers(); } public void leftBlock() { if (isPossible(block.getCurrentState(), blockX-1, blockY)) { blockX--; notifyObservers(); } } public void jumpLeftBlock() { while (isPossible(block.getCurrentState(), blockX-1, blockY)) blockX--; notifyObservers(); } public void rightBlock() { if (isPossible(block.getCurrentState(), blockX+1, blockY)) { blockX++; notifyObservers(); } } public void jumpRightBlock() { while (isPossible(block.getCurrentState(), blockX+1, blockY)) blockX++; notifyObservers(); } public void turnRightBlock() { if (isPossible(block.getRightState(), blockX, blockY)) { block.turnRight(); notifyObservers(); } } public void turnLeftBlock() { if (isPossible(block.getLeftState(), blockX, blockY)) { block.turnLeft(); notifyObservers(); } } public void dropBlock() { State s=block.getCurrentState(); for (int i=0; i<4; i++) c[s.getPoint(i).x+blockX][s.getPoint(i).y+blockY] = block.getColor(); int l=0; for (int i=0; i<4; i++) if (blockY+i < height) l+=removeFullLine(blockY+i)?1:0; score(l); newBlock(); } public boolean removeFullLine(int line) { for (int i=0; i<width; i++) if (line<0 || c[i][line]==null) return false; for (int l=line; l>=0; l--) for (int i=0; i<width; i++) if (l==0) c[i][0]=null; else c[i][l]=c[i][l-1]; return true; } public void score(int scoredLines) { if (scoredLines==4) tetrisses++; int inc=(int)(Math.sqrt(((level+1)*50))); for (int i=0; i<scoredLines; i++) { score+=inc; inc+=inc; } lines+=scoredLines; if (lines>10*level+9) level++; } public void newBlock() { if (nextBlock==null) nextBlock=randomBlock(); block=nextBlock; blockX=3; blockY=-1; nextBlock=randomBlock(); if (!isPossible(block.getCurrentState(), blockX, blockY)) gameOver(); } public Block randomBlock() { if (rnd==null) rnd = new Random(); int i = (int)(rnd.nextDouble()*7); switch (i) { case 0: return Block.square(); case 1: return Block.bar(); case 2: return Block.rightHook(); case 3: return Block.leftHook(); case 4: return Block.leftZag(); case 5: return Block.rightZag(); default:return Block.triangle(); } } public void gameOver() { gameOver = true; for (int l=0; l<height; l++) for (int i=0; i<width; i++) c[i][l]=new Color((float)Math.random(),(float)Math.random(),(float)Math.random()); notifyObservers(); } public boolean isPossible(State s, int x, int y) { try { for (int i=0; i<4; i++) if (c[s.getPoint(i).x+x][s.getPoint(i).y+y]!=null) return false; } catch (Exception e) { return false; } return true; } } |