package org.andengine.examples; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import org.andengine.engine.camera.Camera; import org.andengine.engine.options.EngineOptions; import org.andengine.engine.options.ScreenOrientation; import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy; import org.andengine.entity.scene.IOnAreaTouchListener; import org.andengine.entity.scene.IOnSceneTouchListener; import org.andengine.entity.scene.ITouchArea; import org.andengine.entity.scene.Scene; import org.andengine.entity.scene.background.Background; import org.andengine.entity.sprite.Sprite; import org.andengine.entity.util.FPSLogger; import org.andengine.examples.adt.messages.client.ClientMessageFlags; import org.andengine.examples.adt.messages.server.ConnectionCloseServerMessage; import org.andengine.examples.adt.messages.server.ServerMessageFlags; import org.andengine.examples.util.BluetoothListDevicesActivity; import org.andengine.extension.multiplayer.protocol.adt.message.IMessage; import org.andengine.extension.multiplayer.protocol.adt.message.server.IServerMessage; import org.andengine.extension.multiplayer.protocol.adt.message.server.ServerMessage; import org.andengine.extension.multiplayer.protocol.client.IServerMessageHandler; import org.andengine.extension.multiplayer.protocol.client.connector.BluetoothSocketConnectionServerConnector; import org.andengine.extension.multiplayer.protocol.client.connector.BluetoothSocketConnectionServerConnector.IBluetoothSocketConnectionServerConnectorListener; import org.andengine.extension.multiplayer.protocol.client.connector.ServerConnector; import org.andengine.extension.multiplayer.protocol.exception.BluetoothException; import org.andengine.extension.multiplayer.protocol.server.BluetoothSocketServer; import org.andengine.extension.multiplayer.protocol.server.BluetoothSocketServer.IBluetoothSocketServerListener; import org.andengine.extension.multiplayer.protocol.server.connector.BluetoothSocketConnectionClientConnector; import org.andengine.extension.multiplayer.protocol.server.connector.BluetoothSocketConnectionClientConnector.IBluetoothSocketConnectionClientConnectorListener; import org.andengine.extension.multiplayer.protocol.server.connector.ClientConnector; import org.andengine.extension.multiplayer.protocol.shared.BluetoothSocketConnection; import org.andengine.extension.multiplayer.protocol.util.MessagePool; import org.andengine.input.touch.TouchEvent; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas; import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory; import org.andengine.opengl.texture.region.ITextureRegion; import org.andengine.ui.activity.SimpleBaseGameActivity; import org.andengine.util.debug.Debug; import android.app.AlertDialog; import android.app.Dialog; import android.bluetooth.BluetoothAdapter; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.os.Bundle; import android.util.SparseArray; import android.view.KeyEvent; import android.widget.Toast; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga * * @author Nicolas Gramlich * @since 11:45:03 - 06.03.2011 */ public class MultiplayerBluetoothExample extends SimpleBaseGameActivity implements ClientMessageFlags, ServerMessageFlags { // =========================================================== // Constants // =========================================================== /** Create your own unique UUID at: http://www.uuidgenerator.com/ */ private static final String EXAMPLE_UUID = "6D2DF50E-06EF-C21C-7DB0-345099A5F64E"; private static final int CAMERA_WIDTH = 720; private static final int CAMERA_HEIGHT = 480; private static final short FLAG_MESSAGE_SERVER_ADD_FACE = 1; private static final short FLAG_MESSAGE_SERVER_MOVE_FACE = FLAG_MESSAGE_SERVER_ADD_FACE + 1; private static final int DIALOG_CHOOSE_SERVER_OR_CLIENT_ID = 0; private static final int DIALOG_SHOW_SERVER_IP_ID = DIALOG_CHOOSE_SERVER_OR_CLIENT_ID + 1; private static final int REQUESTCODE_BLUETOOTH_ENABLE = 0; private static final int REQUESTCODE_BLUETOOTH_CONNECT = REQUESTCODE_BLUETOOTH_ENABLE + 1; // =========================================================== // Fields // =========================================================== private BitmapTextureAtlas mBitmapTextureAtlas; private ITextureRegion mFaceTextureRegion; private int mFaceIDCounter; private final SparseArray<Sprite> mFaces = new SparseArray<Sprite>(); private String mServerMACAddress; private BluetoothSocketServer<BluetoothSocketConnectionClientConnector> mBluetoothSocketServer; private ServerConnector<BluetoothSocketConnection> mServerConnector; private final MessagePool<IMessage> mMessagePool = new MessagePool<IMessage>(); private BluetoothAdapter mBluetoothAdapter; // =========================================================== // Constructors // =========================================================== public MultiplayerBluetoothExample() { this.initMessagePool(); } private void initMessagePool() { this.mMessagePool.registerMessage(FLAG_MESSAGE_SERVER_ADD_FACE, AddFaceServerMessage.class); this.mMessagePool.registerMessage(FLAG_MESSAGE_SERVER_MOVE_FACE, MoveFaceServerMessage.class); } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override protected void onCreate(final Bundle pSavedInstanceState) { super.onCreate(pSavedInstanceState); this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); this.mServerMACAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); if (this.mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available!", Toast.LENGTH_LONG).show(); this.finish(); return; } else { if (this.mBluetoothAdapter.isEnabled()) { this.showDialog(DIALOG_CHOOSE_SERVER_OR_CLIENT_ID); } else { final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); this.startActivityForResult(enableIntent, REQUESTCODE_BLUETOOTH_ENABLE); } } } @Override protected Dialog onCreateDialog(final int pID) { switch(pID) { case DIALOG_SHOW_SERVER_IP_ID: return new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_info) .setTitle("Server-Details") .setCancelable(false) .setMessage("The Name of your Server is:\n" + BluetoothAdapter.getDefaultAdapter().getName() + "\n" + "The MACAddress of your Server is:\n" + this.mServerMACAddress) .setPositiveButton(android.R.string.ok, null) .create(); case DIALOG_CHOOSE_SERVER_OR_CLIENT_ID: return new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_info) .setTitle("Be Server or Client ...") .setCancelable(false) .setPositiveButton("Client", new OnClickListener() { @Override public void onClick(final DialogInterface pDialog, final int pWhich) { final Intent intent = new Intent(MultiplayerBluetoothExample.this, BluetoothListDevicesActivity.class); MultiplayerBluetoothExample.this.startActivityForResult(intent, REQUESTCODE_BLUETOOTH_CONNECT); } }) .setNeutralButton("Server", new OnClickListener() { @Override public void onClick(final DialogInterface pDialog, final int pWhich) { MultiplayerBluetoothExample.this.toast("You can add and move sprites, which are only shown on the clients."); MultiplayerBluetoothExample.this.initServer(); MultiplayerBluetoothExample.this.showDialog(DIALOG_SHOW_SERVER_IP_ID); } }) .setNegativeButton("Both", new OnClickListener() { @Override public void onClick(final DialogInterface pDialog, final int pWhich) { MultiplayerBluetoothExample.this.toast("You can add sprites and move them, by dragging them."); MultiplayerBluetoothExample.this.initServerAndClient(); MultiplayerBluetoothExample.this.showDialog(DIALOG_SHOW_SERVER_IP_ID); } }) .create(); default: return super.onCreateDialog(pID); } } @Override public EngineOptions onCreateEngineOptions() { final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT); return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera); } @Override protected void onDestroy() { if(this.mBluetoothSocketServer != null) { try { this.mBluetoothSocketServer.sendBroadcastServerMessage(new ConnectionCloseServerMessage()); } catch (final IOException e) { Debug.e(e); } this.mBluetoothSocketServer.terminate(); } if(this.mServerConnector != null) { this.mServerConnector.terminate(); } super.onDestroy(); } @Override public boolean onKeyUp(final int pKeyCode, final KeyEvent pEvent) { switch(pKeyCode) { case KeyEvent.KEYCODE_BACK: this.finish(); return true; } return super.onKeyUp(pKeyCode, pEvent); } @Override public void onCreateResources() { BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/"); this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 32, 32, TextureOptions.BILINEAR); this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "face_box.png", 0, 0); this.mBitmapTextureAtlas.load(); } @Override public Scene onCreateScene() { this.mEngine.registerUpdateHandler(new FPSLogger()); final Scene scene = new Scene(); scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f)); /* We allow only the server to actively send around messages. */ if(MultiplayerBluetoothExample.this.mBluetoothSocketServer != null) { scene.setOnSceneTouchListener(new IOnSceneTouchListener() { @Override public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) { if(pSceneTouchEvent.isActionDown()) { try { final AddFaceServerMessage addFaceServerMessage = (AddFaceServerMessage) MultiplayerBluetoothExample.this.mMessagePool.obtainMessage(FLAG_MESSAGE_SERVER_ADD_FACE); addFaceServerMessage.set(MultiplayerBluetoothExample.this.mFaceIDCounter++, pSceneTouchEvent.getX(), pSceneTouchEvent.getY()); MultiplayerBluetoothExample.this.mBluetoothSocketServer.sendBroadcastServerMessage(addFaceServerMessage); MultiplayerBluetoothExample.this.mMessagePool.recycleMessage(addFaceServerMessage); } catch (final IOException e) { Debug.e(e); } return true; } else { return false; } } }); scene.setOnAreaTouchListener(new IOnAreaTouchListener() { @Override public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final ITouchArea pTouchArea, final float pTouchAreaLocalX, final float pTouchAreaLocalY) { try { final Sprite face = (Sprite)pTouchArea; final Integer faceID = (Integer)face.getUserData(); final MoveFaceServerMessage moveFaceServerMessage = (MoveFaceServerMessage) MultiplayerBluetoothExample.this.mMessagePool.obtainMessage(FLAG_MESSAGE_SERVER_MOVE_FACE); moveFaceServerMessage.set(faceID, pSceneTouchEvent.getX(), pSceneTouchEvent.getY()); MultiplayerBluetoothExample.this.mBluetoothSocketServer.sendBroadcastServerMessage(moveFaceServerMessage); MultiplayerBluetoothExample.this.mMessagePool.recycleMessage(moveFaceServerMessage); } catch (final IOException e) { Debug.e(e); return false; } return true; } }); scene.setTouchAreaBindingOnActionDownEnabled(true); } return scene; } @Override protected void onActivityResult(final int pRequestCode, final int pResultCode, final Intent pData) { switch(pRequestCode) { case REQUESTCODE_BLUETOOTH_ENABLE: this.showDialog(DIALOG_CHOOSE_SERVER_OR_CLIENT_ID); break; case REQUESTCODE_BLUETOOTH_CONNECT: this.mServerMACAddress = pData.getExtras().getString(BluetoothListDevicesActivity.EXTRA_DEVICE_ADDRESS); this.initClient(); break; default: super.onActivityResult(pRequestCode, pResultCode, pData); } } // =========================================================== // Methods // =========================================================== public void addFace(final int pID, final float pX, final float pY) { final Scene scene = this.mEngine.getScene(); /* Create the face and add it to the scene. */ final Sprite face = new Sprite(0, 0, this.mFaceTextureRegion, this.getVertexBufferObjectManager()); face.setPosition(pX - face.getWidth() * 0.5f, pY - face.getHeight() * 0.5f); face.setUserData(pID); this.mFaces.put(pID, face); scene.registerTouchArea(face); scene.attachChild(face); } public void moveFace(final int pID, final float pX, final float pY) { /* Find and move the face. */ final Sprite face = this.mFaces.get(pID); face.setPosition(pX - face.getWidth() * 0.5f, pY - face.getHeight() * 0.5f); } private void initServerAndClient() { this.initServer(); /* Wait some time after the server has been started, so it actually can start up. */ try { Thread.sleep(500); } catch (final Throwable t) { Debug.e(t); } this.initClient(); } private void initServer() { this.mServerMACAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); try { this.mBluetoothSocketServer = new BluetoothSocketServer<BluetoothSocketConnectionClientConnector>(EXAMPLE_UUID, new ExampleClientConnectorListener(), new ExampleServerStateListener()) { @Override protected BluetoothSocketConnectionClientConnector newClientConnector(final BluetoothSocketConnection pBluetoothSocketConnection) throws IOException { try { return new BluetoothSocketConnectionClientConnector(pBluetoothSocketConnection); } catch (final BluetoothException e) { Debug.e(e); /* Actually cannot happen. */ return null; } } }; } catch (final BluetoothException e) { Debug.e(e); } this.mBluetoothSocketServer.start(); } private void initClient() { try { this.mServerConnector = new BluetoothSocketConnectionServerConnector(new BluetoothSocketConnection(this.mBluetoothAdapter, this.mServerMACAddress, EXAMPLE_UUID), new ExampleServerConnectorListener()); this.mServerConnector.registerServerMessage(FLAG_MESSAGE_SERVER_CONNECTION_CLOSE, ConnectionCloseServerMessage.class, new IServerMessageHandler<BluetoothSocketConnection>() { @Override public void onHandleMessage(final ServerConnector<BluetoothSocketConnection> pServerConnector, final IServerMessage pServerMessage) throws IOException { MultiplayerBluetoothExample.this.finish(); } }); this.mServerConnector.registerServerMessage(FLAG_MESSAGE_SERVER_ADD_FACE, AddFaceServerMessage.class, new IServerMessageHandler<BluetoothSocketConnection>() { @Override public void onHandleMessage(final ServerConnector<BluetoothSocketConnection> pServerConnector, final IServerMessage pServerMessage) throws IOException { final AddFaceServerMessage addFaceServerMessage = (AddFaceServerMessage)pServerMessage; MultiplayerBluetoothExample.this.addFace(addFaceServerMessage.mID, addFaceServerMessage.mX, addFaceServerMessage.mY); } }); this.mServerConnector.registerServerMessage(FLAG_MESSAGE_SERVER_MOVE_FACE, MoveFaceServerMessage.class, new IServerMessageHandler<BluetoothSocketConnection>() { @Override public void onHandleMessage(final ServerConnector<BluetoothSocketConnection> pServerConnector, final IServerMessage pServerMessage) throws IOException { final MoveFaceServerMessage moveFaceServerMessage = (MoveFaceServerMessage)pServerMessage; MultiplayerBluetoothExample.this.moveFace(moveFaceServerMessage.mID, moveFaceServerMessage.mX, moveFaceServerMessage.mY); } }); this.mServerConnector.getConnection().start(); } catch (final Throwable t) { Debug.e(t); } } private void log(final String pMessage) { Debug.d(pMessage); } private void toast(final String pMessage) { this.log(pMessage); this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MultiplayerBluetoothExample.this, pMessage, Toast.LENGTH_SHORT).show(); } }); } // =========================================================== // Inner and Anonymous Classes // =========================================================== public static class AddFaceServerMessage extends ServerMessage { private int mID; private float mX; private float mY; public AddFaceServerMessage() { } public AddFaceServerMessage(final int pID, final float pX, final float pY) { this.mID = pID; this.mX = pX; this.mY = pY; } public void set(final int pID, final float pX, final float pY) { this.mID = pID; this.mX = pX; this.mY = pY; } @Override public short getFlag() { return FLAG_MESSAGE_SERVER_ADD_FACE; } @Override protected void onReadTransmissionData(final DataInputStream pDataInputStream) throws IOException { this.mID = pDataInputStream.readInt(); this.mX = pDataInputStream.readFloat(); this.mY = pDataInputStream.readFloat(); } @Override protected void onWriteTransmissionData(final DataOutputStream pDataOutputStream) throws IOException { pDataOutputStream.writeInt(this.mID); pDataOutputStream.writeFloat(this.mX); pDataOutputStream.writeFloat(this.mY); } } public static class MoveFaceServerMessage extends ServerMessage { private int mID; private float mX; private float mY; public MoveFaceServerMessage() { } public MoveFaceServerMessage(final int pID, final float pX, final float pY) { this.mID = pID; this.mX = pX; this.mY = pY; } public void set(final int pID, final float pX, final float pY) { this.mID = pID; this.mX = pX; this.mY = pY; } @Override public short getFlag() { return FLAG_MESSAGE_SERVER_MOVE_FACE; } @Override protected void onReadTransmissionData(final DataInputStream pDataInputStream) throws IOException { this.mID = pDataInputStream.readInt(); this.mX = pDataInputStream.readFloat(); this.mY = pDataInputStream.readFloat(); } @Override protected void onWriteTransmissionData(final DataOutputStream pDataOutputStream) throws IOException { pDataOutputStream.writeInt(this.mID); pDataOutputStream.writeFloat(this.mX); pDataOutputStream.writeFloat(this.mY); } } private class ExampleServerConnectorListener implements IBluetoothSocketConnectionServerConnectorListener { @Override public void onStarted(final ServerConnector<BluetoothSocketConnection> pConnector) { MultiplayerBluetoothExample.this.toast("CLIENT: Connected to server."); } @Override public void onTerminated(final ServerConnector<BluetoothSocketConnection> pConnector) { MultiplayerBluetoothExample.this.toast("CLIENT: Disconnected from Server..."); MultiplayerBluetoothExample.this.finish(); } } private class ExampleServerStateListener implements IBluetoothSocketServerListener<BluetoothSocketConnectionClientConnector> { @Override public void onStarted(final BluetoothSocketServer<BluetoothSocketConnectionClientConnector> pBluetoothSocketServer) { MultiplayerBluetoothExample.this.toast("SERVER: Started."); } @Override public void onTerminated(final BluetoothSocketServer<BluetoothSocketConnectionClientConnector> pBluetoothSocketServer) { MultiplayerBluetoothExample.this.toast("SERVER: Terminated."); } @Override public void onException(final BluetoothSocketServer<BluetoothSocketConnectionClientConnector> pBluetoothSocketServer, final Throwable pThrowable) { Debug.e(pThrowable); MultiplayerBluetoothExample.this.toast("SERVER: Exception: " + pThrowable); } } private class ExampleClientConnectorListener implements IBluetoothSocketConnectionClientConnectorListener { @Override public void onStarted(final ClientConnector<BluetoothSocketConnection> pConnector) { MultiplayerBluetoothExample.this.toast("SERVER: Client connected: " + pConnector.getConnection().getBluetoothSocket().getRemoteDevice().getAddress()); } @Override public void onTerminated(final ClientConnector<BluetoothSocketConnection> pConnector) { MultiplayerBluetoothExample.this.toast("SERVER: Client disconnected: " + pConnector.getConnection().getBluetoothSocket().getRemoteDevice().getAddress()); } } }