Back to Content

Creating a scripted behavior using JavaScript


You can create your own behaviors in CopperCube using JavaScript. They will behave just like the native, built-in ones. This tutorial will show how to do this.

If you haven't read yet the tutorial on how to creating a scripted action using JavaScript, please do this now. This tutorial is building on that one.

Let's start

As in the creating an action tutorial, create a new file in the extension directory (Documents\CopperCube\extensions on Windows, or ~/Documents/CopperCube/extensions on Mac OS X) and name it "behavior_moveBetweenPoints.js". Open it with a text editor, and fill the content with this:

/*
  <behavior jsname="behavior_moveBetweenPoints" 
	description="Move scene node between 2 points">
      <property name="EndPoint" type="vect3d" default="100.0, 100.0, 100.0" />
      <property name="Speed" type="float" default="0.02" />
  </behavior>
*/

behavior_moveBetweenPoints = function()
{
	this.LastTime = null;
	this.StartPoint = null;
};

// called every frame. 
//   'node' is the scene node where this behavior is attached to.
//   'timeMs' the current time in milliseconds of the scene.
// Returns 'true' if something changed, and 'false' if not.
behavior_moveBetweenPoints.prototype.onAnimate = function(node, timeMs)
{
   // get the time since the last frame
  
  if (this.LastTime == null)
  {
    // we were never called before, so store the time and cancel
    this.LastTime = timeMs; 
    this.StartPoint = ccbGetSceneNodeProperty(node, 'Position');
    return false;
  }
  
  var delta = timeMs - this.LastTime;
  this.LastTime = timeMs;
  if (delta > 200) delta = 200; // never do movements longer than 200 ms
  
  // move 
  
  var pos = ccbGetSceneNodeProperty(node, 'Position');
      
  var movementVector = this.EndPoint.substract(this.StartPoint);
  
  if (pos.substract(this.StartPoint).getLength() > movementVector.getLength())
  {
    // end point reached, switch direction and restart
      
    var tmp = this.StartPoint;
    this.StartPoint = this.EndPoint;
    this.EndPoint = tmp;
      
    movementVector = this.EndPoint.substract(this.StartPoint);
  }   
  
  // move
      
  movementVector.normalize();
  
  pos.x += movementVector.x * delta * this.Speed; 
  pos.y += movementVector.y * delta * this.Speed; 
  pos.z += movementVector.z * delta * this.Speed; 
          
  // set new position
  
  ccbSetSceneNodeProperty(node, 'Position', pos);
  
  return true;
}

If you start CopperCube, a new Behavior named "Move scene node between 2 points" will be available. Now in the default scene of CopperCube, click on the 3D cube 'cubeMesh1', select the 'Behavior Tab', click '+' to add a new behavior, and select this new behavior which you should find under "Scripted Behaviors".





If you now start the app for example as Windows .exe or Mac OS X .app, then this behavior will be run and the cube the behavior is attached to will move continuously between its current position and the one specified in the parameter 'EndPoint', with the speed 'Speed'. Your first own behavior worked!

How it works

The XML in the header of the behavior script works just like for actions, as described in the tutorial on how to creating a scripted action, also all parameter types like 'string', 'color', 'texture' etc are available there. All rules are the same here: We need to specify the name of the class (in this case "behavior_moveBetweenPoints") and create a constructor for it looking like below. The only difference to actions: The javascript class name and file name must start with 'behavior_' instead of with 'action_'.
behavior_moveBetweenPoints = function()
{
	this.LastTime = null;
	this.StartPoint = null;
};

In the constructor, we initialize two variables, which we need later: The last time value when the behavior was executed so we can move the cube smoothly independent of the current frame rate, and the start point of the scene node this behavior is attached to, in this case the cube.
The next function is executed every frame, and does the actual work: Moving the cube between two points:
behavior_moveBetweenPoints.prototype.onAnimate = function(node, timeMs)
{
    ...
}

The function needs to be named 'onAnimate', and accepts two parameters: The code inside this function just moves the node by using the ccbGetSceneNodeProperty() and ccbSetSceneNodeProperty() for obtaining and setting the 3d position of the node between the two points. Every time the function onAnimate() is called by CopperCube, the node is moved by this function a bit more into the direction of the EndPoint property, and if the EndPoint has been reached, the movement direction is reversed.


Adding keyboard input

So far so good, but what if we want to add some keyboard input to our behavior? Actually, this is not that difficult. We only need to add a function for handling keyboard input to our behavior. To do this add the following code to the end of the behavior_moveBetweenPoints.js file:
// parameters: key: key id pressed or left up.  
// pressed: true if the key was pressed down, false if left up
behavior_moveBetweenPoints.prototype.onKeyEvent = function(key, pressed)
{
  if (key == 32) // 'Space' key
  {
     if (pressed)
        this.Speed = 0.02;
     else
        this.Speed = 0.0;
  }
}

If a key is pressed or released, this function is called. For this example, we set the 'this.Speed' property to 0 if the space bar is released and to the default value (0.02) again once it is pressed. This makes the cube move only if the space bar is pressed. Easy. :)
The codes are the standard Windows key codes. Popular ones are 37 for the left cursor key, 38 for up, 39 for right, 40 for down or 32 for space.

Adding mouse input

Getting mouse input is very similar to keyboard input support. Also, if this is enough for you, you can simply query the current mouse coordinates with the functions ccbGetMousePosX() and ccbGetMousePosY(). For getting mouse button events, add this function:
// mouseEvent: 0=mouse moved, 1=mouse wheel moved, 2=left mouse up,
//     3=left mouse down, 4=right mouse up, 5=right mouse down
behavior_moveBetweenPoints.prototype.onMouseEvent 
           = function(mouseEvent, mouseWheelDelta)
{
  // handle mouse input here
}