.. highlight:: javascript .. _getting_started_guide: ===================== Getting Started Guide ===================== .. _introduction: ------------ Introduction ------------ Turbulenz is an HTML5 game engine and server-side APIs available in JavaScript and TypeScript for building and distributing 2D and 3D games that run on platforms that support HTML5 features such as modern browsers without the need for plugins. In This Guide ------------- The aim of this guide is to familiarize developers with the SDK, quickly allowing them to start creating great games for the Turbulenz platform. We give a brief introduction to some important concepts and tools, and describe the process of writing, building and running a simple Turbulenz application. To learn the basics of how to use Turbulenz APIs read the next section. If you are comfortable with how to use a basic Turbulenz JavaScript APIs, for example to draw an image to the screen, you can skip this section and move on to the finding the best way to structure a :ref:`Turbulenz application `. **At this point you should have done at least *one* of the following:** * Installed the latest SDK from ``__ and run through the setup steps mentioned :ref:`here `. * Cloned the Turbulenz open source git repository from ``__ and run through the setup steps in the README.rst. Getting Started with Turbulenz APIs ----------------------------------- To try the Turbulenz APIs requires only a text editor and a browser such as Google Chrome or Mozilla Firefox. Start by creating a new file with a .html file extension e.g. turbulenz_example.html Place this file in the root of the Turbulenz directory. .. highlight:: html In that file add the following basic HTML tags:: Turbulenz - Getting Started Guide - API Example The tag is where Turbulenz will draw the game. Think of this as the game window, in this case we'll make it 640x480 pixels. Loading the Turbulenz libraries are done by including scripts in the HTML before your game code is executed. To get started begin by using the core TurbulenzEngine and the GraphicsDevice library to change the background color of the canvas element. Add the following script tags after the section marked as "Script includes go here":: .. highlight:: javascript To initialize create a *WebGLTurbulenzEngine* and pass a reference to the element to the constructor in the game code section:: TurbulenzEngine = WebGLTurbulenzEngine.create({ canvas: document.getElementById("canvas") }); The TurbulenzEngine variable will allow you to create instances of the low-level modules such as GraphicsDevice, SoundDevice, NetworkDevice, InputDevice and PhysicsDevice. You can usually assume the existence of TurbulenzEngine and debug variables because they are automatically added by the Turbulenz build tools when you get to :ref:`creating Turbulenz apps `. In this example we will declare them manually. To create an graphics module instance add the following code:: var graphicsDevice = TurbulenzEngine.createGraphicsDevice({}); These creation functions take parameters with construct options (An object literal with properties). In this case just use an empty object to denote no options. Now the graphicsDevice is created the element can be cleared with a color. Now initialize a color array for background color to be set:: var r = 1.0, g = 1.0, b = 0.0, a = 1.0; var bgColor = [r, g, b, a]; The bgColor is a 4-dimensional vector specified by [red, green, blue, alpha], where each value is from 0.0 to 1.0. In this example the color will be yellow. Declare an *update* function, this will act as the game loop:: function update() { /* Update code goes here */ } TurbulenzEngine.setInterval(update, 1000 / 60); Having declared the function and passed it to *setInterval* function of TurbulenzEngine, this will attempt to call the function at the interval specified in milliseconds. In this case 1/60th of a second or 60 frames-per-second (fps). Now add this code inside the update function to clear the element, which will happen every frame:: if (graphicsDevice.beginFrame()) { graphicsDevice.clear(bgColor, 1.0); /* Rendering code goes here */ graphicsDevice.endFrame(); } This will prepare the frame by calling *beginFrame* and if successful will clear the screen with the bgColor, then finish the frame. Now you have function that will attempt to clear the screen yellow at 60fps. To run the JavaScript code in the browser, navigating to the page by opening the file directly from your filesystem with the default browser or drag and drop the HTML file into the browser of your choice. If you want to reload the code, refresh the page. You should now see a yellow box, which from this point will be your game window. .. highlight:: html So far your code should look like this:: Turbulenz - Getting Started Guide - API Example .. highlight:: javascript To add a little variation, try cycling the color by modifying it in the *update* function. Add this code just above the *beginFrame* function:: b += 0.01; bgColor[2] = b % 1; // Clamp color between 0-1 If you refresh the page in your browser, you will see the canvas will cycle color from yellow to white. The next thing to do is to draw a simple rectangle, using the Draw2D API. .. highlight:: html Include the Draw2D library by adding the following script tag below the other includes:: .. highlight:: javascript After creating the GraphicsDevice, you can create the Draw2D module:: var draw2D = Draw2D.create({ graphicsDevice: graphicsDevice }); After creating the bgColor array, construct the rectangle to draw:: var x1 = 50; var y1 = 50; var x2 = graphicsDevice.width - 50; var y2 = graphicsDevice.height - 50; var rectangle = [x1, y1, x2, y2]; var drawObject = { color: [1.0, 0.0, 0.0, 1.0], destinationRectangle: rectangle }; This will create a rectangle with coordinates (x1, y1) and (x2, y2) where (0, 0) is the top left of the screen. The rectangle will start 50px from the edges of the canvas and will be colored red. To draw this rectangle with Draw2D add the following code between the *clear()* and the *endFrame()* in the update loop:: draw2D.begin(); draw2D.draw(drawObject); draw2D.end(); If you refresh the page, you should now see the red rectangle. The draw2D.draw function is an easy way to just draw an object, but for more flexibility and control, drawing a sprite is better. Construct a simple sprite by using the Draw2DSprite function, do this under the drawObject declaration:: var sprite = Draw2DSprite.create({ width: 100, height: 100, x: graphicsDevice.width / 2, y: graphicsDevice.height / 2, color: [1.0, 1.0, 1.0, 1.0], rotation: Math.PI / 4 }); These will be the initial properties of the sprite. To draw it, use the *drawSprite* function and put it after the *draw2D.draw* function:: draw2D.drawSprite(sprite); Reload the example and you should see a white diamond in the center of the screen. Sprite values can be changed via methods such as *getColor* & *setColor*. For a sprite, position can be changed by directly accessing the property on the sprite object. Define the following angles to use for rotating the sprite below the sprite declaration:: var PI2 = Math.PI * 2; var rotateAngle = Math.PI / 32; To rotate the sprite add the following in the *update* function after the code that modifies the background color:: sprite.rotation += rotateAngle; sprite.rotation %= PI2; //Wrap rotation at PI * 2 Reload now and you should see the sprite spinning. .. highlight:: html Your code should now look like this:: Turbulenz - Getting Started Guide - API Example .. highlight:: javascript The next step is to start using assets such as images to make the sprite more interesting. To do this you will need to start hosting the files on a web server. There are many ways to do this, since you have *Python* installed as part of the setup, you can start a basic webserver from the command-line in the current directory using the following command:: # For Python 2.7 use python -m SimpleHTTPServer .. TODO: List a number of ways to start a webserver Run the command from the same directory as your .html file and navigate your browser to *127.0.0.1:8000* or *localhost:8000* you will see a list of files in that directory. Click on the .html to view the file, it should run as before. Now you can start loading image files as textures for the sprite. Start by creating a texture using the GraphicsDevice, after the *sprite* creation:: var texture = graphicsDevice.createTexture({ src: "assets/textures/particle_spark.png", mipmaps: true, onload: function (texture) { if (texture) { sprite.setTexture(texture); sprite.setTextureRectangle([0, 0, texture.width, texture.height]); } } }); To create a texture this way the *src* image can be a png, jpg, dds or tga. You can test what a browser supports using the `graphicsDevice.isSupported `__ function. Calling *createTexture* will cause the JavaScript to request the image. The *onload* function will be called when the image has been retrieved and will return the texture object if successful or *null* if not. Passing the loaded texture object to the sprite and setting the textureRectangle to use the width and height of the texture will allow the code to start drawing the image. If you are seeing only a white sprite then check the following notes below: .. NOTE:: Draw2D requires the texture to have "power-of-2" dimensions i.e. 16x16, 64x32, 128x512, etc and also to have mipmaps turned on in this example. The example file complies with these requirements. If you use your own image you need to make sure it does too. .. NOTE:: If you are trying to use a file hosted on a different server, that server will need to allow `CORS `__. `corsproxy.com `__ will allow you to test it out with images if you do *http://www.corsproxy.com/www.website.com/img/name.png* for example, otherwise you should do host the files on your own server. To use a transparent image you will need to change how it is rendered. In this example move the *drawSprite* call to its own draw2D.begin and end and set the draw mode to be "additive" which will make dark colors transparent for the particle_spark. It should now look like this:: draw2D.begin(); // Opaque draw2D.draw(drawObject); draw2D.end(); draw2D.begin('additive'); // Additive draw2D.drawSprite(sprite); draw2D.end(); .. NOTE:: If the image already has alpha transparency, set the mode to 'alpha' to use the alpha channel. You can the size of the sprite in a number of different ways. Changing the scale is one option. After the rotationAngle declaration, define the following variable:: var scale = [1, 1]; In the update function add the following:: scale[0] = scale[1] = Math.cos(sprite.rotation) + 2; sprite.setScale(scale); This will shrink and grow the sprite between 1.0 and 2.0 by manipulating the scale. .. highlight:: html Your file should now look like this:: Turbulenz - Getting Started Guide - API Example .. highlight:: javascript At this point you have been able to use basic drawing APIs to manipulate the element using the Turbulenz Engine! For more information on the various APIs, see the following links: * :ref:`Low-level API `, :ref:`2D Physics API `, :ref:`3D Physics API ` * :ref:`High-level API ` * :ref:`Turbulenz Services API ` * :ref:`Protolib API ` .. _getting_started_writing_turbulenz_games: Writing Turbulenz Games ----------------------- Once you are familiar with how the Turbulenz APIs can be used you can start creating games against those APIs yourself. To help you better structure your first app, Turbulenz provide a range of tools, examples and features to make supporting modern and older browsers easier. These come in the form of file/API servers, code/asset processing tools, build configurations and more. This section will start to introduce you to these tools and explain some of the terminology Turbulenz use when describing apps. Code written for the Turbulenz engine can run in several configurations. :Canvas Mode: Using only the **in-built features of the browser**. This is referred to as *canvas mode* (named after the HTML ```` tag through which modern browsers expose accelerated rendering features). As well as accelerated graphics capabilities, modern browsers often allow access to a range of low-level functionality including sound playback, input events and more. In *canvas mode*, the Turbulenz Engine will determine which APIs are available and use the most suitable of these to provide functionality to the game. Games using this mode require sufficiently modern browsers, but end-users with such browsers are not required to enable any extensions. :With Browser Extensions: To provide games with a fixed set of features and performance characteristics on a wider range of browsers, Turbulenz supplies a small binary plugin that exposes a some native functionality to JavaScript. Games targeting this configuration will require the end user to install these extensions. Using the plugin guarantees that the game will support the full range of popular browsers across multiple operating systems. The Turbulenz extensions to the browser include native support for several features that are not yet available in browsers (such as physics simulation or rendering to multiple color buffers). Also included is a JavaScript engine selected and optimized for the execution of game code. This means that game code will have more predictable performance characteristics but still have full access to all the APIs and data, just as the code that drives the rest of the HTML page. The set of built-in functionality in modern browsers is continually increasing, and *canvas* mode is now a viable option for many games. The majority of the code that makes up the Turbulenz engine is shared between both configurations, and similarly games can usually be built for either configuration without change to the code. We suggest that developers test and compare the performance of the two configurations from an early stage. Depending on the support provided by the browser, there may still be limitations in canvas mode. However the gap is narrowing all the time. .. NOTE:: **EXPERIMENTAL** Introduced in SDK 0.25.0 Turbulenz has added support for writing games in TypeScript. The TypeScript compiler allows developers to write code in syntax similar to JavaScript with additional type checking and code verification to help them confidently develop large applications. More information about TypeScript can be found :ref:`here `. .. _getting_started_build_modes: Build Modes ----------- The Turbulenz SDK comes with build tools that are run on the game code before it is executed. These tools can perform several optimization functions, and also automatically generate the appropriate html code to load and run the game. The tools support several build 'modes': **plugin** A *release* version of the game (suitable for deployment), using the browser extensions plugin to provide low level access. The :ref:`maketzjs` tool is used to bundle JavaScript code and all referenced libraries into a single .tzjs file that the Turbulenz engine can load with one request to the server. Code will be executed by the JavaScript engine embedded in the browser plugin. Optionally, the code can also be compacted to obfuscate it and make it as small and fast as possible. **canvas** Equivalent to *plugin*, except that the browser extensions plugin is not used. Instead, the platform libraries make use of functionality built into the browser. In this mode, code is still bundled into a single file and can be compacted as in *plugin* mode. However, the code bundle is a single .js file, since it must be loaded and run by the browsers own JavaScript engine. **plugin-debug** and **canvas-debug** Intended for debugging during development, corresponding to *debug* versions of *plugin* and *canvas* respectively. In these modes there is very little transformation of the JavaScript code. A single command (using the :ref:`makehtml` tool) takes a .js :ref:`template file `, and optionally a .html file, as input and produces a .html file that loads the game. In these modes the code always runs using the browsers JavaScript engine, allowing standard web development tools to be used to debug the code (see :ref:`debugging`). .. _getting_started_local_development_server: The Local Development Server ---------------------------- .. TODO: Going to need maintenance if/when devserver role changes. The Turbulenz SDK comes with a small server (referred to as the :ref:`local development server `), intended to be run on the developer's machine. This *local development server* is capable of serving files, emulating the Turbulenz online services, recording metrics about the game code and data as well as managing and deploying game projects. While it is sometimes possible to launch games directly from the file system, we recommend that developers use the local development server to run and test during development. Most browsers *require* that applications are run from a server, especially in *canvas* modes. .. TODO: Link to the HUB .. TODO: OK to mention emulation of the online services? .. ------------------------------------------------------------ .. _getting_started_creating_turbulenz_app: -------------------------------- Creating a Turbulenz Application -------------------------------- A Simple Example ---------------- With the local server still running: 1. Create a new folder such as *C:\\dev\\myfirstapp* or */Users/\*USERNAME\*/Development/myfirstapp* for the application. 2. Copy (DO NOT MOVE) the `jslib` folder from the SDK install directory into your applications folder. This is required for the build step to work. 3. Open your browser and navigate to http://127.0.0.1:8070. Use the *plus* button on the left of the page to create a new project, and fill in the 'Game Directory' text box with the path of the directory created in step 1. Click 'CONFIRM' in the drop down box. Add a title e.g. "My First App". The rest can be left as default for now. .. NOTE:: In the game directory field, you must specify the full path. Do not use ~/ to replace /Users/\*USERNAME*\/ There should now be a manifest.yaml file in your applications directory. 4. Create a new file ``myfirstapp.js`` in your applications directory with the following contents:: TurbulenzEngine.onload = function onloadFn() { var intervalID; var gd = TurbulenzEngine.createGraphicsDevice({}); function tick() { if (gd.beginFrame()) { gd.clear([1.0, 1.0, 1.0, 1.0], 1.0, 0.0); gd.endFrame(); } } intervalID = TurbulenzEngine.setInterval(tick, 1000/60); }; 5. Open a Turbulenz Environment prompt and change directory to your new folder. Enter the following command to build an html page that runs your app in *plugin-debug* mode:: makehtml --mode plugin-debug -t . myfirstapp.js -o myfirstapp.debug.html A file ``myfirstapp.debug.html`` should have been created in the current directory. .. NOTE:: On Linux, the SDK only supports running in canvas mode. Use the command for canvas-debug below in order to run the app. 6. Back in your browser, click on the *Play* button for your newly created project. The page should list the file just created *myfirstapp.debug.html*. Click on this file to open and run the application. You will see the default development HTML page containing an instance of your application (for now just a blank area). Try changing the value passed to ``gd.clear`` in the code (the components represent Red, Green, Blue and Alpha values). Re-run the build step (5) and click *reload* in the browser. This example shows the :ref:`makehtml` tool being used to build the application in *plugin-debug* mode referred to above. The other modes can be built as follows. **plugin** For *plugin* (and *canvas* mode), a .tzjs code bundle is built using the :ref:`maketzjs` tool, and then :ref:`makehtml` is used to create an HTML page to load and run it:: maketzjs --mode plugin -t . -o myfirstapp.tzjs myfirstapp.js makehtml --mode plugin -t . -o myfirstapp.release.html --code myfirstapp.tzjs myfirstapp.js **canvas** The process is similar to the *plugin* case, but the bundle is built to a .js file (since the browser will load it directly):: maketzjs --mode canvas -t . -o myfirstapp.canvas.js myfirstapp.js makehtml --mode canvas -t . -o myfirstapp.canvas.html --code myfirstapp.canvas.js myfirstapp.js **canvas-debug** Similar to *plugin-debug* mode. A single command creates the HTML page:: makehtml --mode canvas-debug -t . myfirstapp.js -o myfirstapp.canvas.debug.html This application simply clears the screen each frame, but it illustrates the process of building and running code with the Turbulenz tools. Run either of the above tools with the ``-h`` flag to get a list of available options. In particular, the :ref:`maketzjs` tool provides support for compacting and obfuscating JavaScript code. Explanation of Simple Example ----------------------------- The Engine requires that the game define an entry point and assign it to ``TurbulenzEngine.onload``, to be called at load time. In general the game will use this entry point function to perform some minimal initialization and schedule asynchronous operations (such as screen updates and loading) before returning control to the browser. The :ref:`TurbulenzEngine ` global object exposes the low-level API functionality of the engine. Here the code uses it to create a :ref:`GraphicsDevice ` (through which graphics API calls are made), before defining the ``tick`` function. Next, the :ref:`TurbulenzEngine ` is used again, this time to schedule the newly defined ``tick`` function to be called 60 times per second. ``tick`` uses the :ref:`GraphicsDevice ` (via the ``gd`` variable created in the scope of the ``onloadFn`` entry point) to clear the back buffer and display it to the browser window. Using JavaScript Libraries -------------------------- Code in other .js files can be imported using markup understood by the Turbulenz build tools. The majority of the Turbulenz Engine is made up of JavaScript library code, contained in the ``jslib`` directory that can be imported in this way. When starting a new project we recommend that developers take a copy of this directory and immediately submit the unchanged versions to their revision control system. 1. Copy the ``jslib`` folder from the install path to *C:\\dev\\myfirstapp* (or the location you chose for the simple example above). 2. Add the following two lines to the top of myfirstapp.js:: /*{{ javascript("jslib/camera.js") }}*/ /*{{ javascript("jslib/floor.js") }}*/ 3. In ``onloadFn``, just before the ``tick`` function is defined, create a :ref:`Camera object ` and a :ref:`Floor object `, as follows:: var md = TurbulenzEngine.createMathDevice({}); var camera = Camera.create(md); camera.lookAt(md.v3BuildZero(), md.v3Build(0, 1, 0), md.v3Build(0, 20, 100)); var floor = Floor.create(gd, md); 4. Inside the ``tick`` function insert the following code in between the calls to ``clear`` and ``endFrame``, to render a floor:: camera.updateViewMatrix(); camera.updateViewProjectionMatrix(); floor.render(gd, camera); 5. Re-run the commands above to build the .html (and .tzjs) files and open them in the browser. JavaScript library code referenced using the technique above is handled in one of two ways depending on the build mode. In *plugin-debug* and *canvas-debug* modes, the html created by :ref:`makehtml` contains ``