Example: Ghosts

The example MIDlet demonstrates the usage of multipoint touch events.

The example zip file can be downloaded here.

The MIDlet is a small game, and it uses multipoint touch functionality to emulate a gamepad, consisting of an analog stick and a fire button. The virtual analog stick behaves in a similar way to a traditional analog joystick: the thumb can be moved to any direction inside of its range, providing the game information about the position relative to its center.

Figure: Ghosts example MIDlet

The game uses two JAD attributes to achieve good touch experience:

Nokia-UI-Enhancement: EnableMultiPointTouchEvents

which enables multipoint touch events and makes it possible to simultaneously control the crosshair and fire at the ghost, and

Nokia-MIDlet-Tap-Detection-Options: 0, 0

which disables tap detection to improve responsiveness of the gamepad analog stick.

Multipoint touch event handling is implemented in the class Scene, which derives from LCDUI Canvas and overrides Canvas methods pointerPressed, pointerDragged and pointerReleased. When multipoint touch events are enabled, the system property com.nokia.pointer.number exists in scope of these methods, and can be queried to obtain the pointer number of pointer which was the source of the pointer event.

The pointer number is obtained using the Scene method getPointerId:

private int getPointerEventId() 
	{
    	String idString = System.getProperty("com.nokia.pointer.number");
    	int id = 0;
    	if (idString != null)
    	{
    		id = Integer.parseInt(idString);
    	}
    	return id;
	}

The pointer number and pointer event coordinates are then passed to Gamepad methods pointerPressed, pointerDragged and pointerReleased which handle the interaction with virtual gamepad.

Gamepad stores information about pointer numbers which are used to interact with both the fire button and the virtual analog stick. When the player touches the screen, Gamepad's pointerPressed is executed and when the pointer event is generated in virtual analog stick or the fire button area, the pointer number is stored like in the code snippet:

 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;
		}
	}

Drag events in the virtual analog stick can be then easily distinguished:

public void pointerDragged(int pointerId, int x, int y) 
    {
    	if(this.analogStickPointerId == pointerId) 
        {
			// Process analog stick movement 
			// ...
    	}
    }

Pointer release event resets stored pointer numbers for both the fire button and the virtual analog stick:

public void pointerReleased(int pointerId, int x, int y) 
    {    	
    	if(this.fireButtonPointerId == pointerId) 
		{
    		this.fireButtonPointerId = -1;
		}
    	
    	if(this.analogStickPointerId == pointerId) 
		{
    		this.analogStickPointerId = -1;
    		// Handle analog stick pointer release
    		...
		}
    }