* Additional call to makeClone function to interactive sample code would create a new instance of a character. This function also sets up navigation controller for a new instance.

/**
* This functin make a clone of Model node and sets Navigaion Contraller
*/privatefunction makeClone():void{// First lets find the root node of a character// we know in advance it's Id is 'Cube'varnodename:String = "Cube";
var model_node:Node3d = this.animator.source.find(nodename) as Node3d;
if(!model_node){
statusText.visible = true;
statusText.text = "Failed to make clone. Not found node: " + nodename;
return;
}// next step is to make a clone instance of a character nodevar cloned_model_node:Node3d = model_node.clone();
// A cloned instance of a node if not attached is handing in the air// To make it visible we need to add it to a scene, whic is KeyFrame// There is only one KeyFrame ( with infinite duration) and we know Id // in advance by looking at the file.var kfname:String = "Scene_kf";
var kf:KeyFrame3d = this.animator.source.find(kfname) as KeyFrame3d;
if(!kf){
statusText.visible = true;
statusText.text = "Failed to make clone. Not found keyframe: " + kfname;
return;
}// adding cloned node to Keyframe
kf.addNode(cloned_model_node);
// This step is also importan to understand.// Although we added node to a scene, the actual rendering is taking place// in Rendering engine, in this case papervision3D. So Cast3d is just manupulating // with transforms and geometry. This step populates rendering engine with newly created // node's data. Xc3 file loader does it for you, after it's done, you need to do that explicitly.
cloned_model_node.register(this.animator, kf);
// lets create navigation conrloller for new node.var nc:NavigationController = new NavigationController(cloned_model_node,"navigator");
_navigations.push(nc);
// We know that "cube" node actually represents Skined geometry, which means// the motion is controlled by another skeleton node(s), in this case "lowerBack" node is// root skeleton node( see source file)nodename = "lowerBack";
var skeleton_node:Node3d = this.animator.source.find(nodename) as Node3d;
// lets make a clone of that too. Otherwise both original chatecter skin and cloned one // will be controlled by same skeleton node(s). var cloned_skeleton_node:Node3d = skeleton_node.clone();
if(!cloned_skeleton_node){
statusText.visible = true;
statusText.text = "Failed to set Cloning for node: " + nodename;
return;
}// add to same scene
kf.addNode(cloned_skeleton_node);
// populate rendering engine
cloned_skeleton_node.register(this.animator, kf);
// This step required only for Skin var skin:Skin3d = cloned_model_node.part as Skin3d;
if(skin){// The cloned version of skinned node holds the references to original skeleton bones// Now we need to reassign to the bones of new ( cloned) skeleton nodes// binding works in the way that it tries to find matching id of old bone in provided skeleton bone branhes// once it finds it does the replacement. If fails to find any single bone, the whole process fails.if(!skin.bindBones(cloned_skeleton_node)){
statusText.visible = true;
statusText.text = "Failed to make clone. Clould not bind skin: " + skin.id + " to node: " + cloned_skeleton_node.id;
return;
}}var tarck_id:String;
var motionAlias:String;
// now we add a 'walking' motion which is represented by MotionGroup class instance with id == "lowerBack_motion"// again, we know that by looking at source file.
tarck_id = "lowerBack_motion";
motionAlias = "walk";
if(!nc.addMotion(cloned_skeleton_node, tarck_id, motionAlias)){
statusText.visible = true;
statusText.text = "Failed to add Motion " + motionAlias + " for track: " + tarck_id;
return;
}// another motion is a 'jump' motion with id == "lowerBack_motionjump"
motionAlias = "jump";
tarck_id = "lowerBack_motionjump";
if(!nc.addMotion(cloned_skeleton_node, tarck_id, motionAlias)){
statusText.visible = true;
statusText.text = "Failed to add Motion " + motionAlias + " for track: " + tarck_id;
return;
}// lets move the newly created model away from intial position so it does not interlap with original
nc.position.x += 5.0;
nc.rotation.x = 0; nc.rotation.y = 0; nc.rotation.z = 1; nc.rotation.w = 60*Math.PI/180.0 ;
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, this.keyDownHandler);
}