/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package tc.samples.game.scape; import totalcross.game.*; import totalcross.io.ByteArrayStream; import totalcross.io.IOException; import totalcross.sys.*; import totalcross.ui.Container; import totalcross.ui.MainWindow; import totalcross.ui.dialog.MessageBox; import totalcross.ui.event.*; import totalcross.ui.gfx.Color; import totalcross.ui.gfx.Graphics; import totalcross.ui.image.Image; import totalcross.ui.image.ImageException; import totalcross.ui.media.*; import totalcross.util.Properties; /** * Scape game */ public class Scape extends GameEngine implements ProdConfig { protected final static boolean ARCADE_GAME = true; protected final static boolean CLEAR_SCREEN = true; protected final static boolean SPRITE_BKGD_SAVING = false; protected final static boolean HAS_UI = false; protected final static int BLOCKS = 4; protected final static int RADIUS = Settings.screenWidth/2; protected final static int PEN_OFFSET = 24; protected final static int MAX_DIFFICULTIES = 3; // Increase the game level each time the scores is a multiple of 128 private final static int SCORE_NEXT_LEVEL = (128 - 1); // Ball speed increase of 10% at each level private final static int SPEED_INCR_PERC = 10; // Racket move speed when controlled with the keyboard private final static int BLOCK_SPEED_PERC1000 = 22; // reduce the game playground to display the game level and score protected static int miny; protected static int maxw, maxh; protected static int borderWidth = 2; protected static int blockSizePerc = 24; protected static int moveDist; private int midx, midy; // game level & score private int level, score; // sound support version private static MediaClip lostClip; // define the game sprites private Block blocks[]; private Ball ball; // 2 text renderers to quickly display level and score values private TextRenderer levelRenderer; private TextRenderer scoreRenderer; // define 2 game settings, // by declaring them static they can be accessed in all classes. protected static Properties.Boolean optSound; protected static Properties.Int optDifficulty; // the high scores and settings Options settings; protected static Scape game; public Scape() { setUIStyle(Settings.Android); // adjust attributes gameName = "Scape"; // when not run on device, appCreatorId does not always return the same value. gameCreatorID = !Settings.onJavaSE ? totalcross.sys.Settings.applicationId : PC_CREATOR_ID; gameVersion = 100; gameHighscoresSize = 0; gameRefreshPeriod = ARCADE_GAME ? (Settings.keyboardFocusTraversable?100:100) : NO_AUTO_REFRESH; gameDoClearScreen = CLEAR_SCREEN; gameHasUI = HAS_UI; setBackColor(0x66FFFF); MainWindow.setDefaultFont(font.asBold()); game = this; } public void onOtherEvent(Event evt) { if (evt.type == MediaClipEvent.END_OF_MEDIA) showIntroduction(); } public void onGameInit() { // access the game settings settings = getOptions(); // if the properties do not yet exist, use the specified default values optSound = settings.declareBoolean("sound", false); optDifficulty = settings.declareInteger("difficulty", 0); try { levelRenderer = createTextRenderer(getFont(), Color.BLACK, "level: ", 2, false); scoreRenderer = createTextRenderer(getFont(), Color.BLACK, "score: ", 5, true); } catch (ImageException e) { MessageBox.showException(e,true); } // set the screen dimensions maxw = Settings.screenWidth; maxh = Settings.screenHeight; // keyboard moves distance moveDist = maxw / 20; midx = maxw >> 1; midy = maxh >> 1; miny = scoreRenderer.getHeight() + 2; maxh -= miny; frameSizes = new int[MAX_DIFFICULTIES]; for (int i = 0; i < MAX_DIFFICULTIES; i++) { frameSizes[i] = maxw * i / 16; } // this is the hunted object try {ball = new Ball();} catch (ImageException e) {} catch (IOException e) {} try { lostClip = new MediaClip(new ByteArrayStream(Vm.getFile("tc/samples/game/scape/lost.wav"))); } catch (IOException e) { MessageBox.showException(e, true); } showIntroduction(); } private static int frameSizes[]; public void onGameStart() { if (blocks == null) try { Image blockImg; try {blockImg = new Image("tc/samples/game/scape/block.png");} catch (Exception e) {blockImg = new Image(40,40);} int baseSize = Math.min(maxw, maxh); int blockSize = baseSize * blockSizePerc / 100; int speed = baseSize * BLOCK_SPEED_PERC1000 / 1000; // these are the hunting blocks blocks = new Block[BLOCKS]; for (int i = 0; i < BLOCKS; i++) { int q = (i << 1) + 1; int vecx = (int) (RADIUS * Math.cos(2 * Math.PI * q / (BLOCKS << 1))); int vecy = (int) (RADIUS * Math.sin(2 * Math.PI * q / (BLOCKS << 1))); int xx = (int) (midx + vecx); int yy = (int) (midy + vecy); // 14, 26, 46, 62 // 62, 46, 26, 14 int bs4 = blockSize >> 2; int sx = bs4 + i * bs4; int sy = bs4 + bs4 * (BLOCKS - 1 - i); blocks[i] = new Block(speed, xx, yy, vecx < 0 ? -1 : 1, vecy < 0 ? -1 : 1, blockImg.getHwScaledInstance(sx, sy), ball); } } catch (ImageException e) { MessageBox.showException(e,true); } ball.reduceZone(frameSizes[optDifficulty.value]); for (int i = 0; i < BLOCKS; i++) { blocks[i].reinit(); } ball.place(midx, midy, false); level = 1; score = 0; } public void onGameStop() { if (Scape.optSound.value) { if (lostClip != null) { try { lostClip.start(); } catch (IOException e) { MessageBox.showException(e, true); } if (!Settings.onJavaSE) return; // showIntroduction will be displayed when the sound stops - in Java, stop is never called } } // when the game stops, popup the GameOver window showIntroduction(); } private boolean setcolor; public final void onPaint(Graphics gfx) { if (gameIsRunning) { if (!setcolor) { setcolor = true; gfx.foreColor = 0x0000FF; } for (int i = borderWidth; i >= 1; i--) { int o = i + frameSizes[optDifficulty.value]; int w = o << 1; gfx.drawRect(o, miny + o, maxw - w, maxh - w); } for (int i = 0; i < BLOCKS; i++) { Block b = blocks[i]; b.move(); b.show(); } ball.show(); score++; // Increase the game level each time the scores is a multiple of SCORE_NEXT_LEVEL if ((score & SCORE_NEXT_LEVEL) == 0) { // increase the level and the ball speed level++; for (int i = 0; i < BLOCKS; i++) blocks[i].increaseSpeed(SPEED_INCR_PERC); } // render level & score levelRenderer.display(16, 2, level); scoreRenderer.display(Settings.screenWidth >> 1, 2, score); } } public final void onPenDown(PenEvent evt) { if (!ball.place(evt.x - PEN_OFFSET, evt.y - PEN_OFFSET, true)) stop(); // if non arcade game is selected, redrawings have to be called explicitly if (!ARCADE_GAME) refresh(); } public final void onPenDrag(PenEvent evt) { if (!ball.place(evt.x - PEN_OFFSET, evt.y - PEN_OFFSET, true)) stop(); // if non arcade game is selected, redrawings have to be called explicitly if (!ARCADE_GAME) refresh(); } Container blankContainer; /** Creates and places a blank container in the screen. */ public void blankScreen() { if (blankContainer == null) { blankContainer = new Container(); blankContainer.setRect(getRect()); blankContainer.setBackColor(backColor); } swap(blankContainer); } /** * display the game introduction screen. */ public final void showIntroduction() { Introduction.swapTo(); } }