Gamepad.java

/*
 * 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 javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/**
 * This class implements the on-screen gamepad.
 *
 * The gamepad consists of a virtual analog stick and a fire button.
 * Since multipoint touch events are enabled, it is possible to
 * move the analog stick and press the fire button simultaneously.
 */
public class Gamepad
{
    Size parentSize;
    private Image fireButtonImage;
    private Image analogStickThumbImage;
    private Image analogStickBackgroundImage;
    private Point analogStickPosition = new Point();
    private Point analogStickCenter = new Point();
    private double analogStickDiameter = 0.0;
    private double analogStickThumbDiameter = 0.0;
    private int analogStickPointerId = -1;
    private int fireButtonPointerId = -1;

    public Gamepad(Size parentSize) throws IOException
    {
        super();
        this.parentSize = parentSize;
        this.fireButtonImage = Image.createImage("/images/FireButton.png");
        this.analogStickThumbImage = Image.createImage("/images/AnalogStickThumb.png");
        this.analogStickBackgroundImage = Image.createImage("/images/AnalogStickBackground.png");

        this.analogStickCenter.x = this.analogStickBackgroundImage.getWidth() / 2;
        this.analogStickCenter.y = this.parentSize.height - this.analogStickBackgroundImage.getHeight() / 2;
        this.analogStickPosition.x = 0;
        this.analogStickPosition.y = 0;
        this.analogStickDiameter = this.analogStickBackgroundImage.getWidth();
        this.analogStickThumbDiameter = this.analogStickThumbImage.getWidth();
    }

    public void paint(Graphics graphics)
    {
        // Draw the analog stick
        graphics.drawImage(
            this.analogStickBackgroundImage,
            this.analogStickCenter.x,
            this.analogStickCenter.y,
            Graphics.HCENTER | Graphics.VCENTER
        );
        graphics.drawImage(
            this.analogStickThumbImage,
            this.analogStickCenter.x + this.analogStickPosition.x,
            this.analogStickCenter.y + this.analogStickPosition.y,
            Graphics.HCENTER | Graphics.VCENTER
        );

        // Draw the fire button
        graphics.drawImage(
            this.fireButtonImage,
            this.parentSize.width,
            this.parentSize.height,
            Graphics.RIGHT | Graphics.BOTTOM
        );
    }

    /**
     * Returns the state of the fire button.
     */
    public boolean isFireButtonPressed()
    {
        return this.fireButtonPointerId != -1;
    }

    /**
     * Returns the analog stick position.
     * The position is relative to analog stick's center.
     */
    public Point getAnalogStickPosition()
    {
        return new Point(
                   this.analogStickPosition.x,
                   this.analogStickPosition.y
               );
    }

    /**
     * This method needs to be called from Canvas pointerPressed() method.
     */
    public void pointerPressed(int pointerId, int x, int y)
    {
        if (this.fireButtonPointerId == -1 && this.fireButtonHitTest(x, y))
        {
            this.fireButtonPointerId = pointerId;
        }
        if (this.analogStickPointerId == -1 && this.analogStickHitTest(x, y))
        {
            this.analogStickPointerId = pointerId;
        }
    }

    /**
     * This method needs to be called from Canvas pointerDragged() method.
     */
    public void pointerDragged(int pointerId, int x, int y)
    {
        if (this.analogStickPointerId == pointerId)
        {
            double thumbDistance = this.getAnalogStickThumbDistance(x, y);
            if ((thumbDistance + this.analogStickThumbDiameter / 2) < (this.analogStickDiameter / 2))
            {
                this.analogStickPosition.x = x - this.analogStickCenter.x;
                this.analogStickPosition.y = y - this.analogStickCenter.y;
            }
        }
    }

    /**
     * This method needs to be called from Canvas pointerReleased() method.
     */
    public void pointerReleased(int pointerId, int x, int y)
    {
        if (this.fireButtonPointerId == pointerId)
        {
            this.fireButtonPointerId = -1;
        }

        if (this.analogStickPointerId == pointerId)
        {
            this.analogStickPointerId = -1;
            this.analogStickPosition.x = 0;
            this.analogStickPosition.y = 0;
        }
    }

    private boolean fireButtonHitTest(int x, int y)
    {
        return x > (this.parentSize.width - this.fireButtonImage.getWidth())
               && y > (this.parentSize.height - this.fireButtonImage.getHeight());
    }

    private boolean analogStickHitTest(int x, int y)
    {
        double pointDistance = getAnalogStickThumbDistance(x, y);
        return pointDistance < this.analogStickDiameter;
    }

    private double getAnalogStickThumbDistance(int x, int y)
    {
        int relX = x - this.analogStickCenter.x;
        int relY = y - this.analogStickCenter.y;
        double pointDistance = Math.sqrt(relX * relX + relY * relY);
        return pointDistance;
    }
}