import java.awt.*; import java.awt.image.*; import java.applet.Applet; import java.awt.event.*; import java.applet.AudioClip; import java.util.Vector; import java.lang.Math; import java.lang.Thread; import java.lang.System; public class Blocks extends java.applet.Applet implements Runnable, ActionListener, KeyListener { public static final int cols = 10; // number of columns in the grid public static final int rows = 23; // number of rows in the grid public static final int ElementSize = 15; //size of the element...bigger is bigger public static final int MaxElement = 3; public static final Color BackGroundColor = Color.black; public static final int SOUND_DROP = 0; public static final int SOUND_GAMEOVER = 1; public static final int SOUND_NEXTLEVEL = 2; public static final int SOUND_LINE = 3; CanvasField myPlayFieldCanvas; Stats Statistics; Thread killme = null; // used for thread control Vector ShapeSet; Shape FallingShape = null; Shape NextShape = null; Color PlayField[][]; static AudioClip sounds[]; public boolean GamePaused = false; Button startBtn, pauseBtn; public void init() { // runs the applet setLayout(new BorderLayout()); // type of layout for the applet myPlayFieldCanvas = new CanvasField(); // actual game grid add( myPlayFieldCanvas, BorderLayout.WEST ); // add game grid to layout Statistics = new Stats(); // innitiate stats object add( Statistics, BorderLayout.CENTER ); // add stats grid to applet layout Panel p = new Panel(); // used to hold the start and pause buttons p.setLayout(new FlowLayout()); startBtn = new Button(" Start "); startBtn.addActionListener( this ); p.add(startBtn); // adds the buttons to the panel pauseBtn = new Button("Pause / Resume"); pauseBtn.addActionListener( this ); pauseBtn.setEnabled(false); p.add(pauseBtn); add( p, BorderLayout.SOUTH ); ShapeSet = new Vector(); // creates and colors the elements ShapeSet.addElement(new Shape( 0x0000,0x0FF0,0x0FF0,0x0000, Color.blue,3)); ShapeSet.addElement(new Shape( 0x0F00,0x0F00,0x0FF0,0x0000, Color.yellow,5)); ShapeSet.addElement(new Shape( 0x00F0,0x00F0,0x0FF0,0x0000, Color.pink,5)); ShapeSet.addElement(new Shape( 0x0000,0x0F00,0xFFF0,0x0000, Color.green,4)); ShapeSet.addElement(new Shape( 0x0F00,0x0F00,0x0F00,0x0F00, Color.red, 4)); ShapeSet.addElement(new Shape( 0x0F00,0x0FF0,0x00F0,0x0000, Color.magenta, 4)); ShapeSet.addElement(new Shape( 0x00F0,0x0FF0,0x0F00,0x0000, Color.orange, 4)); // create an array for the sound / wav files sounds = new AudioClip[4]; sounds[0] = getAudioClip(getCodeBase(), "audio/drop.au"); sounds[1] = getAudioClip(getCodeBase(), "audio/gameover.au"); sounds[2] = getAudioClip(getCodeBase(), "audio/nextlevel.au"); sounds[3] = getAudioClip(getCodeBase(), "audio/line.au"); PlayField = new Color[cols][rows]; myPlayFieldCanvas.SetPlayField(PlayField); InitNewGame(); GetNextRandomShape(); addKeyListener(this); requestFocus(); } public static void play(int n) { if (sounds[n] != null) { sounds[n].play(); }} public void InitNewGame() { ClearPlayField(); Statistics.InitNewGame(); // startThread(); } public void ClearPlayField() // clears the playing field between games { int x, y; for (x = 0; x < cols ; x++) { for (y = 0 ; y < rows ; y++) { PlayField[x][y] = Color.black; }}} public int GetRandomShapeNr() { int ShapeNr; do { ShapeNr = (int) (Math.random() * ShapeSet.size()); } while (ShapeNr >= ShapeSet.size()); return ShapeNr; } //gets the next random shape to be played public void GetNextRandomShape() { if (FallingShape == null) { FallingShape = (Shape) ShapeSet.elementAt(GetRandomShapeNr()); } else FallingShape = NextShape; FallingShape.Init(); if (!FallingShape.CheckIfShapeFits(PlayField, 0, 0, false)) { GameOver(); } NextShape = (Shape) ShapeSet.elementAt(GetRandomShapeNr()); Statistics.DisplayNextShape(NextShape); } public void GameOver() { play (SOUND_GAMEOVER); myPlayFieldCanvas.GameOver(); Statistics.GameOver(); // InitNewGame(); killme = null; // toggle the thread startBtn.setEnabled(true); // cant use start unless game is paused or stopped pauseBtn.setEnabled(false); } public void start() { } public void startThread(){ if(killme == null) { killme = new Thread(this); killme.start(); } } public void stop() { killme = null; } public void run() { while (killme != null) { try { Thread.sleep(Statistics.GetGameSpeed()); } catch (InterruptedException e){} if (!GamePaused) { if (FallingShape != null) { if (FallingShape.CheckIfShapeFits(PlayField, 0, 1, false)) { ChangeShapePosition(0, 1, false); } else { play (SOUND_DROP); FallingShape.PlaceInPlayField(PlayField); myPlayFieldCanvas.RepaintPlayField(); Statistics.AddScore(FallingShape.GetValue()); CheckForFullLines(); GetNextRandomShape(); } } myPlayFieldCanvas.repaint(FallingShape); } } killme = null; } public void CheckForFullLines() { int Lines = 0; int x, y, yc; boolean Gap; for (y = 0; y < rows; y++) { Gap = false; for (x = 0; x < cols; x++) { if (PlayField[x][y] == Color.black) Gap = true; } if (!Gap) { Lines++; for (yc = y - 1; yc >= 0; yc--) { for (x = 0; x < cols; x++) { PlayField[x][yc + 1] = PlayField[x][yc]; } } for (x = 0; x < cols; x++) { // Delete top row. PlayField[x][0] = Color.black; } } } if (Lines > 0) { play (SOUND_LINE); myPlayFieldCanvas.RepaintPlayField(); } Statistics.AddLines(Lines); } public void actionPerformed( ActionEvent e ){ if( e.getSource() == startBtn ){ InitNewGame(); myPlayFieldCanvas.RepaintPlayField();/// startThread(); startBtn.setEnabled(false); pauseBtn.setEnabled(true); } else if (e.getSource() == pauseBtn ){ if (GamePaused) { myPlayFieldCanvas.RepaintPlayField(); } GamePaused = !GamePaused; } requestFocus( ); } // get the players movement from the key pad public void keyPressed( KeyEvent e ){ int xChange = 0; int yChange = 0; boolean Rotate = false; // get the arror keys if( e.getKeyCode() == KeyEvent.VK_LEFT ) xChange--; else if( e.getKeyCode() == KeyEvent.VK_RIGHT ) xChange++; else if( e.getKeyCode() == KeyEvent.VK_DOWN ) yChange++; else if( e.getKeyCode() == KeyEvent.VK_UP ) Rotate = true; ChangeShapePosition (xChange, yChange, Rotate); } // } public void keyReleased( KeyEvent e ){ } public void keyTyped( KeyEvent e ){ int xChange = 0; int yChange = 0; boolean Rotate = false; // get the as & z keys if( e.getKeyChar()== 'a' || e.getKeyChar()== 'A') xChange--; else if( e.getKeyChar()== 's' || e.getKeyChar()== 'S') xChange++; else if( e.getKeyChar()== 'z' || e.getKeyChar()== 'Z') Rotate = true; else if( e.getKeyChar()== ' ') yChange++; // showStatus( "hey " + e.getKeyChar( ) ); ChangeShapePosition (xChange, yChange, Rotate); } // make changes depending on the players input public void ChangeShapePosition(int xChange, int yChange, boolean Rotate) { while (!FallingShape.IsReady()) ; if (FallingShape.CheckIfShapeFits(PlayField, xChange, yChange, Rotate)) { FallingShape.ChangePosition(xChange, yChange, Rotate); myPlayFieldCanvas.repaint(FallingShape); } }} class Stats extends Canvas implements ImageObserver // keep the stats of the game // from score to speed of the dropping element { public static final Color textColor = Color.black; public static final int MaxLevel = 9; public static final int myFontHeight = 16; private int hiScore = 0; protected Font BlocksFont; protected FontMetrics BlocksFontMetrics; protected int Level, Lines, Score; protected Shape NextShape = null; public void InitNewGame() { Level = Lines = Score = 0; } public void GameOver() { if( Score > hiScore ) hiScore = Score; } public int GetGameSpeed() { switch (Level) { case 0: return 225; case 1: return 200; case 2: return 175; case 3: return 300; case 4: return 140; case 5: return 130; case 6: return 125; case 7: return 120; case 8: return 110; case 9: return 50; default: return 100; } } public Stats() { reshape(0, 0, 100, 100); BlocksFont = new Font("TimesRoman",Font.PLAIN,20); setFont(BlocksFont); BlocksFontMetrics = getFontMetrics(BlocksFont); InitNewGame(); } public void AddScore(int s) { Score += s; repaint(); } public void AddLines(int ln) { switch (ln) { case 1: AddScore (25); break; case 2: AddScore (100); break; case 3: AddScore (250); break; case 4: AddScore (1000); break; } Lines += ln; if (Lines > (3* (Level + 1))) AddLevel(); repaint(); } public void AddLevel() { Blocks.play (Blocks.SOUND_NEXTLEVEL); if (Level < MaxLevel) Level++; repaint(); } public void DisplayNextShape(Shape s) { NextShape = s; repaint(); } public void paint(Graphics g) { g.setColor(textColor); g.drawString(" Level: " + Level, 0, myFontHeight); g.drawString(" Lines: " + Lines, 0, myFontHeight * 3); g.drawString(" Score: " + Score, 0, myFontHeight * 5); if(Score > hiScore) hiScore = Score; g.drawString(" High Score: " + hiScore, 0, myFontHeight * 7 ); g.drawString(" Next:", 0, myFontHeight * 9); if (NextShape != null) { NextShape.DisplayAbs(g, 10, myFontHeight * 9 + 10); } }} // class canvas starts here // create the playing field class CanvasField extends Canvas implements ImageObserver { public static final int fh1 = 17, fh2 = 17; public static final int BorderWidth = 5; public static final Color BorderColor = Color.blue; protected Shape FallingShape = null; boolean FallingShapeNeedRepaint = false; boolean PlayFieldNeedRepaint = false; boolean DiscardGame = false; protected Font BlocksFont1, BlocksFont2; Color PlayField[][] = null; public void GameOver() { DiscardGame = true; repaint(); } public void RepaintPlayField() { PlayFieldNeedRepaint = true; repaint(); } public void SetPlayField(Color pv[][]) { PlayField = pv; } public CanvasField() { BlocksFont1 = new Font("TimesRoman",Font.BOLD,20); FontMetrics BlocksFontMetrics1 = getFontMetrics(BlocksFont1); BlocksFont2 = new Font("TimesRoman",Font.PLAIN,14); FontMetrics BlocksFontMetrics2 = getFontMetrics(BlocksFont2); reshape(0, 0, Blocks.ElementSize * Blocks.cols + BorderWidth * 2, Blocks.ElementSize * Blocks.rows + BorderWidth ); } public void repaint(Shape Shp) { FallingShape = Shp; FallingShapeNeedRepaint = true; repaint(); } public void DrawLines (Graphics g, int y1, int y2) { for (int y = y1 * Blocks.ElementSize; y < y2 * Blocks.ElementSize; y++) { g.drawLine (BorderWidth, y, BorderWidth + Blocks.cols * Blocks.ElementSize, y); } } public void GraphicsEffect(Graphics g, int y1, int y2) { for (int l = 0; l < 10; l++) { g.setColor(Color.red); DrawLines (g, y1, y2); g.setColor(Color.green); DrawLines (g, y1, y2); g.setColor(Color.blue); DrawLines (g, y1, y2); g.setColor(Color.black); DrawLines (g, y1, y2); } } public void DiscardIt(Graphics g) { DiscardGame = false; GraphicsEffect (g, 0, Blocks.rows); } public void update(Graphics g) { if (DiscardGame) { DiscardIt(g); } if (PlayFieldNeedRepaint) { DrawPlayField(g); } DrawFallingShape(g); } public void paint(Graphics g) { DrawPlayField(g); FallingShapeNeedRepaint = true; DrawFallingShape(g); } public void DrawFallingShape(Graphics g) { if (FallingShapeNeedRepaint && FallingShape != null) { FallingShape.hide(g, BorderWidth); while (!FallingShape.IsReady()) ; FallingShape.Display(g, BorderWidth); FallingShapeNeedRepaint = false; } } public void DrawPlayField(Graphics g) { int x, y; g.setColor(BorderColor); // Draw left border g.fillRect (0, 0, BorderWidth, Blocks.ElementSize * Blocks.rows); // Draw right border g.fillRect (Blocks.ElementSize * Blocks.cols + BorderWidth, 0, BorderWidth, Blocks.ElementSize * Blocks.rows); // Draw bottom border g.fillRect (0, Blocks.ElementSize * Blocks.rows, Blocks.ElementSize * Blocks.cols + BorderWidth * 2, BorderWidth); for (x = 0; x < Blocks.cols; x++) { for (y = 0; y < Blocks.rows; y++) { if (PlayField[x][y] != Color.black) { g.setColor(PlayField[x][y]); g.fillRect(BorderWidth + x * Blocks.ElementSize + 1, y * Blocks.ElementSize + 1, Blocks.ElementSize - 2, Blocks.ElementSize - 2); g.setColor(Color.white); g.drawRect(BorderWidth + x * Blocks.ElementSize, y * Blocks.ElementSize, Blocks.ElementSize - 1, Blocks.ElementSize - 1); } else { g.setColor(Color.black); g.fillRect(BorderWidth + x * Blocks.ElementSize, y * Blocks.ElementSize, Blocks.ElementSize, Blocks.ElementSize); }} } PlayFieldNeedRepaint = false; }} // class element starts here // create the game play from dropping element to size etc class Element { protected int x, y; int oldX, oldY; protected int xInShape, yInShape; protected int OriginalX, OriginalY; protected int OriginalXInShape, OriginalYInShape; protected Color clr; protected boolean ErasePossible; public Element(int xPos, int yPos, Color c) { ErasePossible = false; xInShape = OriginalXInShape = xPos; yInShape = OriginalYInShape = yPos; x = OriginalX = xPos + Blocks.cols / 2 - (Blocks.MaxElement + 1)/ 2; y = OriginalY = yPos; clr = c; } public void Init() { ErasePossible = false; x = OriginalX; y = OriginalY; xInShape = OriginalXInShape; yInShape = OriginalYInShape; } public void hide (Graphics g, int xOffs, int yOffs) { if (ErasePossible) { int Size = Blocks.ElementSize; g.setColor(Color.black); g.fillRect(xOffs + oldX * Size, yOffs + oldY * Size, Size, Size); ErasePossible = false; } } public void Display (Graphics g, int xOffs, int yOffs) { int Size = Blocks.ElementSize; g.setColor(clr); g.fillRect(xOffs + x * Size + 1, yOffs + y * Size + 1, Size - 2, Size - 2); g.setColor(Color.white); g.drawRect(xOffs + x * Size, yOffs + y * Size, Size - 1, Size - 1); oldX = x; oldY = y; ErasePossible = true; } public void DisplayAbs (Graphics g, int xOffs, int yOffs) { int Size = Blocks.ElementSize; g.setColor(clr); g.fillRect(xOffs + OriginalXInShape * Size + 1, yOffs + OriginalYInShape * Size + 1, Size - 2, Size - 2); g.setColor(Color.white); g.drawRect(xOffs + OriginalXInShape * Size, yOffs + OriginalYInShape * Size, Size - 1, Size - 1); } public boolean CheckIfElementFits(Color PlayField[][], int xOffs, int yOffs, boolean Rotate) { if (Rotate) { xOffs += Blocks.MaxElement - yInShape - xInShape; yOffs += xInShape - yInShape; } if (x + xOffs < 0 || x + xOffs >= Blocks.cols) return false; if (y + yOffs >= Blocks.rows ) return false; if (PlayField[x + xOffs][y + yOffs] != Color.black) return false; return true; } public void ChangeElementPosition(int xOffs, int yOffs, boolean Rotate) { if (Rotate) { xOffs += Blocks.MaxElement - yInShape - xInShape; yOffs += xInShape - yInShape; int tempxInShape = xInShape; xInShape = Blocks.MaxElement - yInShape; yInShape = tempxInShape; } x += xOffs; y += yOffs; } public int GetXPos() { return x; } public int GetYPos() { return y; } public Color GetColor() { return clr; } } class Shape { protected Vector Elements; protected int Value; protected boolean DrawReady = true; public Shape() { DrawReady = true; } public void Init() { DrawReady = true; Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement = (Element) Elements.elementAt(ix); WalkElement.Init(); }} public Shape(int a, int b, int c, int d, Color clr, int v) { Value = v; Elements = new Vector(); AddElements(0, a, clr); AddElements(1, b, clr); AddElements(2, c, clr); AddElements(3, d, clr); Init(); } protected void AddElements (int row, int a, Color clr) { if ((a & 0xf000) > 0) Elements.addElement (new Element(0, row, clr)); if ((a & 0x0f00) > 0) Elements.addElement (new Element(1, row, clr)); if ((a & 0x00f0) > 0) Elements.addElement (new Element(2, row, clr)); if ((a & 0x000f) > 0) Elements.addElement (new Element(3, row, clr)); } public void hide (Graphics g, int xOffs) { Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement = (Element) Elements.elementAt(ix); WalkElement.hide(g, xOffs, 0); } } public void Display (Graphics g, int xOffs) { Element WalkElement; DrawReady = false; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement = (Element) Elements.elementAt(ix); WalkElement.Display(g, xOffs, 0); } DrawReady = true; } public void DisplayAbs (Graphics g, int xAbs, int yAbs) { Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement = (Element) Elements.elementAt(ix); WalkElement.DisplayAbs(g, xAbs, yAbs); } } public boolean CheckIfShapeFits(Color PlayField[][], int xOffs, int yOffs, boolean Rotate) { Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement= (Element) Elements.elementAt(ix); if (!WalkElement.CheckIfElementFits (PlayField, xOffs, yOffs, Rotate)) return false; } return true; } public void ChangePosition(int xOffs, int yOffs, boolean Rotate) { Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement = (Element) Elements.elementAt(ix); WalkElement.ChangeElementPosition(xOffs, yOffs, Rotate); } } public void PlaceInPlayField(Color PlayField[][]) { Element WalkElement; for (int ix = 0; ix < Elements.size(); ix++) { WalkElement= (Element) Elements.elementAt(ix); PlayField[WalkElement.GetXPos()] [WalkElement.GetYPos()] = WalkElement.GetColor(); } } public int GetValue() { return Value; } public boolean IsReady() { return DrawReady; } }