/* * Copyright © 2012 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.ghosts; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.midlet.MIDlet; /** * This class implements the game logic. * * This is a simple game where the player should shoot a ghost by moving the crosshair * over the screen and firing. The crosshair is controlled by an on-screen gamepad * which emulates an analog stick and fire button on multipoint touch-enabled Canvas. * Game records the score and high-score. * A progress bar is displayed, showing the remaining time before score reset. */ public class Scene extends Canvas { protected MIDlet midlet; private Image exitImage; private Image exitPressedImage; private Image shotImage; private Image missImage; private boolean exitButtonPointerDown = false; private Timer inactivityTimer; private Point firePosition = new Point(); private boolean shot = false; private boolean miss = false; private int level = 1; private int score = 0; private int hiScore = 0; private Font font; private Ghost ghost; private Crosshair crosshair; private Gamepad gamepad; public Scene(MIDlet midlet) { super(); this.setFullScreenMode(true); this.midlet = midlet; try { this.exitImage = Image.createImage("/images/Exit.png"); this.exitPressedImage = Image.createImage("/images/ExitPressed.png"); this.shotImage = Image.createImage("/images/Shot.png"); this.missImage = Image.createImage("/images/Miss.png"); Size sceneSize = new Size( this.getWidth(), this.getHeight() ); this.ghost = new Ghost(sceneSize); this.crosshair = new Crosshair(sceneSize); this.gamepad = new Gamepad(sceneSize); } catch (IOException e) { Display.getDisplay(this.midlet).setCurrent( new Alert("Cannot load graphics."), this ); e.printStackTrace(); } // Is used to draw score this.font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_MEDIUM); // The initial fire position this.firePosition = this.crosshair.getCrosshairPosition(); // The game's world clock this.inactivityTimer = new Timer(); this.inactivityTimer.schedule( new TimerTask() { // This timer method updates all parts of the game and repaints the game public void run() { // Update the ghost's clock boolean ghostRelocated = ghost.handleClockTick(); // Ghost wasn't hit, and it was relocated, that means the player failed if (!shot && ghostRelocated) { // Reset game score = 0; level = 0; } if (ghostRelocated) { shot = false; miss = false; level++; } // Update crosshair position crosshair.handleClockTick(gamepad.getAnalogStickPosition()); repaint(); } }, 0, 20 ); } protected void paint(Graphics graphics) { // Black background graphics.setColor(0x000000); graphics.fillRect(0, 0, this.getWidth(), this.getHeight()); // Draw the ghost this.ghost.paint(graphics); // Draw the shot image if (this.shot) { graphics.drawImage( this.shotImage, this.firePosition.x, this.firePosition.y, Graphics.HCENTER | Graphics.VCENTER ); } if (this.miss) { graphics.drawImage( this.missImage, this.firePosition.x, this.firePosition.y, Graphics.HCENTER | Graphics.VCENTER ); } // Draw the crosshair this.crosshair.paint(graphics); // Draw the gamepad this.gamepad.paint(graphics); // Draw the exit button graphics.drawImage( this.exitButtonPointerDown ? this.exitPressedImage : this.exitImage, this.getWidth(), 0, Graphics.RIGHT | Graphics.TOP ); // Draw remaining time // Bar shows percentage of time remaining, the maximum is 100. int barMaxHeight = 100; int barHeight = 0; if (!this.shot) { barHeight = this.ghost.getPercentOfTimeUsed(); } final int barWidth = 20; int barX = this.getWidth() - barWidth - 10; int barY = (this.getHeight() - barMaxHeight) / 2; graphics.setColor(0xffff00); graphics.drawRect(barX, barY, barWidth, barMaxHeight); graphics.setColor(0x00ff00); graphics.fillRect(barX + 1, barY + (barMaxHeight - barHeight) + 1, barWidth - 1, barHeight - 1); // Draw score graphics.setColor(0xffff00); graphics.setFont(this.font); String scoreString = Integer.toString(this.score) + " / " + Integer.toString(this.hiScore); graphics.drawString( scoreString, this.getWidth() - this.exitImage.getWidth() - 30, 10, Graphics.TOP | Graphics.RIGHT ); } protected void pointerPressed(int x, int y) { int pointerId = this.getPointerEventId(); // Check whether the exit button was tapped this.exitButtonPointerDown = this.exitButtonHitTest(pointerId, x, y); boolean wasFirePressed = this.gamepad.isFireButtonPressed(); // Pass pointer event to gamepad this.gamepad.pointerPressed(pointerId, x, y); if (!wasFirePressed && this.gamepad.isFireButtonPressed()) { // Fire only when the fire button was released and pressed again this.handleFire(); } } protected void pointerDragged(int x, int y) { int pointerId = this.getPointerEventId(); // Update exit button state this.exitButtonPointerDown = this.exitButtonHitTest(pointerId, x, y); // Pass pointer event to gamepad this.gamepad.pointerDragged(pointerId, x, y); } protected void pointerReleased(int x, int y) { int pointerId = this.getPointerEventId(); if (this.exitButtonPointerDown && this.exitButtonHitTest(pointerId, x, y)) { // The exit button was pressed and released, exit the game. this.exit(); } else { this.exitButtonPointerDown = false; } // Pass pointer event to gamepad this.gamepad.pointerReleased(pointerId, x, y); } /** * Returns the number of the pointer which caused last pointer event. * This method should be called only from pointerPressed(), pointerDragged() and * pointerReleased(), otherwise its return value has no meaning. */ private int getPointerEventId() { String idString = System.getProperty("com.nokia.pointer.number"); int id = 0; if (idString != null) { id = Integer.parseInt(idString); } return id; } private boolean exitButtonHitTest(int pointerId, int x, int y) { return pointerId == 0 && x > (this.getWidth() - this.exitImage.getWidth()) && y < this.exitImage.getHeight(); } private void handleFire() { // After a successful shot, ignore fire events until the next ghost relocation if (this.shot) { return; } // Remember the fire position this.firePosition = this.crosshair.getCrosshairPosition(); // Check whether the ghost was shot and hit if (this.ghost.hitTest(this.firePosition.x, this.firePosition.y)) { // The ghost was shot this.shot = true; this.miss = false; this.ghost.setShot(true); this.score += 5 * this.level; if (this.score > this.hiScore) { this.hiScore = score; } } else { // The player missed this.miss = true; } } private void exit() { this.inactivityTimer.cancel(); Display.getDisplay(this.midlet).setCurrent(null); this.midlet.notifyDestroyed(); } }