Cursors Gone Wild Tutorial

From EsWiki

Jump to: navigation, search

This is a tutorial that covers the steps of using User Variables to show the location of other users' mice.

Contents

What You'll Learn

  • How to use User Variables to show the mice of other users
  • How to hide the appearance of lag

Prerequisites

  • You must have ElectroServer 4 installed and running.
  • You need the client-side ElectroServer 4 API.
  • This tutorial uses the User Variables tutorial as a base, but could use the Advanced Chat as a base also (with a few minor changes).

Download

If you wish to simply download the entire set of Cursors Gone Wild files (source code and compiled), it is found in CursorsGoneWildTutorial.zip.

Let's Get Started!

In the steps below you will learn how to display the mice of other users in the room on the screen.

The Plan

First we should outline the main goal of this tutorial which is:

  • To show the mice of each user in a room to all the other users

To achieve this we are going to use User Variables, which are what we worked with in the last tutorial. Every dozen or so frames, we will update a User Variables that contains our mouse location and send it to the server. Then the server will send the update to the other users, who will then move the mouse to that position. (We will be not just updating the location, as that will look choppy, instead we will ease to the different position).

The first thing we will look at is how to handle the easing and moving of other mice.


Easing the Mice

In different tutorials to come, we will be using the idea of easing objects between positions. In order to make our code reusable, we will create a EaseObject class which will handle the easing for us.

Create a new file call EaseObject.as in the same folder as your .fla .

The class will look like this:


  	package {
  		import flash.display.DisplayObject;
  		
  		public class EaseObject {
        	
  			var m_time:int; //How long til it should arrive at the desination
  			var m_x:Number; //desired x location
  			var m_y:Number; //desired y location
  			var m_object:DisplayObject
  			var m_owner:String; //username of owner
  			
  			public function EaseObject( x, y, owner:String, object:DisplayObject )
  			{
  				m_time = 1;
  				m_object = object;
  				m_object.x = m_x = x;
  				m_object.y = m_y = y;
  				m_owner = owner;
     
  			}
  			
  			public function setDestination( x, y, time )
  			{
   			  m_time = time;
   			  m_x = x;
   			  m_y = y;
  			}
  			
  			public function update()
  			{
     
  				if( m_time < 1 )
  				{
  					m_time = 1;
  				}
     
  				var xDif = m_x-m_object.x;
  				var yDif = m_y-m_object.y;
  				
  				m_object.x += xDif/m_time;
  				m_object.y += yDif/m_time;
  				
  				m_time--;
  			}
  			
  		}
  		
  	}
  


This class stores the x and y coordinates, what display object it refers to and how long is left until it should arrive at its destination. The constructor accepts the starting values while the setDestination function sets the x, y and how long it should take to get to the next spot. The update function will calculate how far it needs to move, and then moves however much it should to maintain a constant speed.

Next, we will look at the changes that will be needed to the Main class.


Updating the Main Class

The user will need to keep track of all the mice in the Main class, so it can move them accordingly. We will use an array, but instead of storing them with numbers, store them with the corresponding username.


  	public static var TAG_XPOSITION:String 			= "x";
  	public static var TAG_YPOSITION:String			= "y";
  	public static var UPDATE_RATE:int   = 15;
  	
  	private var miceList:Array;
  	private var timer:int;
  	
  	public function Main()
  	{
  		miceList = [];
  		timer = 0;
  	}
  


We added an array that will hold all the mice, a timer, and a constructor to Main just to initialize the array (though you could initialize it elsewhere). We also added some static variables that will be used later on to move the mice.

We are going to integrate the display of mice into the chat system. Normally, you would want to separate this into another "module", but for this example we will just keep it all together.

Another thing we should think about is when and what messages need to sent:

  • The constantly changing positions of the mice
  • The current location of the mice when one joins a room
  • Addition of a mouse when a player joins a room
  • Removal of a mouse when that player leaves the room

The way we will simplify this problem is not to worry about addition as mice enter the room (adding the mouse for is already there) or adding the mice for is has just joined. We will just send position updates, and if the mouse is not created, create it at a random location and move to the new desired location.


Listening for User Variable Updates

What we will look at now is listening for User Variable updates. We are going to edit the enableChat and disableChat functions by adding a listener for User Variables being updated and a listener that will be called each frame( ENTER_FRAME ) to both update the position of other mice and send the position of its own mouse.


  	private function enableChatScreen()
  	{
  		es.addEventListener(MessageType.PublicMessageEvent, "onPublicMessageEvent", this);
  		es.addEventListener(MessageType.UserListUpdateEvent, "onUserListUpdateEvent", this);
  		es.addEventListener(MessageType.JoinRoomEvent, "onJoinRoomEvent", this);
  		es.addEventListener(MessageType.ZoneUpdateEvent, "onZoneUpdateEvent", this);
  		es.addEventListener(MessageType.PrivateMessageEvent, "onPrivateMessageEvent", this);
  		es.addEventListener(MessageType.UserVariableUpdateEvent, "onUserVariableUpdateEvent", this);
  		es.addEventListener(MessageType.GetUserVariablesResponse, "onGetUserVariablesResponse", this);
  		addEventListener(Event.ENTER_FRAME, updateMice );
  		addEventListener(MouseEvent.CLICK, onButtonClick);
  		
  		showUserList();
  		showRoomList();
  	}
  	
  	private function disableChatScreen()
  	{
  		es.removeEventListener(MessageType.PublicMessageEvent, "onPublicMessageEvent", this);
  		es.removeEventListener(MessageType.UserListUpdateEvent, "onUserListUpdateEvent", this);
  		es.removeEventListener(MessageType.JoinRoomEvent, "onJoinRoomEvent", this);
  		es.removeEventListener(MessageType.ZoneUpdateEvent, "onZoneUpdateEvent", this);
  		es.removeEventListener(MessageType.PrivateMessageEvent, "onPrivateMessageEvent", this);
  		es.removeEventListener(MessageType.UserVariableUpdateEvent, "onUserVariableUpdateEvent", this);
  		es.removeEventListener(MessageType.GetUserVariablesResponse, "onGetUserVariablesResponse", this);
  		removeEventListener(Event.ENTER_FRAME, updateMice );
  		removeEventListener(MouseEvent.CLICK, onButtonClick);
  		
  		if( window != null )
  		{
  			window = null;
  			removeChild( window );
  		}
     	
  	}
  


Now lets look at the onUserVariableUpdateEvent function. First it gets the id of the user whose mouse has been updated, makes sure it is not their own mouse and that the variable being updated is related to the mouse. It then checks to see if the mouse is created and if not, it creates it. Finally, it gets the mouse's current position from the EsObject and sets that as its desination.


  	public function onUserVariableUpdateEvent( e:UserVariableUpdateEvent )
  	{
  		var mouseOwnerID:String = e.getUserId();
  		if( mouseOwnerID != userID && e.getVariableName() == "mouse" )
  		{
  			//If the userID is not this players
  			
  			if( miceList[mouseOwnerID] == null )
  			{
  				  //Mouse is not created, create it!
  				  var mc:MovieClip = new MouseClip();
  				  addChild( mc );
  				  var randomX:Number = Math.random()*550;
  				  var randomY:Number = Math.random()*400;
  				  miceList[mouseOwnerID] = new EaseObject( randomX, randomY, mouseOwnerID, mc );
     
  			}
  			
  			var mouse:EaseObject = miceList[mouseOwnerID] as EaseObject;
  			var position:EsObject = e.getVariable().getValue();
  			//10 added to make it look smooth
  			mouse.setDestination( position.getFloat(TAG_XPOSITION), position.getFloat( TAG_YPOSITION ), UPDATE_RATE + 10 );
  			
  			
  		}
  	}
  


The updateMice function is called every frame. It loops through all the mice and calls the update function for them to update their position. Then, if enough time has gone by, the mouse position of this user is sent out.

The sendMouseUpdate function sets up a UpdateUserVariableRequest with an EsObject holding the mouse position and then sends it to the server.


  	private function updateMice( event:Event )
  	{
  		timer++;
  		
  		for each( var mouse:EaseObject in miceList )
  		{
  			mouse.update();
  		}
  		
  		if( timer > UPDATE_RATE )
  		{
  			timer = 0;
  			sendMouseUpdate();
  		}
  		
  	}
  	
  	private function sendMouseUpdate()
  	{
  		var update:UpdateUserVariableRequest = new UpdateUserVariableRequest();
  		update.setName( "mouse" );
  		
  		var mouseObject:EsObject = new EsObject();
  		mouseObject.setFloat( TAG_XPOSITION, mouseX );
  		mouseObject.setFloat( TAG_YPOSITION, mouseY );
  		
  		update.setValue( mouseObject );
  		
  		es.send( update );
  		
  	}
  


To end, we will look at handling a user leaving the room and the creation of the MouseClip.


Removing Mice When Users Leave

When a user leaves the room, the mouse will just stop if we leave it as the code is. To fix this, we will find the mouse of the user who left and remove it.


  		public function onUserListUpdateEvent(e:UserListUpdateEvent) 
  		{
  			showUserList();
  			
  			if(e.getActionId() == UserListUpdateEvent.DeleteUser )
  			{
  				  //If a user was removed try to find their mouse and remove it
  				  for( var key:String in miceList )
  				  {
  					if(key == e.getUserId() )
  					{
  						removeChild(miceList[key].m_object);
  						delete miceList[key];
  						break;
  					}
  				  }
  			}
  		}
  


Also, if a player joins a new room, we need to remove all of their mice.


  		public function onJoinRoomEvent(e:JoinRoomEvent):void 
  		{
  			myRoom = e.room;
  			myZone = zoneManager.getZoneById( e.getZoneId() );
  			showUserList();
  			showRoomList();
  			removeAllMice();
     		
  		}
  		
  		private function removeAllMice()
  		{
  			for( var key:String in miceList )
  			{
  				removeChild(miceList[key].m_object);
  				delete miceList[key];
  			}
  		}
  


Change onJoinRoomEvent to the above function, which just calls removeAllMice.

Finally, go into the .fla and create a new MovieClip, exporting it for Actionscript with the name MouseClip. Draw whatever you want in it to show up as a mouse, and your finished!



Finished!

Well done, you now have another tutorial under your belt. From here you can look at Room Variables Tutorial or Joining Games Tutorial.

Personal tools
download