Erain 3D
-->

RedSandy Project

Introduction to the RedSandy project and SVN : http://code.google.com/p/redsandy/

Installing the Red5 'Engine' application : http://code.google.com/p/redsandy/wiki/Install

Security Considerations : http://code.google.com/p/redsandy/wiki/Security

AS Docs: http://www.thebitstream.com/api/

RedSandy has been fully updated to server version .7

At the time of this post 2008/06/25, it is also compatible with the trunk.

The Latest

RedSandy 2.0

Introducing RedSandy 2.0

Although there are no samples yet, the library is available at the svn. A new ActionScript Class, 'Ocotillo', improves speed and sync over Omnicron. As well, there is no new java at this point, but both Classes run off of the Omnicron webapp in the original RedSandy.

The server Events are being reduced as well in the new java, and there are only about 4 events to listen for: Status, Scope, player join/leave, SharedObject Update. The rest are removed. The communication method abandons all nc.call methods for so.send. The results are much faster flash application, and higher capacity on the server.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()" layout="absolute">
<mx:Script>
	<![CDATA[
		/** 
		 * Simple sample of typical app handling. We have our list of users, a name and a connection handler.
		 * 
		 * */
		import mx.collections.ArrayCollection;
		import sandy.red5World.core.*;
		import sandy.red5World.events.*;
		/**
		 * My name
		 * */
		public var username:String="username";
		/** 
		 * Everyone's shared objects.
		 * */
		public var users:ArrayCollection=new ArrayCollection();
		/**
		 * Red5 connection.
		 * */
		public var red5:Ocotillo;
 
		/**
		 * Set up red5 and event listeners.
		 *   */
		public function init():void
		{
			//Build session and add listeners
			red5=new Ocotillo(username);
			// status 
			red5.addEventListener(WorldEvent.WORLD_READY, onStatus);
			red5.addEventListener(WorldEvent.WORLD_FAIL, onStatus);
			red5.addEventListener(WorldEvent.WORLD_EXIT, onStatus);
			// User has left
			red5.addEventListener(ScopeEvent.USER_PART, removeUser);
			// User so has been updated
			red5.addEventListener(WorldEvent.SO_UPDATE, onSync);
			// Set address of server with scope.
			red5.red5Address("rtmp://localhost/omnicron/roomname");
			//Go!
			red5.red5Connect();
		}
 
		/** 
		 * Add user.
		 * */
		public function newUser(obj:Object):void
		{
			trace(obj.name);
			users.addItem(obj);
		}
		/** 
		 * Shared object updated.
		 * */
		public function onSync(we:WorldEvent):void
		{
			 trace("So  :"+we.uName);
 
			 var so:SharedObject = we.sharedObject;
			 if(so.data.name==username)
			 {
			 	if(so.data.code!="ready")
			 	{
			 		so.setProperty("code","ready");
			 		return newUser(so.data);		 			
			 	}			 	
			 }
			 else 
			 {
			 	if(users.contains(so.data)==false)
			 	{	
			 		if(so.data.code=="ready")
			 		{		 		
			 			return newUser(so.data);	
			 		}
			 	}
			 }
 
		}
		/** 
		 * Sandy is ready with scene3d
		 * */
		public function onSandy():void
		{
			trace("Sandy ready");
			//Add sprite to stage component.
			//  UIComponent.addChild( red5.sprite());
		}
		/** 
		 * Red5 is ready for service.
		 * */
		public function onRed():void
		{
			//Need functions?
		}
		/** 
		 * User has parted
		 * */
		public function removeUser(we:ScopeEvent):void
		{
			for each(var obj:Object in users)
			{
				if(obj.name==we.m_sName)
				{
					users.removeItemAt(users.getItemIndex(obj));
					break;
				}
			}
		}
		/** 
		 * Red5 and sandy session status.		 * 
		 * */
		public function onStatus(we:WorldEvent):void
		{
			switch(we.uName)
			{
				case "vectors":
				onSandy();
				break;
 
				case "red5":
					switch(we.type)
					{
						case WorldEvent.WORLD_READY:
						onRed();
						break;	
						// handle status
						case WorldEvent.WORLD_FAIL:
						break;
						// handle status
						case WorldEvent.WORLD_EXIT:
						break;					
					}				
				break;							
			}
		}
	]]>
</mx:Script>	
</mx:Application>

More to come soon!

The Events

At all times you can know who is connected to the application, and who is connected to a room. While connected to a room, each user has a shared object and a position in a sandy world. Server side, I support retrieving the names of scopes/rooms at single depth such as “rtmp:localhost/omnicron/private”, and “rtmp:localhost/omnicron/lobby”. The shared objects are already laid out with properties “name,tag,code,x,y,z”. With all these features built in, I hope the developer can move on to writing killer red5 applications without basic troubles, or starting from scratch every time.

//Connect Success or Scene3d is ready. Check event.uName for "vectors" or "red5".
red5.addEventListener(WorldEvent.WORLD_READY,worldReady);
//Connection Closed.
red5.addEventListener(WorldEvent.WORLD_EXIT, worldExit);
//Connection rejected or server issues.
red5.addEventListener(WorldEvent.WORLD_FAIL, worldfail);
 
//New ID as joined the application.
red5.addEventListener(WorldEvent.USER_ADD, newUser);
//ID is ending session or reconnecting.
red5.addEventListener(WorldEvent.USER_CLOSE, userClose);	
 
// Please refer the the red5 documentation as to the order of events.
// I forward the scope events from red5 to sandy.
// When an ID has joined the same scope/room as yours,
// red5 calls us and the name is added to the vector manager which 
// fires the scope event. 
red5.addEventListener(ScopeEvent.USER_JOIN,newPlayer);
// ID has left the same scope/room as yours.
red5.addEventListener(ScopeEvent.USER_PART, playerClose);
 
// An ID has joined an existing room or creating a new room.
red5.addEventListener(ScopeEvent.ROOM_START, newRoom);			
//A scope is empty.
red5.addEventListener(ScopeEvent.ROOM_STOP, roomClose);
//Your id has entered or passed through a scope/room.
red5.addEventListener(ScopeEvent.SCOPE_CHANGE, scopeChange);
 
// Each  ID in a scope has an associated SO to utilise.
red5.addEventListener(WorldEvent.SO_UPDATE, soUpdate);
New Features

Now supporting 'rooms' and using remote SharedObjects as the primary messengers. Major Red5 Application update to support the new features. Rooms(Scopes) created as direct children to the main application scope now fully supported. Deeper scopes possible but not automated by default. OmniTests.mxml sample on the svn show the new methods and scope events available. Additional Docs to come.

The Animation Engine

Ever since I animated sprites with the ti-99/4a I realized the need for storing a velocity and using a loop to have a nice display. I could fly them down to the bottom of the T.V. for a gentle landing. The first thing you should know about the VectorManager, is the Red5vector class. Each complex object you want to animate will be assigned one.

	public var m_sName:String;
	public var m_vPosition:Vector=new Vector();
	public var m_vRotation:Vector=new Vector();
	public var m_vVelocity:Vector=new Vector();
	public var m_vRadialVelocity:Vector=new Vector();

The most intimidating aspect of the Vectomanager is the interface to adjust vectors. It is writen to be compatible with 'invoke' calls from java applications(red5). The following snippet adjusts red5vector named “box”, vector number 4 m_vRadialVelocity, values 0, .1, .1. You should note these values are added to the existing values.

engine.vectorUpdate(new Array("box",4,0,.1,.1));

You can reference the vectors directly with this method

getR5Vector("box").m_vRadialVelocity.x=0;
// or for big changes...
var localRef:Red5Vector=getR5Vector("box");
localRef.m_vVelocity.x=0;
localRef.m_vVelocity.y=0;
localRef.m_vVelocity.z=0;

The int definitions.

// 1= position, 2= rotation, 3= velocity, 4 = rotational velocity
engine.vectorUpdate(new Array(name,vector ID, x, y, z));

Now I think you have enough information to follow the example.

package {
	import flash.display.Sprite;
	import sandy.red5World.core.VectorManager;
	import sandy.primitive.Box;
 
	public class Animator extends Sprite
	{
		public function Animator():void
		{
			//Construct the manager
			var engine:VectorManager=new VectorManager("box");
			//add it to the stage
			addChild(engine);
			//start it		
			engine.start();
 
			// right now I have a scene3d a camera and a group.
			// also there is a vector named "box"
			var b:Box=new Box("box",50,25,12.5);
			engine.world.root.addChild(b);
 
			// I will animate the box
			// Radial velocity input z and y both += .1
			engine.vectorUpdate(new Array("box",4,0,.1,.1));			
			// Linear velocity input z += .1
			engine.vectorUpdate(new Array("box",3,0,0,.1));	
 
			// There is also a vector named "camera"
			// Adjust camera z velocty += .09
			engine.vectorUpdate(new Array("camera",3,0,0,.09));	
			//I am now following the box at .01 z units per second slower than the box.
		}
 
	}
}

Past Articles

OmniCron

Administration Sample :http://code.google.com/p/redsandy/wiki/OmniCronAdministration

Introducing the OmniCron :http://code.google.com/p/redsandy/wiki/OmniCron

Engine Related

Basic Connection Application :http://code.google.com/p/redsandy/wiki/Connection

Application Templates :http://code.google.com/p/redsandy/wiki/ApplicationTemplates

Chat sample with 'shortMessage' api :http://code.google.com/p/redsandy/wiki/Chat

Rtmp Objects :http://code.google.com/p/redsandy/wiki/RtmpBroadcasterReceiver

Known Bugs of the Engine

Lets say You made your main setting as a transformGroup named “root”, and a player named “root” joins the game. When he leaves, so does the setting. Names can be restricted server side, and maybe in the future, name checks will include current display objects, and not just current netconnection ID's.

The biggest problem I have is remembering all the details

Detail for OmniCron: Two 'world ready' events are fired, one for red5 and one for scene3d

Solution: Check the name of the event.

By adding objects or vectors on this event and not checking the name of the event you can have multiple objects with the same name.

Symptoms:

Input of vector changes appears to not work: The animator does not do a redundant check for children of a single name.

Attempting to access server assets such as the shared objects or calls using the net connection will result in a null object error: The event was fired for the scene3d ready, not the server connection. Cheack WorldReady.name property.

Until next time...

rsbsmall.jpg