{"id":286,"date":"2011-05-16T21:26:58","date_gmt":"2011-05-16T20:26:58","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=286"},"modified":"2014-11-01T15:07:45","modified_gmt":"2014-11-01T14:07:45","slug":"synch-a-phone-with-a-website-using-the-union-platform","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/synch-a-phone-with-a-website-using-the-union-platform\/","title":{"rendered":"Synch a phone with a website using the Union Platform"},"content":{"rendered":"<p>For my school game project, I use an iPhone to move my hero thanks to the accelerometer. It can move to left\/right, jump&#8230; and manage informations in a menu. To make the synchronization, I use the Union Platform.<\/p>\n<p>There are several ways to realize a synchronization between a smartphone and a website using servers like : <a target=\"_blank\" href=\"http:\/\/www.adobe.com\/products\/flashmediaserver\/\">Flash Media Server<\/a>, <a target=\"_blank\" href=\"http:\/\/www.smartfoxserver.com\/\">SmartFox Server<\/a>, <a target=\"_blank\" href=\"http:\/\/opensource.adobe.com\/wiki\/display\/blazeds\/BlazeDS\">BlazeDS<\/a>&#8230; I didn&#8217;t really try FMS because I use a mac and it can not runs on it. At first I wanted to put my game online using SmartFox, so I needed a Java server&#8230; but it&#8217;s really expensive ! However there was an alternative with the <a target=\"_blank\" href=\"https:\/\/appengine.google.com\/\">Google App Engine<\/a>. We can have a free access to Java and Python server hosting by Google ! It seemed to be great, but SmartFox can&#8217;t be deploy on it whereas BlazeDS and <a target=\"_blank\" href=\"http:\/\/www.graniteds.org\">GraniteDS<\/a> can ! These 2 servers use the flex technology&#8230; it was a big problem to deal with because I use an old iPhone 2G. Even if today you can easily export flash with as3 for iPhone with Flash IDE or the new Flash Builder 4.5, exporting flex for iPhone is not easy : indeed, we need to use some Ant Tasks&#8230; and if your .ipa is well exported, it will not run on iPhone 2G. In fact with the new Air 2.6 you can&#8217;t export to old iPhone.<\/p>\n<p>So these months have been really frustrating, until a friend informed me of the release of a new server : <a target=\"_blank\" href=\"http:\/\/www.unionplatform.com\/\">the Union Platform<\/a>. It has been released by Colin Moock who wrote <a target=\"_blank\" href=\"http:\/\/oreilly.com\/catalog\/9780596526948\/\">Essential ActionScript 3.0<\/a> book.<\/p>\n<p><!--more--><\/p>\n<p><em>Union is a development platform for creating multiuser applications. Build chat, whiteboards, real-time multiplayer games, meeting applications, collaborative editing tools, and shared interfaces that run in desktop and mobile web browsers (JavaScript), Adobe\u00ae Flash\u00ae, Java, C#, and dozens of other languages.<\/em><\/p>\n<p>Union is a Java server, you can install it easily on your computer. But what is really cool is that there is already a Union&#8217;s server where you can make your test online easily !! But because of the lag, it is not a big problem with a chat, I created a ad-hoc local network to have better performance.<\/p>\n<p>So here we go, let&#8217;s start coding ! Union is really easy to learn, it is well documented and there are many examples. According to my game, I use it with the Citrus Engine but it shouldn&#8217;t be a big deal, I use it only to dispatch my Event which can be listened on the top of my game.<\/p>\n<p>This is the Union class for my game on my website :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package kinessia.network {\r\n\r\n\timport net.user1.reactor.IClient;\r\n\timport net.user1.reactor.Reactor;\r\n\timport net.user1.reactor.ReactorEvent;\r\n\timport net.user1.reactor.Room;\r\n\r\n\timport com.citrusengine.core.CitrusEngine;\r\n\r\n\timport flash.events.EventDispatcher;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Network extends EventDispatcher {\r\n\t\t\r\n\t\tprivate var _ce:CitrusEngine;\r\n\t\tprivate var _reactor:Reactor;\r\n\t\tprivate var _room:Room;\r\n\t\t\r\n\t\tprivate var _uniqueID:String;\r\n\r\n\t\tpublic function Network() {\r\n\t\t\t\r\n\t\t\t_ce = CitrusEngine.getInstance();\r\n\t\t\t\r\n\t\t\t_uniqueID = \"CHAT_MESSAGE\"; \/\/_generateRandomString(7);\r\n\r\n\t\t\t_reactor = new Reactor();\r\n\r\n\t\t\t_reactor.connect(\"localhost\", 9110);\r\n\t\t\t\/\/_reactor.connect(\"tryunion.com\", 80);\r\n\r\n\t\t\t_reactor.addEventListener(ReactorEvent.READY, _createRoom);\r\n\t\t}\r\n\t\t\r\n\t\tprivate function _generateRandomString(newLength:uint = 1, userAlphabet:String = \"123456789\"):String{\r\n\t\t\t\r\n\t\t\t\tvar alphabet:Array = userAlphabet.split(\"\");\r\n\t\t\t\tvar alphabetLength:int = alphabet.length;\r\n\t\t\t\tvar randomLetters:String = \"\";\r\n\t\t\t\tfor (var i:uint = 0; i < newLength; i++){\r\n\t\t\t\t\trandomLetters += alphabet[int(Math.floor(Math.random() * alphabetLength))];\r\n\t\t\t\t}\r\n\t\t\t\treturn randomLetters;\r\n\t\t\t}\r\n\r\n\t\tprivate function _createRoom(rEvt:ReactorEvent):void {\r\n\r\n\t\t\t_room = _reactor.getRoomManager().createRoom(\"Kinessia\");\r\n\t\t\t_room.join();\r\n\r\n\t\t\t_room.addMessageListener(_uniqueID, _chatMessageLisener);\r\n\t\t}\r\n\r\n\t\tprivate function _chatMessageLisener(fromClient:IClient, message:String):void {\r\n\t\t\ttrace(\"Guest\" + fromClient.getClientID() + \" says: \" + message);\r\n\t\t\t\r\n\t\t\tswitch (message) {\r\n\t\t\t\t\r\n\t\t\t\tcase \"jump\":\r\n\t\t\t\t\t_ce.dispatchEvent(new NetworkEvent(NetworkEvent.JUMP));\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t\t\r\n\t\t\t\tcase \"onground\":\r\n\t\t\t\t\t_ce.dispatchEvent(new NetworkEvent(NetworkEvent.ONGROUND));\r\n\t\t\t\t\t\r\n\t\t\t\tcase \"left\":\r\n\t\t\t\t\t_ce.dispatchEvent(new NetworkEvent(NetworkEvent.LEFT));\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t\t\r\n\t\t\t\tcase \"right\":\r\n\t\t\t\t\t_ce.dispatchEvent(new NetworkEvent(NetworkEvent.RIGHT));\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t\t\r\n\t\t\t\tcase \"immobile\":\r\n\t\t\t\t\t_ce.dispatchEvent(new NetworkEvent(NetworkEvent.IMMOBILE));\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic function get uniqueID():String {\r\n\t\t\treturn _uniqueID;\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>We connect to the local server and create a room named \"Kinessia\". Noticed that all your game\/phone connections must be on the same room. In fact only the var uniqueID will change. Here it is \"CHAT_MESSAGE\" but it must be something like \"11463794\" using the generateRandomString to have a \"unique\" id. You display this id, and you enter the number in your Phone to synchronize it with your website.<br \/>\nWe add a listener if we receive a message from the phone and finally we dispatch it !<\/p>\n<p>Now the phone class :<\/p>\n<pre lang=\"actionscript\" line=\"1\">package kinessia.network {\r\n\r\n\timport net.user1.reactor.Reactor;\r\n\timport net.user1.reactor.ReactorEvent;\r\n\timport net.user1.reactor.Room;\r\n\r\n\timport flash.display.Sprite;\r\n\timport flash.events.AccelerometerEvent;\r\n\timport flash.events.Event;\r\n\timport flash.sensors.Accelerometer;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Network extends Sprite {\r\n\r\n\t\tprivate var _reactor:Reactor;\r\n\t\tprivate var _room:Room;\r\n\r\n\t\tprivate var _accelX:Number, _accelY:Number;\r\n\r\n\t\tprivate var _accelerometer:Accelerometer;\r\n\r\n\t\tprivate var _currentHStatus:String, _currentVStatus:String;\r\n\t\t\r\n\t\tprivate var _uniqueID:String;\r\n\r\n\t\tpublic function Network() {\r\n\t\t\t\r\n\t\t\t_reactor  = new Reactor();\r\n\t\t\t_reactor.connect(\"169.254.143.2\", 9110);\r\n\t\t\t\/\/_reactor.connect(\"localhost\", 9110);\r\n\t\t\t\/\/_reactor.connect(\"tryunion.com\", 80);\r\n\t\t\t\r\n\t\t\t_uniqueID = \"CHAT_MESSAGE\";\r\n\t\t\t\r\n\t\t\t_reactor.addEventListener(ReactorEvent.READY, _connexionRoom);\r\n\t\t}\r\n\r\n\t\tprivate function _connexionRoom(rEvt:ReactorEvent):void {\r\n\r\n\t\t\t_room = _reactor.getRoomManager().joinRoom(\"Kinessia\");\r\n\r\n\t\t\t_accelerometer = new Accelerometer();\r\n\r\n\t\t\t_accelerometer.addEventListener(AccelerometerEvent.UPDATE, _accelerometerHandler);\r\n\t\t\t\r\n\t\t\tthis.addEventListener(Event.ENTER_FRAME, _ef);\r\n\t\t\t\/\/_room.sendMessage(_uniqueID, true, null, \"right\");\r\n\t\t}\r\n\r\n\t\tprivate function _accelerometerHandler(aEvt:AccelerometerEvent):void {\r\n\r\n\t\t\t_accelX = aEvt.accelerationX;\r\n\t\t\t_accelY = aEvt.accelerationY;\r\n\t\t}\r\n\r\n\t\tprivate function _ef(evt:Event):void {\r\n\r\n\t\t\tif ((_accelX > 0.7) && (_currentVStatus != \"onground\")) {\r\n\t\t\t\t_room.sendMessage(_uniqueID, true, null, \"onground\");\r\n\t\t\t\t_currentVStatus = \"onground\";\r\n\t\t\t}\r\n\r\n\t\t\tif ((_accelX < -0.7) &#038;&#038; (_currentVStatus != \"jump\")) {\r\n\t\t\t\t_room.sendMessage(_uniqueID, true, null, \"jump\");\r\n\t\t\t\t_currentVStatus = \"jump\";\r\n\t\t\t}\r\n\r\n\t\t\tif ((_accelY > 0.7) && (_currentHStatus != \"right\")) {\r\n\t\t\t\t_room.sendMessage(_uniqueID, true, null, \"right\");\r\n\t\t\t\t_currentHStatus = \"right\";\r\n\t\t\t}\r\n\r\n\t\t\tif ((_accelY < -0.7) &#038;&#038; (_currentHStatus != \"left\")) {\r\n\t\t\t\t_room.sendMessage(_uniqueID, true, null, \"left\");\r\n\t\t\t\t_currentHStatus = \"left\";\r\n\t\t\t}\r\n\r\n\t\t\tif (((_accelY < 0.7) &#038;&#038; (_accelY > -0.7)) && (_currentHStatus != \"immobile\")) {\r\n\t\t\t\t_room.sendMessage(_uniqueID, true, null, \"immobile\");\r\n\t\t\t\t_currentHStatus = \"immobile\";\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t\tpublic function set uniqueID(uniqueID:String):void {\r\n\t\t\t_uniqueID = uniqueID;\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>We connect to the server (not localhost here, because we are on the phone \ud83d\ude09 ), and wait if it is ready. Then we join the room. Noticed that you shouldn't let \"CHAT_MESSAGE\" as the uniqueID, you put the previous code. After that we use the phone accelerometer and an EnterFrame to send the phone's position. Here we assume that we stand it on the side ! And we use two vars to store the last position and send only a message if we change it to optimize bandwith !<br \/>\nWe may use a room message listener if we want to handle message from the website.<\/p>\n<p>There are also many listeners to manage connection and pause your game... :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">chatRoom.addEventListener(RoomEvent.JOIN, joinRoomListener);\r\nchatRoom.addEventListener(RoomEvent.ADD_OCCUPANT, addClientListener);\r\nchatRoom.addEventListener(RoomEvent.REMOVE_OCCUPANT, removeClientListener);\r\nchatRoom.addEventListener(RoomEvent.UPDATE_CLIENT_ATTRIBUTE, updateClientAttributeListener);<\/pre>\n<p>Try Union, it is really easy to learn, has a great documentation, many examples... and with the free versions you can handle 1000 connections !! It made my weekend \ud83d\ude00<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For my school game project, I use an iPhone to move my hero thanks to the accelerometer. It can move to left\/right, jump&#8230; and manage informations in a menu. To make the synchronization, I use the Union Platform. There are several ways to realize a synchronization between a smartphone and a website using servers like &hellip; <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/synch-a-phone-with-a-website-using-the-union-platform\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Synch a phone with a website using the Union Platform<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[4,33,11,55],"tags":[15,56,57,58,59],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/286"}],"collection":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/comments?post=286"}],"version-history":[{"count":9,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions"}],"predecessor-version":[{"id":1299,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/286\/revisions\/1299"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=286"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}