View Javadoc

1   package erland.game.tetris;
2   /*
3    * Copyright (C) 2003 Erland Isaksson (erland_i@hotmail.com)
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18   *
19   */
20  
21  import erland.game.GameEnvironmentInterface;
22  import erland.game.FpsCounter;
23  import erland.game.GamePanelInterface;
24  
25  import java.awt.event.KeyAdapter;
26  import java.awt.event.KeyEvent;
27  import java.awt.event.KeyListener;
28  import java.awt.*;
29  
30  public class TetrisMain implements GamePanelInterface {
31      private GameEnvironmentInterface environment;
32      private boolean bQuit;
33      private boolean cheatMode;
34      private KeyListener keyListener;
35      private FpsCounter fps;
36      /*** Container representing the game logo */
37      protected BlockContainerData titleContainer;
38      /*** Container representing the next block */
39      protected BlockContainerData previewContainer;
40  
41      /*** Size of the squares */
42      protected int squareSize;
43  
44      /*** Horizontal drawing offset */
45      protected int offsetX;
46      /*** Vertical drawing offset */
47      protected int offsetY;
48      /*** Number of pixels between squares */
49      protected int spaceBetweenSquares;
50      /*** Counter to handle blinking of text when game is completed or GAME OVER has occurred */
51      protected int endBlink;
52      /*** Speed of blinking text */
53      protected final int END_BLINK_SPEED=10;
54      /*** Object representing the tetris data model */
55      private TetrisModelInterface model;
56  
57      public TetrisMain(TetrisModelInterface model) {
58          this.model = model;
59      }
60      public boolean isExit() {
61          return bQuit;
62      }
63  
64      public void setCheatmode(boolean enable) {
65          cheatMode = enable;
66      }
67  
68      public void exit() {
69          environment.getScreenHandler().getContainer().removeKeyListener(keyListener);
70      }
71  
72      public void init(GameEnvironmentInterface environment) {
73          this.environment = environment;
74          bQuit = false;
75          cheatMode = false;
76  
77          keyListener = new KeyAdapter() {
78              public void keyPressed(KeyEvent e) {
79                  if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
80                      bQuit = true;
81                  }else if(e.getKeyCode() == KeyEvent.VK_LEFT) {
82                      model.moveLeft();
83                  }else if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
84                      model.moveRight();
85                  }else if(e.getKeyCode() == KeyEvent.VK_UP) {
86                      model.rotate();
87                  }else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
88                      model.moveDown();
89                  }else if(e.getKeyCode()==e.VK_SPACE) {
90  				    newGame();
91  			    }
92              }
93          };
94          environment.getScreenHandler().getContainer().setCursor(null);
95          environment.getScreenHandler().getContainer().requestFocus();
96          environment.getScreenHandler().getContainer().addKeyListener(keyListener);
97          environment.getScreenHandler().getContainer().setBackground(Color.black);
98          fps = new FpsCounter(60);
99  
100         previewContainer = new BlockContainerData(4,2);
101         titleContainer = new BlockContainerData(34,5);
102         titleContainer.clear();
103         makeTitle(titleContainer);
104         this.offsetX = 20;
105         this.offsetY = 20;
106         this.squareSize = 13;
107         this.spaceBetweenSquares = 1;
108         init();
109         model.init(environment);
110     }
111 
112     /***
113      * Initialize a new game
114      */
115     protected void init()
116     {
117         endBlink=0;
118     }
119 
120     /***
121      * Start a new game, this will only succeed if there is not a game already running
122      */
123     public void newGame()
124     {
125         if(model.isEnd() || !model.isStarted()) {
126             model.startGame();
127         }
128     }
129 
130     /***
131      * Draw the tetris logo in the specied BlockMatrix
132      * @param m The BlockMatrix to draw the logo in
133      */
134     protected void makeTitle(BlockMatrix m) {
135         //XXXXX-XXXXX-XXXX----X----XXXX
136         //X-------X---X---X---X---X----
137         //XXXX----X---XXXX----X----XXX-
138         //X-------X---X--X----X-------X
139         //XXXXX---X---X---X---X---XXXX-
140 
141         Color c = Color.red;
142         // "E"
143         m.setUsed(6,0,c);
144         m.setUsed(7,0,c);
145         m.setUsed(8,0,c);
146         m.setUsed(9,0,c);
147         m.setUsed(10,0,c);
148         m.setUsed(6,1,c);
149         m.setUsed(6,2,c);
150         m.setUsed(7,2,c);
151         m.setUsed(8,2,c);
152         m.setUsed(9,2,c);
153         m.setUsed(6,3,c);
154         m.setUsed(6,4,c);
155         m.setUsed(7,4,c);
156         m.setUsed(8,4,c);
157         m.setUsed(9,4,c);
158         m.setUsed(10,4,c);
159         // "T"
160         m.setUsed(12,0,c);
161         m.setUsed(13,0,c);
162         m.setUsed(14,0,c);
163         m.setUsed(15,0,c);
164         m.setUsed(16,0,c);
165         m.setUsed(14,1,c);
166         m.setUsed(14,2,c);
167         m.setUsed(14,3,c);
168         m.setUsed(14,4,c);
169         // "R"
170         m.setUsed(18,0,c);
171         m.setUsed(18,1,c);
172         m.setUsed(18,2,c);
173         m.setUsed(18,3,c);
174         m.setUsed(18,4,c);
175         m.setUsed(19,0,c);
176         m.setUsed(20,0,c);
177         m.setUsed(21,0,c);
178         m.setUsed(22,1,c);
179         m.setUsed(19,2,c);
180         m.setUsed(20,2,c);
181         m.setUsed(21,2,c);
182         m.setUsed(21,3,c);
183         m.setUsed(22,4,c);
184         // "I"
185         m.setUsed(25,0,c);
186         m.setUsed(25,1,c);
187         m.setUsed(25,2,c);
188         m.setUsed(25,3,c);
189         m.setUsed(25,4,c);
190         // "S"
191         m.setUsed(30,0,c);
192         m.setUsed(31,0,c);
193         m.setUsed(32,0,c);
194         m.setUsed(33,0,c);
195         m.setUsed(29,1,c);
196         m.setUsed(30,2,c);
197         m.setUsed(31,2,c);
198         m.setUsed(32,2,c);
199         m.setUsed(33,3,c);
200         m.setUsed(29,4,c);
201         m.setUsed(30,4,c);
202         m.setUsed(31,4,c);
203         m.setUsed(32,4,c);
204     }
205 
206     public void update() {
207         fps.update();
208         model.update();
209     }
210 
211     public void draw() {
212         Graphics g = environment.getScreenHandler().getCurrentGraphics();
213         g.setColor(Color.black);
214         g.clearRect(0,0,640,480);
215         if(cheatMode) {
216             fps.draw(g,Color.white,10,10);
217         }
218         BlockContainerData mainContainer1 = model.getMainContainer();
219         int rightColumnX = offsetX + mainContainer1.getWidth()*(squareSize+spaceBetweenSquares)+10;
220         int rightColumnX2 = 640-(offsetX + mainContainer1.getWidth()*(squareSize+spaceBetweenSquares) + 60);
221         int rightColumnY = offsetY;
222         drawContainer(g,mainContainer1,offsetX,offsetY, squareSize,spaceBetweenSquares,1,Color.blue,Color.darkGray);
223         if(model.isMultiplayer()) {
224             if(model.isOpponentConnected()) {
225                 drawContainer(g,model.getOpponentMainContainer(),640-(mainContainer1.getWidth()*(squareSize+spaceBetweenSquares)+offsetX),offsetY, squareSize,spaceBetweenSquares,1,Color.blue,Color.darkGray);
226             }else {
227                 drawContainer(g,model.getOpponentMainContainer(),640-(mainContainer1.getWidth()*(squareSize+spaceBetweenSquares)+offsetX),offsetY, squareSize,spaceBetweenSquares,1,Color.darkGray,Color.darkGray);
228             }
229         }
230         updatePreviewContainer();
231         drawContainer(g,previewContainer,offsetX + mainContainer1.getWidth()*(squareSize+spaceBetweenSquares)+10,rightColumnY, squareSize, spaceBetweenSquares,1,Color.blue,Color.darkGray);
232         drawContainer(g,titleContainer,rightColumnX,
233                         offsetY + mainContainer1.getHeight()*(squareSize+spaceBetweenSquares)-titleContainer.getHeight()*(squareSize/2+spaceBetweenSquares)-20,squareSize/2,spaceBetweenSquares,0,Color.blue,Color.black);
234         g.drawString("by Erland Isaksson",rightColumnX+147,offsetY + mainContainer1.getHeight()*(squareSize+spaceBetweenSquares));
235         rightColumnY += offsetY+previewContainer.getHeight()*(squareSize+spaceBetweenSquares)+20;
236         g.setColor(Color.white);
237         g.drawString("LEVEL: "+model.getLevel(),rightColumnX, rightColumnY);
238         if(model.isMultiplayer()) {
239             g.drawString("LEVEL: "+model.getOpponentLevel(),rightColumnX2, rightColumnY);
240         }
241         rightColumnY+=20;
242         g.drawString("HIGHSCORE:",rightColumnX+100, rightColumnY);
243         g.drawString(model.getHighScore(),rightColumnX+120,rightColumnY+20);
244         g.drawString("SCORE:",rightColumnX,rightColumnY);
245         if(model.isMultiplayer()) {
246             g.drawString("SCORE:",rightColumnX2,rightColumnY);
247         }
248         rightColumnY+=20;
249         g.drawString(model.getScore(),rightColumnX,rightColumnY);
250         if(model.isMultiplayer()) {
251             g.drawString(model.getOpponentScore(),rightColumnX2,rightColumnY);
252         }
253         rightColumnY+=20;
254         if(model.isEnd()) {
255             if(endBlink<END_BLINK_SPEED) {
256                 if(!model.isCompleted()) {
257                     g.drawString("GAME OVER", rightColumnX,rightColumnY);
258                     rightColumnY+=20;
259                     if(!model.isStarted()) {
260                         rightColumnY+=20;
261                         if(!model.isMultiplayer() || model.isOpponentConnected()) {
262                             g.drawString("Press space for new game", rightColumnX, rightColumnY);
263                         }else {
264                             g.drawString("Press space or wait for opponent", rightColumnX, rightColumnY);
265                         }
266                         rightColumnY+=20;
267                     }
268                 }else {
269                     g.drawString("* CONGRATULATIONS *", rightColumnX, rightColumnY);
270                     rightColumnY+=20;
271                     g.drawString(" You have finished ", rightColumnX, rightColumnY);
272                     rightColumnY+=20;
273                     g.drawString("     the game      ", rightColumnX, rightColumnY);
274                     rightColumnY+=20;
275                     if(!model.isStarted()) {
276                         rightColumnY+=20;
277                         if(!model.isMultiplayer() || model.isOpponentConnected()) {
278                             g.drawString("Press space for new game", rightColumnX, rightColumnY);
279                         }else {
280                             g.drawString("Press space or wait for opponent", rightColumnX, rightColumnY);
281                         }
282                         rightColumnY+=20;
283                     }
284 
285                 }
286                 endBlink++;
287             }else {
288                 if(endBlink<(2*END_BLINK_SPEED)) {
289                     endBlink++;
290                 }else {
291                     endBlink=0;
292                 }
293             }
294         }else if(!model.isStarted()) {
295             if(endBlink<END_BLINK_SPEED) {
296                 if(!model.isMultiplayer() || model.isOpponentConnected()) {
297                     g.drawString("Press space for new game",rightColumnX, rightColumnY);
298                 }else {
299                     g.drawString("Press space or wait for opponent",rightColumnX, rightColumnY);
300                 }
301                 rightColumnY+=20;
302                 endBlink++;
303             }else {
304                 if(endBlink<(2*END_BLINK_SPEED)) {
305                     endBlink++;
306                 }else {
307                     endBlink=0;
308                 }
309             }
310         }
311     }
312 
313     /***
314      * Draw all grapics in a specific BlockMatrix
315      * @param g The Graphics object to draw on
316      * @param m The BlockMatix object to draw
317      * @param offsetX The horisontal drawing offset
318      * @param offsetY The vertical drawing offset
319      * @param squareSize The size of each square in pixels
320      * @param spaceBetweenSquares Number of pixels between each square
321      * @param borderSize The size in pixels of the border around the drawn area
322      * @param borderColor The color of the border
323      * @param gridColor The color of the grid
324      */
325     protected void drawContainer(Graphics g, BlockMatrix m, int offsetX, int offsetY, int squareSize, int spaceBetweenSquares, int borderSize, Color borderColor, Color gridColor)
326     {
327         // Draw block container
328         if(borderSize>=0) {
329             g.setColor(borderColor);
330             g.fillRect(offsetX, offsetY, borderSize, (squareSize+spaceBetweenSquares)*m.getHeight()-spaceBetweenSquares+borderSize);
331             g.fillRect(offsetX, offsetY, (squareSize+spaceBetweenSquares)*m.getWidth()-spaceBetweenSquares+borderSize, borderSize);
332             g.fillRect(offsetX+borderSize+(squareSize+spaceBetweenSquares)*m.getWidth()-spaceBetweenSquares, offsetY,borderSize,(squareSize+spaceBetweenSquares)*m.getHeight()-spaceBetweenSquares+borderSize*2);
333             g.fillRect(offsetX, offsetY+borderSize+(squareSize+spaceBetweenSquares)*m.getHeight()-spaceBetweenSquares,(squareSize+spaceBetweenSquares)*m.getWidth()-spaceBetweenSquares+borderSize*2,borderSize);
334         }
335         if(spaceBetweenSquares>0) {
336             g.setColor(gridColor);
337             for(int x=1;x<m.getWidth();x++) {
338                 g.fillRect(offsetX + borderSize + x*(squareSize+spaceBetweenSquares)-spaceBetweenSquares,
339                             offsetY + borderSize,
340                             spaceBetweenSquares,
341                             m.getHeight()*(squareSize+spaceBetweenSquares)-spaceBetweenSquares);
342             }
343             for(int y=1;y<m.getHeight();y++) {
344                 g.fillRect(offsetX + borderSize,
345                             offsetY + borderSize + y*(squareSize+spaceBetweenSquares)-spaceBetweenSquares,
346                             m.getWidth()*(squareSize+spaceBetweenSquares)-spaceBetweenSquares,
347                             spaceBetweenSquares);
348             }
349         }
350         for(int x=0;x<m.getWidth();x++) {
351             for(int y=0;y<m.getHeight();y++) {
352                 if(m.isUsed(x,y)) {
353                     g.setColor(m.getColor(x,y));
354                     g.fillRect(offsetX +borderSize+ x*(squareSize+spaceBetweenSquares),offsetY +borderSize+ y*(squareSize+spaceBetweenSquares),squareSize, squareSize);
355                 }
356             }
357         }
358     }
359     protected void updatePreviewContainer() {
360         previewContainer.clear();
361         Block b = model.getNextBlock();
362         if(b!=null) {
363             b.init(1,0,0);
364             b.moveDown(previewContainer);
365         }
366     }
367 }