Synch a phone with a website using the Union Platform

For my school game project, I use an iPhone to move my hero thanks to the accelerometer. It can move to left/right, jump… 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 : Flash Media Server, SmartFox Server, BlazeDS… I didn’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… but it’s really expensive ! However there was an alternative with the Google App Engine. We can have a free access to Java and Python server hosting by Google ! It seemed to be great, but SmartFox can’t be deploy on it whereas BlazeDS and GraniteDS can ! These 2 servers use the flex technology… 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… and if your .ipa is well exported, it will not run on iPhone 2G. In fact with the new Air 2.6 you can’t export to old iPhone.

So these months have been really frustrating, until a friend informed me of the release of a new server : the Union Platform. It has been released by Colin Moock who wrote Essential ActionScript 3.0 book.

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® Flash®, Java, C#, and dozens of other languages.

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’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.

So here we go, let’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’t be a big deal, I use it only to dispatch my Event which can be listened on the top of my game.

This is the Union class for my game on my website :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package kinessia.network {
 
	import net.user1.reactor.IClient;
	import net.user1.reactor.Reactor;
	import net.user1.reactor.ReactorEvent;
	import net.user1.reactor.Room;
 
	import com.citrusengine.core.CitrusEngine;
 
	import flash.events.EventDispatcher;
 
	/**
	 * @author Aymeric
	 */
	public class Network extends EventDispatcher {
 
		private var _ce:CitrusEngine;
		private var _reactor:Reactor;
		private var _room:Room;
 
		private var _uniqueID:String;
 
		public function Network() {
 
			_ce = CitrusEngine.getInstance();
 
			_uniqueID = "CHAT_MESSAGE"; //_generateRandomString(7);
 
			_reactor = new Reactor();
 
			_reactor.connect("localhost", 9110);
			//_reactor.connect("tryunion.com", 80);
 
			_reactor.addEventListener(ReactorEvent.READY, _createRoom);
		}
 
		private function _generateRandomString(newLength:uint = 1, userAlphabet:String = "123456789"):String{
 
				var alphabet:Array = userAlphabet.split("");
				var alphabetLength:int = alphabet.length;
				var randomLetters:String = "";
				for (var i:uint = 0; i < newLength; i++){
					randomLetters += alphabet[int(Math.floor(Math.random() * alphabetLength))];
				}
				return randomLetters;
			}
 
		private function _createRoom(rEvt:ReactorEvent):void {
 
			_room = _reactor.getRoomManager().createRoom("Kinessia");
			_room.join();
 
			_room.addMessageListener(_uniqueID, _chatMessageLisener);
		}
 
		private function _chatMessageLisener(fromClient:IClient, message:String):void {
			trace("Guest" + fromClient.getClientID() + " says: " + message);
 
			switch (message) {
 
				case "jump":
					_ce.dispatchEvent(new NetworkEvent(NetworkEvent.JUMP));
					break;
 
				case "onground":
					_ce.dispatchEvent(new NetworkEvent(NetworkEvent.ONGROUND));
 
				case "left":
					_ce.dispatchEvent(new NetworkEvent(NetworkEvent.LEFT));
					break;
 
				case "right":
					_ce.dispatchEvent(new NetworkEvent(NetworkEvent.RIGHT));
					break;
 
				case "immobile":
					_ce.dispatchEvent(new NetworkEvent(NetworkEvent.IMMOBILE));
					break;
			}
		}
 
		public function get uniqueID():String {
			return _uniqueID;
		}
	}
}

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.
We add a listener if we receive a message from the phone and finally we dispatch it !

Now the phone class :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package kinessia.network {
 
	import net.user1.reactor.Reactor;
	import net.user1.reactor.ReactorEvent;
	import net.user1.reactor.Room;
 
	import flash.display.Sprite;
	import flash.events.AccelerometerEvent;
	import flash.events.Event;
	import flash.sensors.Accelerometer;
 
	/**
	 * @author Aymeric
	 */
	public class Network extends Sprite {
 
		private var _reactor:Reactor;
		private var _room:Room;
 
		private var _accelX:Number, _accelY:Number;
 
		private var _accelerometer:Accelerometer;
 
		private var _currentHStatus:String, _currentVStatus:String;
 
		private var _uniqueID:String;
 
		public function Network() {
 
			_reactor  = new Reactor();
			_reactor.connect("169.254.143.2", 9110);
			//_reactor.connect("localhost", 9110);
			//_reactor.connect("tryunion.com", 80);
 
			_uniqueID = "CHAT_MESSAGE";
 
			_reactor.addEventListener(ReactorEvent.READY, _connexionRoom);
		}
 
		private function _connexionRoom(rEvt:ReactorEvent):void {
 
			_room = _reactor.getRoomManager().joinRoom("Kinessia");
 
			_accelerometer = new Accelerometer();
 
			_accelerometer.addEventListener(AccelerometerEvent.UPDATE, _accelerometerHandler);
 
			this.addEventListener(Event.ENTER_FRAME, _ef);
			//_room.sendMessage(_uniqueID, true, null, "right");
		}
 
		private function _accelerometerHandler(aEvt:AccelerometerEvent):void {
 
			_accelX = aEvt.accelerationX;
			_accelY = aEvt.accelerationY;
		}
 
		private function _ef(evt:Event):void {
 
			if ((_accelX > 0.7) && (_currentVStatus != "onground")) {
				_room.sendMessage(_uniqueID, true, null, "onground");
				_currentVStatus = "onground";
			}
 
			if ((_accelX < -0.7) && (_currentVStatus != "jump")) {
				_room.sendMessage(_uniqueID, true, null, "jump");
				_currentVStatus = "jump";
			}
 
			if ((_accelY > 0.7) && (_currentHStatus != "right")) {
				_room.sendMessage(_uniqueID, true, null, "right");
				_currentHStatus = "right";
			}
 
			if ((_accelY < -0.7) && (_currentHStatus != "left")) {
				_room.sendMessage(_uniqueID, true, null, "left");
				_currentHStatus = "left";
			}
 
			if (((_accelY < 0.7) && (_accelY > -0.7)) && (_currentHStatus != "immobile")) {
				_room.sendMessage(_uniqueID, true, null, "immobile");
				_currentHStatus = "immobile";
			}
 
		}
 
		public function set uniqueID(uniqueID:String):void {
			_uniqueID = uniqueID;
		}
	}
}

We connect to the server (not localhost here, because we are on the phone 😉 ), 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 !
We may use a room message listener if we want to handle message from the website.

There are also many listeners to manage connection and pause your game… :

1
2
3
4
chatRoom.addEventListener(RoomEvent.JOIN, joinRoomListener);
chatRoom.addEventListener(RoomEvent.ADD_OCCUPANT, addClientListener);
chatRoom.addEventListener(RoomEvent.REMOVE_OCCUPANT, removeClientListener);
chatRoom.addEventListener(RoomEvent.UPDATE_CLIENT_ATTRIBUTE, updateClientAttributeListener);

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 😀

Leave a Reply

Your email address will not be published. Required fields are marked *