Home > AndEngine, AndPingus, Android, Mobile > Pingus On Android – Part 2

Pingus On Android – Part 2

December 5th, 2010

In my first entry (Pingus on Android), I talked about my initial efforts to port the free game called Pingus to run on top of Android using AndEngine.  At that point, I was struggling to properly place sprite images when the sprite is rotated 90 degrees (and presumably 270).  All of the work being done was at a zoom level that allowed the complete scene to be displayed on the device.  Because of the extreme zoom, it was impossible to see the details and therefore to notice when things weren’t properly aligned.  It seemed like I was getting close with this alignment, but the numbers were not something that could be calculated based on available information:

With zoom set to 100% and the ability to drag the image around, it became clearer that there were issues with this placement. The resulting placement code handles the rotation by using the height as an appropriate offset:

	private void setupRotation(float degrees) {
		float width = getWidth();
		float height = getHeight();

		setRotation(degrees);
		setRotationCenter(width / 2, height / 2);

		if (degrees == 90) {
			Position position = definition.getPosition();
			setPosition(position.x - height, position.y + height);
		}
	}

With this code in place, the rotated sprites are properly aligned.

AndEngine Touch Event Handling

In order to have a better view of the scene, it seemed worthwhile to allow for drag and zoom functionality.  This is an area that I’ve not done a whole lot of work previously.  With that said, I managed to hack together a working drag and pinch-to-zoom controller class.  However, it was horribly jittery.  While it helped me solve the rotation issue, it was bad enough that it clearly needed to be fixed.

Digging through the AndEngine sources yielded the solution.  AndEngine already has supporting classes for exactly this functionality.  In what is becoming the theme of working with AndEngine, the library is incredibly powerful… and frustratingly difficult to deal with due to lack of real documentation.  It seems that there are support classes for pretty much anything you want to do, if they can actually be found. In the end, I think the frustration is probably worth it, given the functionality provided. Given that the library is free and open-source, I can’t ask any more from the project, but I do hope that some of these entries will help others that might be struggling with AndEngine.

In addition, I found that the AndEngineExamples that can be installed via the Android Market is seriously out of date. The pinch-to-zoom example does not show up in the Android Market version, further hiding its availability. My suggestion to those that may want to use AndEngine, is to get a copy of the AndEngineExamples (http://code.google.com/p/andengineexamples/) and build/install from that project rather than via the market.

Drag And Zoom Controller

The AndEngineExamples shows how to build out this support in the PinchZoomExample class.  I chose to pull the relevant information into a separate controller class implementation rather than mix it all together in the activity:


/**
 * An AndEngine touch event handler that uses AndEngine function to support
 * touch-based drag operations as well as "pinch to zoom" for devices supporting
 * multitouch.
 * 
 * @author Craig Setera
 */
public class DragAndZoomController implements Scene.IOnSceneTouchListener, IScrollDetectorListener, IPinchZoomDetectorListener {
	
	private ZoomCamera camera;

	private SurfaceScrollDetector mScrollDetector;
	private PinchZoomDetector mPinchZoomDetector;
	private float mPinchZoomStartedCameraZoomFactor;
	
	public DragAndZoomController(ZoomCamera camera) {
		super();
		this.camera = camera;

		this.mScrollDetector = new SurfaceScrollDetector(this);
		if(MultiTouch.isSupportedByAndroidVersion()) {
			try {
				this.mPinchZoomDetector = new PinchZoomDetector(this);
			} catch (final MultiTouchException e) {
			}
		}
	}

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		if (this.mPinchZoomDetector != null) {
			this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);

			if (this.mPinchZoomDetector.isZooming()) {
				this.mScrollDetector.setEnabled(false);
			} else {
				if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
					this.mScrollDetector.setEnabled(true);
				}
				
				this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
			}
		} else {
			this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
		}

		return true;
	}

	@Override
	public void onPinchZoomStarted(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent) {
		this.mPinchZoomStartedCameraZoomFactor = camera.getZoomFactor();
	}

	@Override
	public void onPinchZoom(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		camera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
	}

	@Override
	public void onPinchZoomFinished(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		camera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
	}

	@Override
	public void onScroll(ScrollDetector pScollDetector, TouchEvent pTouchEvent, float pDistanceX, float pDistanceY) {
		final float zoomFactor = camera.getZoomFactor();
		camera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
	}
}

Wiring It Up

With the controller code above, it is just a matter of wiring it up to the scene’s touch listener as part of the onLoadScene() method:

Scene.IOnSceneTouchListener touchListener = 
    new DragAndZoomController(mCamera);
Scene scene = new Scene(1);
scene.setOnSceneTouchListener(touchListener);

In addition, it is necessary to install an AndEngine MultiTouchController into the Engine object as part of the onLoadEngine() method call:

Engine engine = new Engine(engineOptions);
		
// Attempt to set up multitouch support
if (MultiTouch.isSupported(this) && (MultiTouch.isSupported(this))) {
	try {
		engine.setTouchController(new MultiTouchController());
	} catch (MultiTouchException e) {
		Log.e(LOG_TAG, "Error with multitouch initialization", e);
	}
}

What’s Next?

The project has barely scratched the surface on what is to be done. There are no players or game logic. Things are still very much at the beginning. With that said, there are a couple of things that are likely on my shorter term list:

  • Scene Load Speed
    The speed of scene load is still pretty slow. Instead of using object serialization, it is likely that the objects will need to be marshalled into a much more compact and less flexible format. Perhaps some kind of tag/chunk arrangement similar to a PNG file.
  • Loading Screen
    With slow scene loading, demoing on-device is painful as nothing happens for way too long. Adding a startup loading screen would help, even if it is purely cosmetic.
  • Finish Scene Infrastructure
    There are still a number of objects that have not been added to the scene. Many of those objects are animated, which will add an interesting set of complexity.
Categories: AndEngine, AndPingus, Android, Mobile Tags:
Comments are closed.