SmoothStep2D User Guide

Core functionality

Introduction

SmoothStep2D is a 2D Game development framework, written in javascript that uses HTML5 Canvas element for rendering, all available web browser features like WebAudio, XMLRequest, etc. and a set of classes for real time and math operations to provide a complete and flexible API, that let you focus your effort in implementing gameplay. The API is inspired in Sparrow Framework class design, a really good framework for developing native iOS games.

The feature list of SmoothStep2D is constantly growing, since it's release one or more new features has been added per week and a lot of bug and design fixes has been done. There is a list of some of it's main features:

If you want to collaborate with SmoothStep2D project you can report issues or sugerences in the Github Issue Tracker, if you are interested in contribute to SmoothStep2D in another way, make me know anyway with the issue tracker or an email.

Getting started

To start using SmoothStep2D you need to create an html file with the following setup.

<canvas id="mainCanvas" width="512" height="512"></canvas>
<script src="http://galloman.github.com/ss2d/lib/ss2dLib-min.js"></script>
<script>
	//create a view
	var view = new ss2d.View('mainCanvas');

	//canvas background color
	view.mBackgroundFillstyle = '#cccccc';

	//run the game
	view.startLoop();
</script>		
Run this code
Code sample 1.1: Scene setup with ss2d.View

What we are doing here is creating a canvas element with the id "mainCanvas" and a size of 512x512 pixels, you can set any size for canvas, even full screen. Then we add the minified ss2d library, wich brings all ss2d objects you need to draw and interact with the scene. The library can be added in other ways, you can download it and upload to your own server. You can also checkout the source code from the github repository and build your own version of the library or build a single file with all the library and your application together, this is a more advanced topic explained here.

The next thing we do is create a script that will contain the logic of our game or application, of course you can write this code in a separate .js file and include it to the html page. In this script the first we are going to do is instance a ss2d.View, this object takes the canvas wich id we pass as the first parameter and create all the needed stuff to render a scene inside it and capture the player input related to the canvas element like mouse or touch position and the keys that the user is actually pressing. Then in this example we choose a different background color with the mBackgroundFillstyle property from our ss2d.View object. Finally we run our view calling the startLoop method that will start to update the contents of the scene at 60 times per seconds.

At this point the only thing we will see here is a big grey square with nothing inside, let's add for example an ss2d.Quad object and make it moves 20 pixels per second.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//instance a quad object
var quad = new ss2d.Quad(23,  //horizontal location in pixels from the canvas left
						 125, //vertical location in pixels from the canvas top
						 50,  //the width size of our quad
						 50,  //the height size of our quad
						 '#ff0000');  //finally, the color

//add the quad object to the main scene
view.mMainScene.addObject(quad);

//make the quad move 20 pixels per second to the right.
quad.tick = function(deltaTime)
{
	this.mLocation.mX += 20*deltaTime;
};

view.startLoop();	
Run this code
Code sample 1.2: Animated ss2d.Quad

In this code we instanced an ss2d.Quad object, this contains all the needed information and methods to render a quad on our scene, in the constructor we pass the location, the size and the color of the quad. Then we acces to the current rendering scene with the mMainScene property from the view and call addObject method passing the recently created quad object as a parameter.

Now we have a red square drawed on our scene at 23,125 location from the top-left corner of our canvas. Then we override the tick method of the quad object to give it a behaviour. The tick method is called by the view loop on each frame passing the delta time that has been passed since the last frame was rendered, it is usually 0.016 secons at 60 frames per second (1 / frame rate). Within this method we acces to the mLocation property of our quad (represented by the this keyword), this property is an ss2d.Point and is used to set where is located the object in the scene, initially we set it at 23,125 in the constructor, now we are adding to the mX property 20 pixels multiplied by the deltaTime, this means that we want to move our object 20 pixels per second but this frame we add only the distance equivalent to the time passed sinsce the last frame was rendered, this way we get a smooth animation of our quad moving to right at 20 pixels per second.

Quads and Sprites

In SmoothStep2D all objects that are displayed on the scene extends a class named ss2d.DisplayObject, an abastract class that contains the base properties and methods needed to update and render objects every frame, you can see it in the API class reference. So, the combination of a ss2d.DisplayObject and some component we want to show in the scene like a colored rectangle or a texture can become a new class extending ss2d.DisplayObject or a child class that inherits from him. The ss2d.Quad class is an example of that, ss2d.Quad inherits from ss2d.DisplayObject adding some properties and overriding methods like render to achieve what the quad needs to be rendered. Another class that borns from the combination of ss2d.Quad and a texture is ss2d.Sprite wich we can use as follows to show this texture in the scene.

Enemy Bug.png
var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//instance a sprite object
var sprite = new ss2d.Sprite(23, 125, 101,  171,  //same four first parameters as ss2d.Quad
						   	'assets/textures/Enemy Bug.png');  //the texture file

//add the sprite object to the main scene
view.mMainScene.addObject(sprite);

//change the sprite transparency
sprite.mAlpha = 0.7;

//change the pivot of the sprite (point of rotation) to its center
sprite.mPivotX = sprite.mWidth*0.5;
sprite.mPivotY = sprite.mHeight*0.7;

//moving and rotating the sprite
sprite.tick = function(deltaTime)
{
	this.mLocation.mX += 10*deltaTime;
	this.mRotation -= Math.PI*0.5*deltaTime;
};

view.startLoop();	
Run this code
Code sample 2.1: Adding textures to the scene with ss2d.Sprite

In the above sample we instance an ss2d.Sprite at location 23,125 with a size of 101x171 pixels and the Enemy Bug.png texture. The ss2d.Sprite constructor will take this texture path and load it automatically as an Image element to be used for rendering, if two or more sprites use the same texture you can continue using the path as a reference because the framework saves wich resources has been previously loaded and cache it's data instead of trying to request again from the server, you can read more about resource loading in this section. We also change some properties inherited from ss2d.DisplayObject like mAlpha to set the level of transparency from 0 to 1 or the sprite's pivot with mPivotX and mPivotY properites. We also give a behaviour to our sprite overriding the tick method that will move the sprite 10 pixels per second to right direction and will rotate it counterclockwise. The rotation is measured in radinas wich means 1 revolution = 2 x PI, so in this sample the bug will do an spin every 4 seconds.

User input

SmoothStep2D provides an interface to read the state of the user input, specifically the mouse or touch location in canvas space, the state of the mouse main button and wich keyboard keys are pressed in each frame. To get this information we must acces to the instance of ss2d.Input that the ss2d.View object creates and updates for us. If we instanced our ss2d.View in a variable called view like in the code samples from other sections we can access to user input state through the mInput property of the view object, but the recommended way to acces to the active view and its properties from anywhere in your code is using a global static property from ss2d namespace called CURRENT_VIEW, so ss2d.CURRENT_VIEW.mInput gives us the ss2d.Input object used by our view to collect the user input. Let's see how to use it setting the location of an sprite to the mouse location.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//instance the sprite and add to the scene
var sprite = new ss2d.Sprite(256, 256, 101,  171, 'assets/textures/Star.png'); 
view.mMainScene.addObject(sprite);

//change the pivot of the sprite (point of rotation) to its center
sprite.mPivotX = sprite.mWidth*0.5;
sprite.mPivotY = sprite.mHeight*0.6;

//update the sprite state with tick
sprite.tick = function(deltaTime)
{
	//get the user input state
	var input = ss2d.CURRENT_VIEW.mInput;

	//set the sprite location to the mouse coords
	this.mLocation.mX = input.mMouseX;
	this.mLocation.mY = input.mMouseY;
};

view.startLoop();	
Run this code
Code sample 3.1: Set a sprite following mouse

In the above sample we use mMouseX and mMouseY properties from the input object to get the mouse location relative to the canvas top-left corner. We can also move an object using keys like W,A,S,D, to do so we need to call a method from the input object named isKeyPressed passing as a parameter the key code we want to check, for that we can use ss2d.Input.Keys namespace wich contains all key codes referenced by its character and some special keys like SHIFT, TAB, CTRL, the arrows, etc. Let's see how to move a quad with the keyboard.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//instance the quad, add to the scene, center it's pivot.
var quad = new ss2d.Quad(256, 256, 50,  100, [255, 0, 0]); 
view.mMainScene.addObject(quad);
quad.mPivotX = quad.mWidth*0.5;
quad.mPivotY = quad.mHeight*0.5;

//move the quad with W A S D keys
quad.tick = function(deltaTime)
{
	//get the user input state
	var input = ss2d.CURRENT_VIEW.mInput;

	var speedMultiplier = 1;

	//if SHIT key is pressed
	if(input.isKeyPressed(ss2d.Input.Keys.SHIFT))
	{
		//change the speed multiplier
		speedMultiplier = 2;
	}

	//if W key is pressed
	if(input.isKeyPressed(ss2d.Input.Keys.W))
	{
		//move forward (-Y) 200 pixels per second
		this.mLocation.mY -= 200 * speedMultiplier * deltaTime;
	}

	//if S key is pressed
	if(input.isKeyPressed(ss2d.Input.Keys.S))
	{	
		//move backwards (+Y) 200 pixels per second
		this.mLocation.mY += 200 * speedMultiplier * deltaTime;
	}

	//if A key is pressed
	if(input.isKeyPressed(ss2d.Input.Keys.A))
	{	
		//move left (-X) 200 pixels per second
		this.mLocation.mX -= 200 * speedMultiplier * deltaTime;
	}

	//if D key is pressed
	if(input.isKeyPressed(ss2d.Input.Keys.D))
	{	
		//move right (+X) 200 pixels per second
		this.mLocation.mX += 200 * speedMultiplier * deltaTime;
	}

	//if SPACE key is pressed this frame and was not pressed the previous frame
	if(input.isKeyPressed(ss2d.Input.Keys.SPACE) && !this.mWasSPACEPressed)
	{	
		//change to a random color from 0x000000 to 0xffffff
		this.mColor.setValue(Math.random() * 0xffffff);
	}

	//save the current state of the SPACE key
	this.mWasSPACEPressed = input.isKeyPressed(ss2d.Input.Keys.SPACE);
};

view.startLoop();	
Run this code
Code sample 3.2: Moving a quad with WASD keys

In the code sample 3.2 we move the quad using the W, A, S and D keys. We also added a multiplier that makes the quad move at 400 pixels per second instead of 200 while SHIFT key is pressed, and finally we check if the SPACE key is pressed this frame to change the color. In this final part, we check that SPACE key is not only pressed this frame, but it also was not pressed the previous frame, if we do not do it this way the color will be changed 60 times per second while the user hold the space bar. To doing so we save the SPACE key state in a custom property named mWasSPACEPressed at the end of tick execution, then the next frame we will know if the SPACE key was already pressed the previous frame.

In fact, the mWasSPACEPressed property does not exists in the ss2d.Quad definition or parent classes, it's added on the fly the first time we assign it, thats one of the advantages that javascript brings to us as a scripting language, but don't let this javascript features make your code less comprehensive. It's better to declare this property before it will be used, just after we instance the ss2d.Quad for example, and add a comment explaining what is it's task in our game logic. Even better, when you have some custom properties and custom methods on a built-in object, it's recommended to define a new class extending the ss2d.Quad or whatever class you need from SmoothStep2D Framework, this topic is explained in Extending prototypes section.

An other interesting part is how we change the mColor property, if you check how color is assigned in the constructor and check previous code samples where we use colored quads, you can see three different ways to assign a color, it can be a string with a hex representation of the color like '#ff0000', an array with red, green, and blue components like [255, 0, 0] or an integer value between 0 and 16777215 or what is the same between 0x000000 and 0xffffff. To keep this flexibility the mColor property is an object of type ss2d.Color and it's value must be set with the method setValue that does this color format conversion.

Containers and Scene

As you can see in previous samples, if you need to show and update a DisplayObject like a Sprite or Quad you must add it to the scene. The scene is in fact another object of a type that inherits from ss2d.DisplayObject, the ss2d.DisplayObjectContainer. When you add any DisplayObject to a DisplayObjectContainer it becomes a children of this container, and inherits all transformations applied to it's parent. What it means is that if you have a container with three child objects and you rotate or set a location for the container all it's children will be rendered with this transformation applied plus their own transformation. Let's illustrate the explanation with a sample:

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create a small blue quad that will be at the 0,0 location relative to the container location
var smallQuad = new ss2d.Quad(0, 0, 20,  20, '#3356ff'); 

//create a red quad that will be at 20,50 location relative to the container location
var bigQuad = new ss2d.Quad(20, 50, 40,  40, '#ff0000'); 

//now create the container at 20,20 location relative to the scene (scene is another container located at 0,0 relative to the canvas)
var container = new ss2d.DisplayObjectContainer(20, 20);

//adding the container to the main scene
view.mMainScene.addObject(container);

//adding the two quads to the container
container.addObject(smallQuad);
container.addObject(bigQuad);

//text object that tells us the mouse location
var mouseLocText = new ss2d.TextSprite(0, 0, '', '#000000', 14);
view.mMainScene.addObject(mouseLocText);
mouseLocText.tick = function(deltaTime)
{
	var input = ss2d.CURRENT_VIEW.mInput;
	this.mTextString = input.mMouseX+','+input.mMouseY;
	this.mLocation.set(input.mMouseX + 10, input.mMouseY);
};

view.startLoop();	
Run this code
Code sample 4.1: Inherited transformation

In sample 4.1 we have two quads at different locations, one at 0,0 and another at 20,50. Then we add a new container at 20,20 to the main scene and add the two quads to this container. Finally we add a text sprite that will follow the mouse and tells us the mouse location. If you run this code and use the mouse to check the location of each quad, you will see how the container location has been added to both quads, the quad at 0,0 will be drawn at 20,20 and the quad at 20,50 will be drawn at 40,70.

The properties actually affected by the object's parent transformation are location, rotation, scale and alpha, but this object's properties in fact remains unaffected, what happens is that when the DisplayObjectContainer render method is called we use the ss2d.RenderSupport pushTransform method to load this transformation and alpha values as the current scene state, then all next transformations and render operations will be done with the previous transformation applied until the ss2d.RenderSupport popTransform method is called.

Thats the type of operations that you don't need to worry about because it is all managed internally by SmoothStep2D, but there are some situations where a conversion between local and world coordinate spaces must be done. For exampe if you need to perform a hit test between a point and an object that is within a container or a hirearchy of containers, it requires that you take care to transform this global location point to the local coordinate space of the object. Of course as this is a tipical vector math operation in game programming the ss2d.DisplayObject has a method called hitTestPoint that already performs a hit test taking care of that conversions. If you need to perform more complex operations between several coordinate spaces check methods like hitTestPoint, worldToLocal, localToWorld, getWorldTransformationMatrix or getBounds defined in ss2d.DisplayObject, ss2d.Quad and ss2d.DisplayObjectContainer.

As you can supose, if you give a behaviour to your container, the objects within it will be affected by it's state changes. Objects inside a container can have individual behaviour because each of them has his own tick method that change it's own state, but that doesn't override the transformations inherited from parent containers. An important note about the tick method is that the default implementation of this method in the container takes care of calling the tick method of all it's children, so, if you override the tick method of a container you must add a call to the tickChildren method with the deltaTime. Let's see an example of that moving two objects at the same time, giving a behaviour to it's parent container.

Three Short.png
Wall Block.png
var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//block sprite
var block = new ss2d.Sprite(0, 50, 101, 171, 'assets/textures/Wall Block.png'); 

//tree sprite, set the pivot on the middle bottom.
var tree = new ss2d.Sprite(50, 151, 101, 171, 'assets/textures/Tree Short.png'); 
tree.mPivotX = tree.mWidth * 0.5;
tree.mPivotY = tree.mHeight;

//make the tree suddenly grows every every few seconds
//juggler will control the growing effect
tree.mJuggler = new ss2d.Juggler();
tree.tick = function(deltaTime)
{
	//if juggler isn't playing any transition
    if(this.mJuggler.mObjects.length == 0)
	{
		//first resize it to 0 in 0.1 seconds with a delay of 1.8 seconds
        var resizeToZero = new ss2d.Tween(this, 0.1, ss2d.Transitions.linear, 1.8);
        resizeToZero.resizeTo(0, 0);
        this.mJuggler.addObject(resizeToZero);
        
        //then resize to it's original size in 1 second with a delay of 2.5 seconds
		var growTween = new ss2d.Tween(this, 1.0, ss2d.Transitions.easeInOut, 2.5);
        growTween.resizeTo(101, 171);
		this.mJuggler.addObject(growTween);
	}

	//update the juggler, when transitions are done juggler will remove it
	this.mJuggler.tick(deltaTime);

	//change the pivot to be centered on the middle bottom of the block
	this.mPivotX = this.mWidth * 0.5;
	this.mPivotY = this.mHeight - (0.15 * this.mHeight);
}

//create a container and add the block and tree sprites as children
var treeBlockContainer = new ss2d.DisplayObjectContainer(120, 120);
treeBlockContainer.addObject(block);
treeBlockContainer.addObject(tree);

//add the pickable component in a custom property
treeBlockContainer.mPickable = new ss2d.Pickable(treeBlockContainer);
view.mMainScene.addObject(treeBlockContainer);

//change the pivot of the container to the center of the block
treeBlockContainer.mPivotX = block.mWidth * 0.5;
treeBlockContainer.mPivotY = block.mHeight * 0.75;

//update
treeBlockContainer.tick = function(deltaTime)
{	
	//update state of all children
    this.tickChildren(deltaTime);

	//update pickable component state
	this.mPickable.tick(deltaTime);

    //change the alpha if picked
    this.mAlpha = (this.mPickable.mPicked)?0.5:1;

    //change the scale of the container with Z and X keys
    var input = ss2d.CURRENT_VIEW.mInput;
    if(input.isKeyPressed(ss2d.Input.Keys.Z))
        this.mScaleX = this.mScaleY += deltaTime;
    if(input.isKeyPressed(ss2d.Input.Keys.X))
        this.mScaleX = this.mScaleY -= deltaTime;
};

view.startLoop();	
Run this code
Code sample 4.2: Container behaviour

The first thing we do in sample 4.2 is create twe sprites that will be insidie a container. The sprite that represents the Wall Block.png image has nothing special, only note that is first added to the container because it must be rendered before the tree sprite, that way the tree will be rendered over the block. The tree has a special behaviour, we override the tick to make the tree disappear and grow every few seconds. To achieve that effect with a few lines of code we are using the ss2d.Tween class to create the property animation that resize the tree, and the ss2d.Juggler class to control both animations. To read more about property animations, go to the Property animation section.

Once the treeBlockContainer is created, we add both sprites and then define a behaviour for the container. First we make it piackble with the ss2d.Pickable component, this component will automatically check if an object is hitted when the user click with the mouse or touch on the scene, making the object move with the mouse while picked. Inside the tick we update all children state calling tickChildren method, this is necessary because we a re overriding the tick method of the container. Then we update the ss2d.Pickable component object, then we also use the mPicked property from the ss2d.Pickable object to change the mAlpha property of our container, meaning that everithing inside this container will have this level of transparency applied too. Next thing is to check if Z or X keys are pressed to change the scale of the container, with the same side effect as changing the alpha.

If you run the code sample, you will see how you move and scale the container and how it's children are affected by this behaviour too. At the same time, you can see how independently of what you are doing to the container, the tree sprite still grows and diesappear by it's own beheaviour. As a final comment about containers, note that the scene itself is a container, it means that you can zoom in or out the scene or move what zone of the scene you can see in the canvas by transforming the mMainScene.

Collision detection

Collision and hit tests are very common operations in game programming, so SmoothStep2D has implemented some useful methods in ss2d.DisplayObject and built-in derived prototypes like ss2d.Quad and ss2d.DisplayObjectContainer to perform this operations in an easy way. For example, if we want to check if a point hits any ss2d.DisplayObject of the scene, we can call the hitTestPoint method. This method accepts a ss2d.Point object as a paramenter and return the object that is hitting by this point or null if the point doesn't hit anything. It means that if you call this method from a non-container object, it will return the object itself if it is being hitted or null if it doesn't, and if you call this method from a container object, it will return wich non-container object inside this container is hitted or null if none of it's children are hitted. At the same time hitTestPoint takes care of transforming the point to the appropiate coordinate space for every tested object. You can override this method to define a custom hit testing, for example, when your object is a circle, you would check if the distance between the point and the center of your object is less or equal to the circle radius. See a little example of how we use the mouse location to perform a hit test on each object of the scene, and change the color of this objects if the test success.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//add some objects to the scene
view.mMainScene.addObject(new ss2d.Quad(20, 220, 50,  30, '#3356aa'));
view.mMainScene.addObject(new ss2d.Quad(120, 320, 130,  30, '#3356aa'));
view.mMainScene.addObject(new ss2d.Quad(320, 400, 30,  70, '#3356aa'));
view.mMainScene.addObject(new ss2d.Quad(350, 120, 80,  30, '#3356aa'));
view.mMainScene.addObject(new ss2d.Quad(90, 20, 30,  80, '#3356aa'));

//save the hitted object
view.mMainScene.mHittedObject = null;

//override the tick method for all ss2d.Quads
ss2d.Quad.prototype.tick = function(deltaTime)
{
    var input = ss2d.CURRENT_VIEW.mInput;
    if(this.hitTestPoint(input.mMousePoint))
    {
        this.mColor.setValue('#ff0000');
        this.mParent.mHittedObject = this;
    } 
    else if(this.mParent.mHittedObject == this)
    {
        this.mColor.setValue('#3356aa');
        this.mParent.mHittedObject = null;
    }
};

view.startLoop();	
Run this code
Code sample 5.1: Hit test

Another useful method is getBounds, this method returns an ss2d.Rectangle object with the boundaries of the object or the area covered by a container's children. The ss2d.Rectangle is a math component that you can use to check collisions between objects using the intersectsRectangle method, that returns true if the rectangle intersects with the other rectangle passed as a parameter. Let's see an example of how to use this collision detection way.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create two quads representing two walls
var leftWall = new ss2d.Quad(20, 20, 30,  200, '#3356ff'); 
var rightWall = new ss2d.Quad(300, 20, 30,  200, '#3356ff'); 
view.mMainScene.addObject(leftWall);
view.mMainScene.addObject(rightWall);

//create a quad that will move between this two walls
var collider = new ss2d.Quad(100, 100, 20, 20, '#ff0000');
view.mMainScene.addObject(collider);

//this custom property tells us the direction to move
collider.mDirection = 1;
collider.tick = function(deltaTime)
{       
    //add the displacement
    this.mLocation.mX += 200*deltaTime*this.mDirection;

    //check if this object collides with other objects in the same container
    var colliderBounds = this.getBounds();
    for(var childIndex in this.mParent.mChildren)
    {
        var brother = this.mParent.mChildren[childIndex];
        //check that the other object is not itself
        if(brother != this)
        {
            //if the objects collide change the direction.
            if(colliderBounds.intersectsRectangle(brother.getBounds()))
            {
                collider.mDirection *= -1;
            }
        }
    }
}

view.startLoop();	
Run this code
Code sample 5.2: Collision detection

Displaying text

There are three ways in SmoothStep2D to display text inside your canvas, the first one is using an html element like a div, simply as that, you are inside a web browser, so you still have the ability to create DOM elements with javascript, don't forget that for any element available in the DOM like text input fields, buttons, etc, html+css+javascirpt is one the most powerful tools for creating graphic user interfaces and it's the way to go when creating GUIs on a SmoothStep2D view. Perhaps, there are situations where the html DOM elements are not enought because the transformations we need to apply to our text, are much more complex or expensive in terms of computation when working with DOM elements, in this cases SmoothStep2D provides two scene elements: ss2d.TextSprite and ss2d.BitmapTextSprite.

Let's start with ss2d.TextSprite, with this class you can place any text on canvas, specifiying in the constructor the location, the text string, the color, the font size, the font name, and the style. The last four mentioned parameters are optional, ss2d.TextSprite will use white color, 16px height and Verdana font as default values without any decoration like italic or bold characters. It also has an interesting property called mDisplayChars with it's two accesors getDisplayChars and setDisplayChars, this property is the number of characters that are currently displayed, it's default value is -1 wich will show all of them. The main idea behind the mDisplayChars property, is to "animate" the text creating the classical scrolling effect. Let's see an example of a scrolling text following the mouse location.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create the text element
var text = new ss2d.TextSprite(0, 0, 'This is a ss2d.TextSprite object', '#550000', 16, 'Verdana', 'italic');
view.mMainScene.addObject(text);

//set the number of currenlty displaying chars
text.mDisplayChars = 0;

//animate the mDisplayChars property to get a scrolling effect.
text.tick = function(deltaTime)
{
	//it will show 10 characters per second
	this.mDisplayChars += 10*deltaTime;

	//if we are showing all text plus some extra seconds, reset.
	if(this.mDisplayChars >= this.mTextString.length + 20)
	{
		this.mDisplayChars = 0;
	}

	//transform like any other display object
	var input = ss2d.CURRENT_VIEW.mInput;
	this.mLocation.set(input.mMouseX + 15, input.mMouseY);
};

view.startLoop();	
Run this code
Code sample 6.1: Text sprite

In the above sample we call the constructor specifiying all possible parameters, 0,0 as location, the text string we want to display, #550000 as color, 16px of height, Verdana font and italic style. Then we change the number of characterst that the text must show and give it a behaviour to increment this property and then reset. We also move the text sprite to follow the mouse location.

The other option for displaying text is using a ss2d.BitmapTextSprite object, this object can load bitmap fonts in XML BMFont format, generated with software like BMFont or Glyph Designer. This applications generate a texture file with all characters, plus an XML metada file with all character coords and spacing data. The ss2d.BitmapTextSprite constructor loads all this data to write any string using this characters. Let's see an example, click here to see the BMFont XML metadata file that we will use, and here to see the texture that pairs with the XML file.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create bitmap text sprite object
var bmtext = new ss2d.BitmapTextSprite(40, 60, 'Text with a', 'assets/fonts/fun02.fnt', 45);
view.mMainScene.addObject(bmtext);

//create another bitmap text sprite object
var bmtext2 = new ss2d.BitmapTextSprite(40, 115, 'bitmap font', 'assets/fonts/fun02.fnt', 45);
view.mMainScene.addObject(bmtext2);

view.startLoop(); 
Run this code
Code sample 6.2: BMFont XML file generated with Glyph Designer

We used two ss2d.BitmapTextSprite objects to compose a multi-line text string, there is no multi-line support in ss2d.BitmapTextSprite or ss2d.TextSprite, so that's a way to do it. The ss2d.BitmapTextsprite takes five parameters: the x and y location, the text string, the bitmap font xml path and the font size, note that the bmt font xml and texture are in the same directory. Another way to do miltine text or manipulate every character position with a custom algorithm is overriding a hook method called displacement, this method receives five parameters: the character index in the text string, the character code in ascii table, the default x and y coords where the character will be drawn, and an output parameter of type ss2d.Point called targetDisplacement that represent the final location of the character. By default this method maps the x and y parameters to mX and mY properties from targetDisplacement output parameter. Let's see an example of how to use this method to create some effects.

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create bitmap text sprite object
var shakeText = new ss2d.BitmapTextSprite(40, 160, 'Shake text', 'assets/fonts/fun02.fnt', 46);
view.mMainScene.addObject(shakeText);

//make it pickable and update the pickable component state.
shakeText.mPickable = new ss2d.Pickable(shakeText);
shakeText.tick = function(dt){ this.mPickable.tick(dt); };

//override displacement method making the text shake.
shakeText.displacement = function(charIndex, charCode, x, y, targetDisplacement)
{
    targetDisplacement.mX = x + Math.sin(charIndex*-3 + ss2d.CURRENT_VIEW.mTotalTime*26)*3;
    targetDisplacement.mY = y + Math.sin(charIndex*8 + ss2d.CURRENT_VIEW.mTotalTime*36)*6;
};

//bitmap text sprite with wave effect and transparent
var waveText = new ss2d.BitmapTextSprite(40, 280, 'wave text', 'assets/fonts/gold01.fnt', 46);
view.mMainScene.addObject(waveText);
waveText.mAlpha = 0.8;
waveText.displacement = function(charIndex, charCode, x, y, targetDisplacement)
{
    targetDisplacement.mX = x;
    targetDisplacement.mY = y + Math.sin(charIndex*0.5 + ss2d.CURRENT_VIEW.mTotalTime*8)*16;
};

view.startLoop();	
Run this code
Code sample 6.3: Bitmap text displacement effects

As you can see, Bitmap text sprites are like any other display object and it's state can be changed in the same way, like the ss2d.Pickable component does, but there are some limitations, for example the boundaries of the text sprite are not affected by the displacement method, in this case the shake effect only moves a few pixels from character's original location, so it is negligible, but if we try to apply the ss2d.Pickable component to the wave text we probably perceive a lot of hit fails.

Reel sprites

Reel sprites are the name that animated sprites receive in SmoothStep2D. Animated sprites are one of the most useful features in a 2D Game Framework/Engine, so SmoothStep2D provides an sprite class to display this type of content, the ss2d.ReelSprite. With this class you have ability to load a custom JSON metadata type named Reel Sets, that contains all the animations and poses that you can play from a sprite map. In the next sample we are going to use this spritesheet:

guy0.png

And it's hand-wrote JSON reel set file:

{
	"image": "guy0.png",
	"comments": "32x36 - 0,  46, 92",
	"reels": {
		"walk_down_stop": {
			"duration": 0,
			"frames":[
				[46,0,32,36,0,0]
			]
		},
		"walk_down": {
			"duration": 0.3,
			"frames": [
				[0,0,32,36,0,0],
				[46,0,32,36,0,0],
				[92,0,32,36,0,0]
			]
		},
		"walk_right_stop": {
			"duration": 0,
			"frames":[
				[48,36,32,36,0,0]
			]
		},
		"walk_right": {
			"duration": 0.3,
			"frames": [
				[2,36,32,36,0,0],
				[48,36,32,36,0,0],
				[92,36,32,36,0,0]
			]
		},
		"walk_up_stop": {
			"duration": 0,
			"frames":[
				[46,72,32,36,0,0]
			]
		},
		"walk_up": {
			"duration": 0.3,
			"frames": [
				[0,72,32,36,0,0],
				[46,72,32,36,0,0],
				[92,72,32,36,0,0]
			]
		},
		"walk_left_stop": {
			"duration": 0,
			"frames":[
				[46,108,32,36,0,0]
			]
		},
		"walk_left": {
			"duration": 0.3,
			"frames": [
				[0,107,32,36,0,0],
				[46,108,32,36,0,0],
				[92,108,32,36,0,0]
			]
		}
	}
}	
Code sample 7.1: Reel set JSON file.

In this file we have three key objects, image that tells us the relative location of the texture file with all frames, comments, an optional field only for humans, and reels, wich contain every reel (animation). Each reel is referenced by a unique name and contains two properties, duration, that tells us the duration in seconds and frames, an array that contains the texture coordinates plus two offset values to displace the frame when rendering, it is used when frames have different boundaries and you want to "center" your character. Here is the example of how to use it:

var view = new ss2d.View('mainCanvas');
view.mBackgroundFillStyle = '#cccccc';

//create a guy with 1.5 times it's original size (original is 32x36 pixels) 
//and playin the 'walk_right_stop' animation by default.
var guy = new ss2d.ReelSprite(100, 100, 1.5, 'assets/reels/guy0.reelset', 'walk_right_stop');
view.mMainScene.addObject(guy);

//pivot to it's center
guy.mPivotX = 32*0.5;
guy.mPivotY = 36*0.5

//set the next stop reel in a custom property
//it will change depending on the last played reel.
guy.mNextStopAnimation = 'walk_right_stop';

//move with WASD keys
guy.tick = function(deltaTime)
{
    //update sprite reel state
    this.updateReelAnimation(deltaTime);
    
    //do nothing if reel isn't ready
    if(!this.mPlayingReel)
        return;
    
    var speed = 150 * deltaTime;
    var stopped = true;
    var input = ss2d.CURRENT_VIEW.mInput;

    //if W key is pressed
    if(input.isKeyPressed(ss2d.Input.Keys.W))
    {
        this.mLocation.mY -= speed;
        stopped = false;
    
        //if walk_up is not the active reel, active it 
        //and set it's stop frame as the next stop frame
        if(this.mPlayingReel.mName != 'walk_up')
        { 
            this.playReel('walk_up'); 
            this.mNextStopAnimation = 'walk_up_stop';
        }
    } 
    else if(input.isKeyPressed(ss2d.Input.Keys.S))
    { 
        this.mLocation.mY += speed;
        stopped = false;
        if(this.mPlayingReel.mName != 'walk_down')
        { 
            this.playReel('walk_down'); 
            this.mNextStopAnimation = 'walk_down_stop';
        }
    }
    else if(input.isKeyPressed(ss2d.Input.Keys.A))
    { 
        this.mLocation.mX -= speed;
        stopped = false;
        if(this.mPlayingReel.mName != 'walk_left')
        { 
            this.playReel('walk_left'); 
            this.mNextStopAnimation = 'walk_left_stop';
        }
    }
    else if(input.isKeyPressed(ss2d.Input.Keys.D))
    { 
        this.mLocation.mX += speed;
        stopped = false;
        if(this.mPlayingReel.mName != 'walk_right')
        { 
            this.playReel('walk_right'); 
            this.mNextStopAnimation = 'walk_right_stop';
        }
    }

    //If the player is not moving the character, play the next stop animation.
    if(stopped)
        this.playReel(this.mNextStopAnimation);
    
}

view.startLoop();	
Run this code
Code sample 7.2: Reel sprite usage

Skeletal sprites

SmoothStep2D have the ability to load Skeletons and animations generated with Spine from esoteric software, a really complete tool to create highly detailed 2D skeletal animations. The adventage of Skeletal animations compared to spritesheet animations is that each frame of the animation is prodecurally generated interpolating the transformation values between two key frames, and this key frames only need a few bytes of information about the location, scale and rotation of each bone, so it does not require the amounts of information that require the spritesheets for each animation. Another unique feature compared to sprisheet animation is that you can play animations at different speed rates and the animation keeps playing smooth. In the next example we are going to use an skeleton that comes with Spine software examples called spineboy, we have also packed all spineboy body parts in a single texture atlas. Here you can see the atlas and the spineboy in it's default pose.

spineboyBodyparts.png
spineboy.png

If we want to use an skeleton in our scene we need to instance an ss2d.SkeletalSprite specifying the location, the scale, the spine skeleton JSON file, and optionally the texture atlas file. In the lastest version of Spine, the skeleton and animations are deployed in the same file, so we simply load the spineboy model and play the walk animation.

var view = new ss2d.View('mainCanvas');

//skeleton and atlas paths
var sbSkeleton = 'assets/skeletons/spineboy/spineboySkeleton.json';
var sbAtlas = 'assets/skeletons/spineboy/spineboyBodyparts.json';

//We will use the ss2d.ResourceManager to load the resources.
//The loadResources method takes three parameters: 
//the list of loaders and resources, per-resource callback, 
//and a final all-resources-loaded callback.
ss2d.ResourceManager.loadResources([
    ss2d.ResourceManager.Loaders.SKELETON,
    sbSkeleton,
    ss2d.ResourceManager.Loaders.TEXTURE_ATLAS,
    sbAtlas
],function(itemName, loaded, toLoad){
    console.log(itemName+' - '+loaded+'/'+toLoad);
},function(){
    //once all resources are loaded...
    
    //instance the ss2d.SkeletalSprite and add to the scene
    var spineboy = new ss2d.SkeletalSprite(100, 450, 1, sbSkeleton, sbAtlas);
    view.mMainScene.addObject(spineboy);
    
    //you can display the bones for debug
    spineboy.mShowBones = true;

    //make it pickable like any other ss2d.DisplayObject
    spineboy.mPickable = new ss2d.Pickable(spineboy);
    
    //play walk animation
    spineboy.playAnimation('walk');
    
    spineboy.tick = function(deltaTime)
    {
        //update pickable
        this.mPickable.tick(deltaTime);
        
        //since we override the tick method to update the ss2d.Pickable 
        //component, we must call updateAnimation method too.
        this.updateAnimation(deltaTime);
    };
    
    view.startLoop()
});	
Run this code
Code sample 8.1: Load skeleton

If you run the sample above, you will see the spineboy skeleton playing the walk animation, and all it's bones rendered over the body thanks to the mShowBones debug flag. Note that since we are overriding the tick method, a call to the updateAnimation method is required. Now, le'ts interact with this ss2d.SkeletalSprite objects, what we are goint to do is try to move it with D and A key, and play the jump animation when the space bar is pressed.

var view = new ss2d.View('mainCanvas');
var sbAtlas = 'assets/skeletons/spineboy/spineboyBodyparts.json';
var sbSkeleton = 'assets/skeletons/spineboy/spineboySkeleton.json';
ss2d.ResourceManager.loadResources([
    ss2d.ResourceManager.Loaders.SKELETON,
    sbSkeleton,
    ss2d.ResourceManager.Loaders.TEXTURE_ATLAS,
    sbAtlas
],function(itemName, loaded, toLoad){
    console.log(itemName+' - '+loaded+'/'+toLoad);
},function(){
    var spineboy = new ss2d.SkeletalSprite(100, 450, 1, sbSkeleton, sbAtlas);
    view.mMainScene.addObject(spineboy);
    
    //custom properties to know the current state
    spineboy.mWalking = false;
    spineboy.mJumping = false;
    
    //give a behaviour that moves spineboy with A and D keys
    spineboy.tick = function(deltaTime)
    {
        var input = ss2d.CURRENT_VIEW.mInput;
        var walking = false;
        var run = input.isKeyPressed(ss2d.Input.Keys.SHIFT) ? 1.7 : 1;
        
        
        //If D key is pressed
        if(input.isKeyPressed(ss2d.Input.Keys.D))
        {
            //change the scale to make it face the appropiate direction
            this.mScaleX = 1;
            
            //add movement
            this.mLocation.mX += 220 * deltaTime * run;
            
            //at the end of the frame we will change the walking state
            walking = true;
        }  
        //the same for A key
        else if(input.isKeyPressed(ss2d.Input.Keys.A))
        {
            this.mScaleX = -1;
            this.mLocation.mX -= 220 * deltaTime * run;
            walking = true;
        }
        
        //if space bar is pressed and spineboy is not jumping
        if(input.isKeyPressed(ss2d.Input.Keys.SPACE) && !this.mJumping)
        {
            //make it stop walking and start jumping
            this.mWalking = false;
            this.mJumping = true;
            
            //assure the time dilation is 1 for the mumping animation
            this.mTimeDilation = 1;
            
            //play the jumping animation, starting at 0.3 seconds and only play once.
            this.playAnimation('jump', 0.3, true);
        }
        
        //if not jumping process the walking state things
        if(!this.mJumping)
        {
            //change the time dilation to accelerate the animation when running
            this.mTimeDilation = run;

            if(!this.mWalking && walking)
            {
                //if we started to walk this frame, play the walk animation
                this.playAnimation('walk');
            } 
            else if(this.mWalking && !walking)
            {
                //if we stoped to walk this frame, stop the current animation.
                this.stopAnimation();
            }
            
            //save the salking state for the next frame
            this.mWalking = walking;
        }
        
        //overriding tick method requires to call updateAnimation
        this.updateAnimation(deltaTime);
    };
    
    //add a trigger for jump animation at 0.25 seconds before the 
    //animation ends, changing the jumping state.
    spineboy.addTrigger('jump', spineboy.mAnimationsMap['jump'].mDuration - 0.25, function(){
        this.mJumping = false;
    });
    
    view.startLoop();
}); 
Run this code
Code sample 8.2: Interacting with the skeleton

¿Can you feel the magic? In this example the spineboy is not playing any animation by default, when we press A or D, it moves and play the walk animation, if we are pressing the Shift key, it moves faster, and the animation too thanks to the mTimeDilation property, that modifies the speed at wich the animation is played. Check also the call to the playAnimation for the jump animation, we are calling this method with three parameters, the first one is the name of the animation, the second is the time at we want the animation start playing, and the last one is a flag to tell the ss2d.SkeletalSprite that we want to play the animation only once. We have also added a trigger at the end of the code, triggers let you specify a callback function once an animation reached the specied played time, in this case is 0.25 seconds before the animation starts, so if the duration is 1.3 seconds, it will be triggered at 1.05 seconds, and in this case, what the callback function does is simply change the jumping state.

Playing audio files

There are two components that wich you can play audio data, the sandard HTML5 Audio element <audio> and the newest WebAudio context. SmoothStep2D will try to load sounds as WebAudio data whenever this API is available, otherwise will load the data as an Audio element. There is no ss2d.DisplayObject to play sounds, so to load auido data you must use the ss2d.ResourceManager. Let's see an example.

//setup the view as usual
var view = new ss2d.View('mainCanvas');

//create an "emiter" object that will handle the events to play a sound
var emiter = new ss2d.DisplayObject();
ss2d.CURRENT_VIEW.mMainScene.addObject(emiter);

//load audio data with the ss2d.ResourceManager.loadSound static method
emiter.mSound = ss2d.ResourceManager.loadSound('assets/sounds/clink.wav');
emiter.mSound2 = ss2d.ResourceManager.loadSound('assets/sounds/switch.wav');

//assign a behaviour that play this sounds.
emiter.tick = function(dt)
{
	//control if the F or G keys are pressed this frame
	var input = ss2d.CURRENT_VIEW.mInput;
	var FPressed = input.isKeyPressed(ss2d.Input.Keys.F);
	var GPressed = input.isKeyPressed(ss2d.Input.Keys.G);

	if(FPressed && !this.mFWasPressed)
	{
		//if F is pressed play the "clink.wav" sound
		this.mSound.play();
		console.log('playing clink.wav');
	}
	
	if(GPressed && !this.mGWasPressed)
	{
		//if G is pressed play the "switch.wav" sound
		this.mSound2.play();
		console.log('playing clink.wav');
	}
	
	this.mGWasPressed = GPressed;
	this.mFWasPressed = FPressed;
}
view.startLoop(); 
Run this code
Code sample 9.1: Load and play audio data

To load the audio data we use the ss2d.ResourceManager.loadSound static method, wich returns an object that implements the ss2d.IAudioComponent, and like with any other resource, is recommended that you pre-load the data, what is avoided in some examples to simply it. The ss2d.IAudioComponent interface has three methods, play, pause and stop, and is obvious what this methods do with the sound.

Internally this object works very different in browsers that supports WebAudio context and browsers that only supports HTML5 Audio element, so currently SmoothStep2D only provides this simple interface that is compatible with both APIs. Even if we only use this basic functionality, there is a noticeable advantage of WebAudio over the Audio element, and is that with WebAudio, you can play the same sound in different buffers at the same time, it menas that if a sound has a duration of 2 seconds, and you play it for exemple at t=0, t=0.5 and t=1.5 3 (time = seconds), with WebAudio you will hear this sound 3 times as expected, but with audio element you can only hear this sound once, cause you must wait the 2 seconds of duration to play it again, and in the worst case, you must reload the audio data source to be able to play it again.

If you want to do more complex audio data manipulation, I suggest you extend the ss2d.WebAudio class functionality, adding methods that apply the WebAudio filters you need for your implementation, and be sure to notice your users that must run your app or game in a browser that support's this feature.

Loading content

In SmoothStep2D you usually don't load content resources explicitly except for the audio or custom data, but it is recommended to use the ss2d.ResourceManager class to pre-load the content data before starting to use it in the scene, this way you prevent from showing empty sprites or even get an undesired behaviour due miss syncronization between what you want to "play" and what is loaded. To pre-load content data, ss2d.ResourceManager provides the static method loadResources, wich accepts three parameters. The first one is an array composted by groups of loader class plus the list of resources to load with each loader, the second parameter is a callback function, called for each loaded resource receiving information to track the loading process, and as a third parameter, the callback function that will start the game. Let's see an example.


//create the view before preloading content
var view = new ss2d.View('mainCanvas');

//create a quad that will represent our loading bar and add to the scene
var loaderBar = new ss2d.Quad(200, 230, 1, 20, '#000000');
view.mMainScene.addObject(loaderBar);
view.startLoop();

//calling loadResources staitc method
ss2d.ResourceManager.loadResources([
    //Loader for skeletal models creates with Spine
    ss2d.ResourceManager.Loaders.SKELETON, 
    'assets/skeletons/spineboy/spineboySkeleton.json',
    //Loader for texture atlas created with TexturePacker
    ss2d.ResourceManager.Loaders.TEXTURE_ATLAS,
    'assets/skeletons/spineboy/spineboyBodyparts.json',
    //Loader for regular 2D textures in any format accepted by the browser
    ss2d.ResourceManager.Loaders.TEXTURE,
    'assets/textures/Enemy Bug.png',
    'assets/textures/Star.png',
    //Loader for bitmap fonts
    ss2d.ResourceManager.Loaders.BITMAP_FONT,
    'assets/fonts/fun02.fnt',
    'assets/fonts/gold01.fnt',
], function(itemName, loaded, toLoad){ //Per-resource callback
    console.log(itemName+' loaded. '+loaded+' of '+toLoad+' items loaded');
    //update the loaderBar width according to the loaded objects.
    loaderBar.mWidth = 100 * loaded / toLoad;
}, function(){ //Pre-load of resources ends callback
    console.log('The game starts here');
    //Here you can remove/fade out the loaderBar.
}); 
Run this code
Code sample 10.1: Pre-loading content

If you run the above example with the javascript console opened, you can see how each element is loaded and then a final message 'The game starts here'. Note that another message that says 'Load resources ends' is printed just before staring the game, this message is printed by the ss2d.ResourceManager.loadResources method, and if you didn't see it means that something goes wrong, for exemple, if you specify a reference to an element that didn't exists. Note also that the log printed for each loaded object can be in a different order than you specified in the Array, that's because the resources are loaded asynchronous. The loader classes we specify before each group of resources, are a set of built-in loader classes that implement the ss2d.ILoader interface. You can extend the framework funcionality and create you our loader classes implementing this interface, as a hint, take a look at how ss2d.ResourceManager use this classes in his loader methods. To make a more rich example, I have added a simple loader bar using an ss2d.Quad.

After that, if you want to get a reference to a loeaded resource you must use the proper loader method from ss2d.ResourceManager. For example if you want to get the reference to a specific texture you must use ss2d.ResourceManager.loadTexture method. In the next example we will see how to pre-load two images and add it to our body, that's only for showing this feature, SmoothStep2D isn't designed to manipulate DOM elements. In a real game, is the ss2d.Sprite class who takes care of using this resource as intended.

var view = new ss2d.View('mainCanvas');

ss2d.ResourceManager.loadResources([
    ss2d.ResourceManager.Loaders.TEXTURE,
    'assets/textures/Enemy Bug.png',
    'assets/textures/Star.png',
], function(itemName, loaded, toLoad){
    console.log(itemName+' loaded. '+loaded+' of '+toLoad+' items loaded');
}, function() {
    //One the resources are pre-loaded, the ResourceManager returns a reference from it's cache.
    var texture1 = ss2d.ResourceManager.loadTexture('assets/textures/Enemy Bug.png');
    var texture2 = ss2d.ResourceManager.loadTexture('assets/textures/Star.png');
    
    //Log information about the references
    console.log(texture1, texture2);

    //The mTextureElement property is an standard HTML Image element containing the texture data.
    document.body.appendChild(texture1.mTextureElement);    
    document.body.appendChild(texture2.mTextureElement);
    
    //if you didn't display any "loading" animation, you can start the loop here.
    view.startLoop();
});
Run this code
Code sample 10.2: Resource references

Actually this way of using the loaded resources is only needed when you want to play sounds, when you want to use a custom resource loader that isn't implemented in SmoothStep2D, and for debug utilities.

Property animation

Physics

Advanced features

Extending prototypes

Bulding applications

Networking