How to create local multiplayer functionality in AIR for mobile

1.1k Views Asked by At

I am working on a multiplayer game in AS3/AIR for mobile (both android & iOS) and I want to implement a local multiplayer (on same wifi network/bluetooth) functionality in the game. What could be the best option to do this ??

  • it would be great if it is cross platform (android <-> iOS)
  • if i use peer-to-peer and Adobe Cirrus service (RTMFP) for local multiplayer, can I get into any problems, since the project is in beta ??
  • I already know about this post : http://forum.starling-framework.org/topic/google-play-game-services-ane-1#post-74449
  • I have also gone through this post : http://www.as3gamegears.com/category/multiplayer/ But some of the options that I like uses RTMFP which I am doubtful about !! So please suggest me if its ok to use ??
  • can I use Datagram Sockets class provided by the AIR sdk..?? Although I am not sure but is there any connection between RTMFP and TCP/Datagram sockets ??

If I any more details are required I can specify !!!

Thanks

3

There are 3 best solutions below

0
Arkadiusz Okoń On

I use Adobe Cirrus and it's work well. I used available docs and it takes me about 30 min to start communication between two devices. In my opinion it is best choice.

0
Aaron Beall On

You can use RTMFP without Cirrus using the LAN NetGroup method.

This method is described in the documentation for NetConnection/connect():

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetConnection.html#connect()

A good example of this can be found here:

http://tomkrcha.com/?p=1803

private var connection:NetConnection;
private var group:NetGroup;

private function connect():void {
    connection = new NetConnection();
    connection.connect("rtmfp:");
    connection.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
}

private function netStatus(event:NetStatusEvent):void {
    switch(event.info.code){
        case "NetConnection.Connect.Success":
            joinGroup();
            break;
        case "NetGroup.Posting.Notify":
            receive(event.info.message);
            break;
    }
}

private function joinGroup():void{
    var groupspec:GroupSpecifier = new GroupSpecifier("myGroup/groupOne");
    groupspec.postingEnabled = true;
    groupspec.ipMulticastMemberUpdatesEnabled = true;
    groupspec.addIPMulticastAddress("225.225.0.1:30303");

    group = new NetGroup(connection, groupspec.groupspecWithAuthorizations());
    group.addEventListener(NetStatusEvent.NET_STATUS, netStatus);
}

public function send(text:String):void {
    var message:Object = {
        sender: connection.nearId,
        text: text
    }
    group.post(message);
}

public function receive(message:Object):void {
    trace("Received message from " + message.sender + ": " + message.text);
}

This is in my experienced the easiest way to do multi-user apps on a local network, because it requires no server (even to discover neighbors) and just the Flash Player.

0
FlashPress.ru On

You can try to use Bluetooth Low Energy in AIR for iOS(and OSX). Demonstration here: http://www.youtube.com/watch?v=tiRfYjq4wh0&index=1&list=PLw76-mHQ5mhdmHPJy05n424-DKde1XM8G . ANE library here: http://flashpress.ru/blog/ane/bluetooth/?lang=en

CentralManager:


package 
{
    import flash.display.Sprite;

    import ru.flashpress.ane.queue.FPQueueData;
    import ru.flashpress.ane.queue.FPQueueTypes;
    import ru.flashpress.bluetooth.FPBluetooth;
    import ru.flashpress.bluetooth.constants.FPbtState;
    import ru.flashpress.bluetooth.data.FPBluetoothOptions;
    import ru.flashpress.bluetooth.events.FPBluetoothEvent;
    import ru.flashpress.bluetooth.events.FPCentralManagerEvent;
    import ru.flashpress.bluetooth.events.FPCharacteristicEvent;
    import ru.flashpress.bluetooth.events.FPPeripheralEvent;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristic;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristicValueFormat;
    import ru.flashpress.bluetooth.helpers.characteristic.stream.FPStreamIn;
    import ru.flashpress.bluetooth.helpers.peripheral.FPPeripheral;
    import ru.flashpress.bluetooth.helpers.service.FPService;
    import ru.flashpress.bluetooth.helpers.service.FPServiceEvent;
    import ru.flashpress.bluetooth.managers.central.FPCentralManager;
    import ru.flashpress.bluetooth.managers.central.FPcmScanOptions;

    public class CentralView extends Sprite
    {
        public static const SERVICE_UUID:String = 'E20A39F4-73F5-4BC4-A12F-17D1AD07A961';
        public static const CHARACTERISTIC_UUID:String = '08590F7E-DB05-467E-8757-72F6FAEB13D4';
        //
        public function CentralView()
        {
            var options:FPBluetoothOptions = new FPBluetoothOptions();
            options.nativeLogEnabled = true;
            FPBluetooth.init(options);
            //
            startBluetooth();
        }


        // Bluetooth Methods ****************

        private var cm:FPCentralManager;
        private function startBluetooth():void
        {
            trace('startBluetooth');
            var queue:FPQueueData = new FPQueueData('ru.flashpress.chat.central', FPQueueTypes.SERIAL);
            cm = new FPCentralManager(null, queue);
            cm.addEventListener(FPBluetoothEvent.UPDATE_STATE, updateStateHandler);
            cm.addEventListener(FPCentralManagerEvent.PERIPHERAL_DISCOVER, discoverPeripheralHandler);
        }

        private function updateStateHandler(event:FPBluetoothEvent):void
        {
            trace('updateStateHandler', event.state);
            if (event.state != FPbtState.POWERED_ON) {
                return;
            }
            var options:FPcmScanOptions = new FPcmScanOptions(true, null);
            cm.startScan(options, SERVICE_UUID);
        }

        private var peripheral:FPPeripheral;
        private function discoverPeripheralHandler(event:FPCentralManagerEvent):void
        {
            trace('discoverPeripheralHandler', event.peripheral);
            if (peripheral) return;
            peripheral = event.peripheral;
            trace(' name:', peripheral.advertisementInited ? peripheral.advertisementInited.localName : null);
            //
            peripheral.addEventListener(FPPeripheralEvent.CONNECTED, peripheralConnectedHandler);
            peripheral.addEventListener(FPPeripheralEvent.DISCONNECT, peripheralDisconnectedHandler);
            peripheral.connect();
        }

        private function peripheralConnectedHandler(event:FPPeripheralEvent):void
        {
            trace('peripheralConnectedHandler');
            peripheral.discoverServiceUUIDs(SERVICE_UUID);
            peripheral.addEventListener(FPPeripheralEvent.DISCOVER_SERVICES, discoverServicesHandler);
        }
        private function peripheralDisconnectedHandler(event:FPPeripheralEvent):void
        {
            trace('peripheralDisconnectedHandler');
            peripheral.removeEventListener(FPPeripheralEvent.CONNECTED, peripheralConnectedHandler);
            peripheral.removeEventListener(FPPeripheralEvent.DISCONNECT, peripheralDisconnectedHandler);
            peripheral = null;
        }

        private var service:FPService;
        private function discoverServicesHandler(event:FPPeripheralEvent):void
        {
            trace('discoverServicesHandler');
            if (event.error) {
                trace('discoverServicesHandler, error:', event.error);
                return;
            }
            //
            service = peripheral.services.list[0];
            trace(' service:', service);
            //
            service.discoverCharacteristicUUIDs(CHARACTERISTIC_UUID);
            service.addEventListener(FPServiceEvent.DISCOVER_CHARACTERISTICS, discoverCharacteristicsHandler);
        }

        public var characteristic:FPCharacteristic;
        private var streamIn:FPStreamIn;
        private function discoverCharacteristicsHandler(event:FPServiceEvent):void
        {
            trace('discoverCharacteristicsHandler');
            if (event.error) {
                trace('discoverCharacteristicsHandler, error:', event.error);
                return;
            }
            characteristic = service.characteristics.list[0];
            trace(' characteristic:', characteristic);
            characteristic.initValueFormat(FPCharacteristicValueFormat.MESSAGES);
            streamIn = characteristic.streamIn;
            characteristic.setNotify(true);
            characteristic.addEventListener(FPCharacteristicEvent.UPDATE_NOTIFICATION, updateNotificationHandler);
            //
            characteristic.addEventListener(FPCharacteristicEvent.UPDATE_MESSAGES, updateMessageHandler);
        }

        private function updateNotificationHandler(event:FPCharacteristicEvent):void
        {
            trace('updateNotificationHandler:', event.isNotifying);
        }

        private function updateMessageHandler(event:FPCharacteristicEvent):void
        {
            trace('updateMessageHandler');
            trace(' error:', event.error);
            trace(' messages:', event.messages);
        }
    }
}

Peripheral Manager:


package
{
    import flash.display.Sprite;

    import ru.flashpress.bluetooth.FPBluetooth;
    import ru.flashpress.bluetooth.constants.FPbtState;
    import ru.flashpress.bluetooth.data.FPAdvertisementData;
    import ru.flashpress.bluetooth.data.FPBluetoothOptions;
    import ru.flashpress.bluetooth.events.FPBluetoothEvent;
    import ru.flashpress.bluetooth.events.FPCharacteristicEvent;
    import ru.flashpress.bluetooth.events.FPPeripheralManagerEvent;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristic;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristicPermissions;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristicProperties;
    import ru.flashpress.bluetooth.helpers.characteristic.FPCharacteristicValueFormat;
    import ru.flashpress.bluetooth.helpers.service.FPService;
    import ru.flashpress.bluetooth.managers.peripheral.FPPeripheralManager;

    public class PeripheralView extends Sprite
    {
        public static const SERVICE_UUID:String = 'E20A39F4-73F5-4BC4-A12F-17D1AD07A961';
        public static const CHARACTERISTIC_UUID:String = '08590F7E-DB05-467E-8757-72F6FAEB13D4';
        //
        public function PeripheralView()
        {
            var options:FPBluetoothOptions = new FPBluetoothOptions();
            options.nativeLogEnabled = true;
            FPBluetooth.init(options);
            //
            startBluetooth();
        }

        // Bluetooth Methods ****************

        private var pm:FPPeripheralManager;
        private function startBluetooth():void
        {
            trace('startBluetooth');
            pm = new FPPeripheralManager();
            pm.addEventListener(FPBluetoothEvent.UPDATE_STATE, updateStateHandler);
            pm.addEventListener(FPPeripheralManagerEvent.ADD_SERVICE, addServiceHandler);
        }

        private var characteristic:FPCharacteristic;
        private var service:FPService;
        private function updateStateHandler(event:FPBluetoothEvent):void
        {
            trace('updateStateHandler:', event.state);
            if (event.state != FPbtState.POWERED_ON) {
                return;
            }
            //
            var properties:uint = FPCharacteristicProperties.NOTIFY;
            var permissions:uint = FPCharacteristicPermissions.WRITEABLE;
            var valueFormat:uint = FPCharacteristicValueFormat.MESSAGES;
            characteristic = new FPCharacteristic(CHARACTERISTIC_UUID, properties, permissions, valueFormat);
            characteristic.addEventListener(FPCharacteristicEvent.SUBSCRIBED_TO_CENTRAL, subscribedToCentralHandler);
            characteristic.addEventListener(FPCharacteristicEvent.UNSUBSCRIBED_FROM_CENTRAL, unsubscribedFromCentralHandler);
            characteristic.notifyMTU = 50;
            //
            service = new FPService(SERVICE_UUID, true);
            service.addCharacteristic(characteristic);
            //
            pm.addService(service);
        }
        private function addServiceHandler(event:FPPeripheralManagerEvent):void
        {
            trace('addServiceHandler');
            if (event.error) {
                trace(' error:', event.error);
                return;
            }
            if (!pm.isAdvertising) {
                var uuids:Vector. = new [SERVICE_UUID];
                var advertisementData:FPAdvertisementData = new FPAdvertisementData('My Local name', uuids);
                pm.startAdvertising(advertisementData);
            }
        }

        private function unsubscribedFromCentralHandler(event:FPCharacteristicEvent):void
        {
            trace('unsubscribedFromCentralHandlers', event.central);
        }
        private function subscribedToCentralHandler(event:FPCharacteristicEvent):void
        {
            trace('subscribedToCentralHandler', event.central);
            //
            characteristic.sendMessage('send my message');
        }
    }
}