/* * Copyright © 2011 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.racer.views; import com.nokia.example.racer.helpers.ImageLoader; import com.nokia.example.racer.helpers.SimpleThread; import com.nokia.example.racer.helpers.Engine; import com.nokia.example.racer.views.components.Track; import com.nokia.example.racer.views.tracks.LapListener; import com.nokia.example.racer.views.tracks.Monza; import javax.microedition.lcdui.game.GameCanvas; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.game.Sprite; public class GameView extends GameCanvas implements LapListener { private static final int MAX_SPEED = 12; private Timer mTimer; private Timer raceTimer; private TimerTask clock; private long currentLap = 0; private long bestLap = 0; private long latestLap = 0; private Graphics g; private int trackX = 0; private int trackY = 0; protected int speed = 2; private int surfaceMultiplier = 0; protected int friction = 2; private int x_increment = 0; private int y_increment = 0; private int carXPosition = 72; private int carYPosition = 160; private int currentFrame = 0; private int lastFrame = 0; private int curRed = 0; private int curGreen = 0; private int curBlue = 0; private double[] sins; private double[] coss; private int turnYposition = -80; private Image turnHelp; private Image topBar; private Image speedMeter; private Image startInfo; private Track track; private Sprite carSprite; private Sprite countDown; private Sprite speedNeedle; private boolean showInstructions = false; private boolean stopped = true; private boolean applyGas = false; private boolean turnLeft = false; private boolean turnRight = false; private Engine engine = new Engine(); private SimpleThread gateKeeper; private SimpleThread gameLogic; private Thread countdownThread; private int pauseCounter = 0; private String error = ""; private Font smallFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_ITALIC, Font.SIZE_SMALL); private Font bigFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_ITALIC, Font.SIZE_LARGE); public GameView() { super(false); setFullScreenMode(true); loadGraphics(); preCalculate(); engine.start(); } private void loadGraphics() { try { ImageLoader loader = ImageLoader.getInstance(); carSprite = new Sprite(loader.loadImage("/car_sprite.png"), 64, 64); carSprite.setRefPixelPosition(32, 32); carSprite.setPosition(carXPosition, carYPosition); carSprite.setFrame(currentFrame); turnHelp = loader.loadImage("/turn_help.png"); countDown = new Sprite(loader.loadImage("/countdown_240x121.png"), 240, 121); countDown.setPosition(0, 100); countDown.setFrame(0); speedMeter = loader.loadImage("/speedo.png"); topBar = loader.loadImage("/top_bar.png"); speedNeedle = new Sprite(loader.loadImage("/speed_sprite_46x46.png"),46,46); speedNeedle.setFrame(0); speedNeedle.setPosition(190, 265); startInfo = loader.loadImage("/press_info.png"); } catch (IOException e) { e.printStackTrace(); } } private void preCalculate() { //calculate angles sins = new double[24]; coss = new double[24]; for (int i = 0; i < 24; i++) { int angle = 15 * i; sins[i] = Math.sin(Math.toRadians(angle)); coss[i] = Math.cos(Math.toRadians(angle)); } } public void showNotify() { if(track == null) { setTrack(new Monza(this)); } mTimer = new Timer(); g = getGraphics(); TimerTask ui = new TimerTask() { public void run() { render(g); flushGraphics(); } }; gameLogic = new SimpleThread(40) { public void execute() { if (!stopped) { calculateX(); calculateY(); checkSurface(); handleInstructions(); } } }; TimerTask speedUpdate = new TimerTask() { public void run() { int frame = lastFrame; updateForce(frame); lastFrame = currentFrame; } }; TimerTask keyturning = new TimerTask() { public void run() { if (turnRight) { turnRight(); } else if (turnLeft) { turnLeft(); } } }; gateKeeper = new SimpleThread(40) { public void execute() { track.checkGatePass((-trackX) + (carXPosition + 32), (-trackY) + (carYPosition + 32)); } }; gameLogic.start(); gateKeeper.start(); mTimer.schedule(ui, 0, 40); mTimer.schedule(speedUpdate, 0, 200); mTimer.schedule(keyturning, 0, 100); raceTimer = new Timer(); clock = new TimerTask() { public void run() { currentLap += 10; } }; countdownThread = new Thread() { public void run() { try { countDown.setFrame(0); pauseCounter = 1; Thread.sleep(1000); countDown.nextFrame(); pauseCounter = 2; Thread.sleep(1000); countDown.nextFrame(); pauseCounter = 3; Thread.sleep(1000); countDown.nextFrame(); Thread.sleep(700); stopped = false; raceTimer.scheduleAtFixedRate(clock, 10, 10); } catch (InterruptedException ie) { } } }; countdownThread.start(); engine.on(); } protected void hideNotify() { countdownThread.interrupt(); mTimer.cancel(); raceTimer.cancel(); gateKeeper.stop(); gameLogic.stop(); engine.off(); stopped = true; } public void reset() { this.carXPosition = track.getCarXPosition(); this.carYPosition = track.getCarYPosition(); this.trackX = track.getStartX(); this.trackY = track.getStartY(); currentFrame = track.getCarStartFrame(); carSprite.setFrame(currentFrame); speed = 2; x_increment = 0; y_increment = 0; currentLap = 0; bestLap = 0; latestLap = 0; track.resetLaps(); track.resetPosition(); } private void render(Graphics g) { int anchor = g.TOP | g.LEFT; g.setColor(0xFFFFFF); g.fillRect(0, 0, getWidth(), getHeight()); carSprite.setPosition(carXPosition, carYPosition); track.setPosition(trackX, trackY); track.render(g); carSprite.paint(g); g.drawImage(turnHelp, 0, turnYposition, anchor); if (stopped) { g.drawImage(startInfo, 0, 66, anchor); countDown.paint(g); } g.drawImage(speedMeter, 240, 320, g.BOTTOM | g.RIGHT); g.drawImage(topBar, 0, 0, g.TOP|g.LEFT); speedNeedle.paint(g); g.setFont(bigFont); g.drawString(track.getLaps()+"", 100,0, anchor); g.setFont(smallFont); g.drawString((currentLap / 1000)+":"+(currentLap % 1000) + ":"+ (currentLap % 100), 177, 0, anchor); g.drawString((bestLap / 1000)+":"+(bestLap % 1000) + ":" + (bestLap % 100), 177, 12, anchor); //drawDebugData(g); } private void drawDebugData(Graphics g) { int anchor = g.TOP | g.LEFT; g.setColor(0xFF0000); g.drawString("x_increment:" + x_increment, 0, 0, anchor); g.drawString("y_increment:" + y_increment, 0, 25, anchor); g.drawString("speed:" + speed, 0, 50, anchor); g.drawString("bestLap:" + bestLap, 0, 70, anchor); g.drawString("LatestLap:" + latestLap, 0, 90, anchor); g.drawString("currentLap:" + currentLap, 0, 110, anchor); g.drawString("laps:" + track.getLaps(), 0, 150, anchor); g.drawString("counter:" + pauseCounter, 0, 130, anchor); g.drawString(error, 0, 170, anchor); } private void updateForce(int frame) { if (frame == -1) { frame = currentFrame; } if (applyGas) { if (speed < MAX_SPEED) { speed += 1; } } else if (!applyGas && speed > friction) { speed -= 2; } int speedCalc = ((speed + surfaceMultiplier) - friction); if (speedCalc < 0) { speedCalc = 0; } y_increment = (int) (speedCalc * coss[frame]); x_increment = (int) (speedCalc * sins[frame]); if(speed >= 0 && speed <= 12) { int s = speed - 1; if(s < 0) s = 0; if(!applyGas && speed == friction) s = 0; speedNeedle.setFrame(s); } } private void calculateX() { int trackXAbs = Math.abs(trackX); if (trackXAbs >= (track.getWidth() - 240)) { if (carXPosition < 176 && carXPosition < 220 && x_increment > 0) { carXPosition += x_increment; } else if (carXPosition >= 144 && x_increment < 0) { carXPosition += x_increment; } else if (carXPosition <= 144 && x_increment < 0) { trackX -= x_increment; } } else if (trackX >= 0) { if (carXPosition >= 0 && x_increment < 0) { carXPosition += x_increment; } else if ((carXPosition < 72 && carXPosition > 0) && x_increment < 0) { carXPosition += x_increment; } else if (x_increment > 0 && carXPosition < 72) { carXPosition += x_increment; } else if (carXPosition >= 72 && x_increment > 0) { trackX -= x_increment; } } else { trackX -= x_increment; } } private void calculateY() { if (trackY <= -(track.getHeight() - 320)) { if (carYPosition >= 244 && carYPosition <= 256) { carYPosition += -y_increment; } else if (carYPosition < 244 && y_increment < 0) { carYPosition += -y_increment; } else if (carYPosition <= 244 && y_increment > 0) { trackY += y_increment; } } else if (trackY >= 0) { if (carYPosition >= 0 && carYPosition < 96) { carYPosition += -y_increment; } else if (carYPosition >= 96 && y_increment < 0) { trackY += y_increment; } else if (carYPosition >= 0 && y_increment > 0) { carYPosition -= y_increment; } } else { trackY += y_increment; } if (carYPosition < 0) { carYPosition = 0; } if (carYPosition > 256) { carYPosition = 256; } } private void checkSurface() { int[] rgb = new int[1]; int absX = (trackX < 0) ? -trackX : trackX; int absY = (trackY < 0) ? -trackY : trackY; track.getTrackImage().getRGB(rgb, 0, 1, absX + carXPosition + 32, absY + carYPosition + 32, 1, 1);//32 is the half of car images width and height int currentRGB = rgb[0];//rgb is in format 0xAARRGGBB where AA is alpha channel values //check if the values of rgb are greater than int red = (currentRGB & 0x00FF0000) >> 16; int green = (currentRGB & 0x0000FF00) >> 8; int blue = (currentRGB & 0x000000FF); curRed = red; curGreen = green; curBlue = blue; if (red > 70 && green > 70 && blue > 70) { surfaceMultiplier = -2; } else { surfaceMultiplier = 0; } } protected void turnLeft() { lastFrame = currentFrame; if (currentFrame == 0) { currentFrame = 23; } else { currentFrame--; } carSprite.setFrame(currentFrame); } protected void turnRight() { lastFrame = currentFrame; if (currentFrame == 23) { currentFrame = 0; } else { currentFrame++; } carSprite.setFrame(currentFrame); } protected void keyPressed(int keyCode) { switch (keyCode) { case GameCanvas.KEY_NUM7: applyGas = true; engine.accelerate(); break; case GameCanvas.KEY_NUM0: if (showInstructions) { showInstructions = false; } else { showInstructions = true; } break; case GameCanvas.KEY_NUM4: //turn left turnLeft = true; break; case GameCanvas.KEY_NUM6: //turn right turnRight = true; break; } } protected void keyReleased(int keyCode) { switch (keyCode) { case GameCanvas.KEY_NUM7: applyGas = false; engine.decelerate(); break; case GameCanvas.KEY_NUM4: turnLeft = false; break; case GameCanvas.KEY_NUM6: turnRight = false; break; } } public void lapDriven(int laps) { latestLap = currentLap; currentLap = 0; synchronized(this) { raceTimer.cancel(); raceTimer = new Timer(); clock = new TimerTask() { public void run() { currentLap += 10; } }; raceTimer.scheduleAtFixedRate(clock, 10, 10); } if (latestLap < bestLap || bestLap == 0) { bestLap = latestLap; } } public void setTrack(Track track) { this.track = null; this.track = track; this.carXPosition = track.getCarXPosition(); this.carYPosition = track.getCarYPosition(); this.trackX = track.getStartX(); this.trackY = track.getStartY(); currentFrame = track.getCarStartFrame(); carSprite.setFrame(currentFrame); } public void cleanTrackResources() { track = null; System.gc(); } private void handleInstructions() { if (showInstructions) { if (turnYposition < 38) { turnYposition += 5; } } else { if (turnYposition > -120) { turnYposition -= 5; } } } }