Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

10. January 2017

 

Carmel is a new WebVR browser available for the Oculus Gear VR in preview form.  WebVR is an attempt to bring Virtual Reality to the web browser, while Carmel is their mobile browser supporting it.  You can learn more about the VR web here. In a nutshell, WebVR is going to enable you to write VR experiences in a similar experience to creating dynamic web pages today.  To help with that, Oculus have released the Carmel VR Starter Kit.  It’s a set of samples and examples to get you up and running in WebVR for the Carmel browser. 

 

You can download the starter kit on Github and getting started is easy assuming you have Node.js installed.

Running Samples

First, run npm install to get the npm dependencies used for hosting the samples locally.

Run npm start to start a local http server on port 8000.

You can navigate to, http://:8000/index.html, to access the samples on a Gear VR enabled mobile device.

The top category of links will launch each sample into the Carmel Technical Preview.

The bottom category of links can be used to launch each sample directly in your browser if the sample supports rendering monoscopically.

 

Here is a look at the Hello World example’s code:

<!DOCTYPE html>
<!--
  Copyright 2016-present, Oculus VR, LLC.
  All rights reserved.

  This source code is licensed under the license found in the
  LICENSE-examples file in the root directory of this source tree.
-->
<html>
  <head>
    <title>Hello WebVR</title>
    <style>
      body {
        margin: 0;
      }
      canvas {
        position: absolute;
        width: 100%;
        height: 100%;
      }
      #messages {
        position: absolute;
        color: white;
        width: 100%;
        height: 100%;
      }
    </style>
    <script>
      var vrDisplay;      // The VRDisplay we will present to, discovered from 
      getVRDisplays
      var frameData;      // HMD information, populated each frame by 
      getFrameData
      var layerSource;    // The source of the VRLayer passed to requestPresent, 
      our canvas element.

      var gl;             // The webgl context of the canvas element, used to 
      render the scene
      var quadProgram;    // The WebGLProgram we will create, a simple quad 
      rendering program
      var attribs;        // A map of shader attributes to their location in the 
      program
      var uniforms;       // A map of shader uniforms to their location in the 
      program
      var vertBuffer;     // Vertex buffer used for rendering the scene
      var texture;        // The texture that will be bound to the diffuse 
      sampler
      var quadModelMat;   // The quad's model matrix which we will animate

      // This is the entrypoint to this sample and where we attempt to begin VR 
      presentation
      function requestPresent() {
        // First, initialize our WebGL program for rendering a simple quad
        initWebGLProgram();

        // Next, we will get the first VRDisplay that is available and try to 
        requestPresent.
        // If VR is unavailable or we aren't able to present, we will simply 
        display an HTML message in the page.
        if (navigator.getVRDisplays) {
          navigator.getVRDisplays().then(function (displays) {
            if (displays.length > 0) {
              // We reuse this every frame to avoid generating garbage
              frameData = new VRFrameData();

              vrDisplay = displays[0];

              // We must adjust the canvas (our VRLayer source) to match the 
              VRDisplay
              var leftEye = vrDisplay.getEyeParameters("left");
              var rightEye = vrDisplay.getEyeParameters("right");

              // This layer source is a canvas so we will update its width and 
              height based on the eye parameters.
              // For simplicity we will render each eye at the same resolution
              layerSource.width = Math.max(leftEye.renderWidth, rightEye.
              renderWidth) * 2;
              layerSource.height = Math.max(leftEye.renderHeight, rightEye.
              renderHeight);

              // This can normally only be called in response to a user gesture.
              // In Carmel, we can begin presenting the VR scene right away.
              vrDisplay.requestPresent([{ source: layerSource }]).then(function (
              ) {
                // Start our render loop, which is synchronized with the 
                VRDisplay refresh rate
                vrDisplay.requestAnimationFrame(onAnimationFrame);
              }).catch(function (err) {
                // The Carmel Developer preview allows entry into VR at any time 
                because it is a VR first experience.
                // Other browsers will only allow this to succeed if called in 
                response to user interaction, such as a click or tap though.
                // We expect this to fail outside of Carmel and would present 
                the user with an "Enter VR" button of some sort instead.
                addHTMLMessage("Failed to requestPresent.");
              });
            } else {
              // Usually you would want to hook the vrdisplayconnect event and 
              only try to request present then.
              addHTMLMessage("There are no VR displays connected.");
            }
          }).catch(function (err) {
            addHTMLMessage("VR Displays are not accessible in this context.  
            Perhaps you are in an iframe without the allowvr attribute specified.
            ");
          });
        } else {
          addHTMLMessage("WebVR is not supported on this browser.");
          addHTMLMessage("To support progressive enhancement your fallback code 
          should render a normal Canvas based WebGL experience for the user.");
        }
      }

      // Once we are presenting this will get called any time a new frame should 
      be rendered on the VRDisplay
      // The timestamp passed to our callback is the current DOMHighResTimeStamp 
      at the start of the frame.
      // We can use the timestamp to update our scene and perform animations in 
      a framerate independent way.
      function onAnimationFrame(timestamp) {
        // Continue to request frames to keep the render loop going
        vrDisplay.requestAnimationFrame(onAnimationFrame);

        // Clear the layer source - we do this outside of render to avoid 
        clearing twice
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        // Update the scene once per frame
        update(timestamp);

        // Get the current pose data
        vrDisplay.getFrameData(frameData);

        // Render the left eye
        gl.viewport(0, 0, layerSource.width * 0.5, layerSource.height);
        render(frameData.leftProjectionMatrix, frameData.leftViewMatrix);

        // Render the right eye
        gl.viewport(layerSource.width * 0.5, 0, layerSource.width * 0.5, 
        layerSource.height);
        render(frameData.rightProjectionMatrix, frameData.rightViewMatrix);

        // Submit the newly rendered layer to be presented by the VRDisplay
        vrDisplay.submitFrame();
      }

      function update(timestamp) {
        // Animate the z location of the quad based on the current frame 
        timestamp
        var oscillationSpeed =  Math.PI / 2;
        var z = -1 + Math.cos(oscillationSpeed * timestamp / 1000);
        quadModelMat[14] = z
      }

      // For VR, it's important that your render method is parameterized by the 
      camera
      // (projection and view matrices) so that it can be used to render from 
      each
      // eye's perspective
      function render(projectionMat, viewMat) {
        gl.useProgram(quadProgram);

        // The view and projection uniforms are passed in and are different for 
        the left eye and right eye
        gl.uniformMatrix4fv(uniforms.projectionMat, false, projectionMat);
        gl.uniformMatrix4fv(uniforms.viewMat, false, viewMat);

        // The remainder of our rendering is the same for both eyes now that 
        view and projection have been set up.
        gl.uniformMatrix4fv(uniforms.modelMat, false, quadModelMat);

        gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);

        gl.enableVertexAttribArray(attribs.position);
        gl.enableVertexAttribArray(attribs.texCoord);

        gl.vertexAttribPointer(attribs.position, 3, gl.FLOAT, false, 20, 0);
        gl.vertexAttribPointer(attribs.texCoord, 2, gl.FLOAT, false, 20, 12);

        gl.activeTexture(gl.TEXTURE0);
        gl.uniform1i(uniforms.diffuse, 0);
        gl.bindTexture(gl.TEXTURE_2D, texture);

        gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
      }

      function initWebGLProgram() {
        layerSource =  document.getElementById("webgl-canvas");

        var glAttribs = {
          alpha: false,                   // The canvas will not contain an 
          alpha channel
          antialias: true,                // We want the canvas to perform anti-
          aliasing
          preserveDrawingBuffer: false    // We don't want our drawing to be 
          retained between frames, we will fully rerender each frame.
        };

        // You should also check for "experimental-webgl" when implementing 
        support for canvas based WebGL fallback when VR is not available.
        gl = layerSource.getContext("webgl", glAttribs);

        var quadVS = [
          "uniform mat4 projectionMat;",
          "uniform mat4 viewMat;",
          "uniform mat4 modelMat;",
          "attribute vec3 position;",
          "attribute vec2 texCoord;",
          "varying vec2 vTexCoord;",

          "void main() {",
          "  vTexCoord = texCoord;",
          "  gl_Position = projectionMat * viewMat * modelMat * vec4(position, 1.
          0);",
          "}",
        ].join("\n");

        var quadFS = [
          "precision mediump float;",
          "uniform sampler2D diffuse;",
          "varying vec2 vTexCoord;",

          "void main() {",
          "  gl_FragColor = texture2D(diffuse, vTexCoord);",
          "}",
        ].join("\n");

        quadProgram = gl.createProgram();

        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.attachShader(quadProgram, vertexShader);
        gl.shaderSource(vertexShader, quadVS);
        gl.compileShader(vertexShader);

        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.attachShader(quadProgram, fragmentShader);
        gl.shaderSource(fragmentShader, quadFS);
        gl.compileShader(fragmentShader);

        attribs = {
          position: 0,
          texCoord: 1
        };

        gl.bindAttribLocation(quadProgram, attribs.position, "position");
        gl.bindAttribLocation(quadProgram, attribs.texCoord, "texCoord");

        gl.linkProgram(quadProgram);

        uniforms = {
          projectionMat: gl.getUniformLocation(quadProgram, "projectionMat"),
          modelMat: gl.getUniformLocation(quadProgram, "modelMat"),
          viewMat: gl.getUniformLocation(quadProgram, "viewMat"),
          diffuse: gl.getUniformLocation(quadProgram, "diffuse")
        };

        var size = 0.2;
        var quadVerts = [];

        var x = 0;
        var y = 0;
        var z = -1;
        quadVerts.push(x - size, y - size, z + size, 0.0, 1.0);
        quadVerts.push(x + size, y - size, z + size, 1.0, 1.0);
        quadVerts.push(x + size, y + size, z + size, 1.0, 0.0);
        quadVerts.push(x - size, y + size, z + size, 0.0, 0.0);

        vertBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(quadVerts), gl.
        STATIC_DRAW);

        quadModelMat = new Float32Array([
          1, 0, 0, 0,
          0, 1, 0, 0,
          0, 0, 1, 0,
          0, 0, 0, 1
        ]);

        texture = gl.createTexture();

        var image = new Image();

        // When the image is loaded, we will copy it to the GL texture
        image.addEventListener("load", function() {
          gl.bindTexture(gl.TEXTURE_2D, texture);
          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, 
          image);

          gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
          gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.
          LINEAR_MIPMAP_NEAREST);

          // To avoid bad aliasing artifacts we will generate mip maps to use 
          when rendering this texture at various distances
          gl.generateMipmap(gl.TEXTURE_2D);
        }, false);

        // Start loading the image
        image.src = "../assets/cube-sea.png";
      }

      function addHTMLMessage(msgText) {
        var message = document.createElement("div");
        message.innerHTML = msgText;
        document.getElementById("messages").appendChild(message);
      }
    </script>
  </head>
  <body onload="requestPresent()">
    <canvas id="webgl-canvas"></canvas>
    <div id="messages"></div>
  </body>
</html>

News

24. November 2016

 

Every year there are a large number of great Black Friday deals of interest to game developers.  This list is an attempt to capture as many of them as possible in one place.  If you see a great Black Friday or Cyber-Monday deal of interest to game developers that isn’t on the list below, please let me know in comments below. 

This list will be constantly updated so be sure to check back regularly!

 

Deals on Amazon

Software

 

Hardware

 

Deals on Steam – Autumn Sale

 

Deals on Unreal Engine

 

Deals on Unity

 

Misc

allegorithmic

udemy

Microsoft Store

Dell

HP

tsugi

 ClipStudio

3D Coat

Reallusion

ASoundEffect

GameMaster Audio

Smith Micro

Adobe

Corel

AutoDesk  -- Something Fishy with this promo.  Seems no longer available in Canada and never Available in the US.  BOO

Daz3D

Blender

PaintStorm

GameSalad

News, General ,

17. October 2016

 

The following is a recap of major events in the world of game development for the week ending October 17th, 2016.  I do a weekly video recapping the news available here with this week’s video embedded below.  This post is a collection of links mentioned in the recap.

 

 

The Video

News

26. November 2015

 

Each year Black Friday has more and more game development deals.  Each year it also gets earlier and earlier… Black Thursday, Black Wednesday, you name it and of course they are trying to stretch it out with Cyber Monday.  This post is an attempt to capture the Black Friday/Cyber Monday deals most relevant to game developers.  If you know of a applicable sale I missed on this list, please let me know!

I will edit this list as new deals are located.  Have a gamedev deal to announce, email me at news@gamefromscratch.com, leave a comment below or in this reddit conversation.

 

Steam

 

Amazon

 

Phaser.io

 

3D Coat

 

YoYo Games

 

Udemy

 

Adobe

 

Microsoft Store

 

Misc PC Manufacturers Black Friday Sales Pages (US Store links)

 

The Foundry

 

Daz3D

 

Allegorithmic

 

Smith Micro

 

XFrog

 

CG Axis

 

Marmoset

 

3DRt

 

Mobile Game Graphics

 

Game Salad

News, GameDev News, General

18. November 2015

 

Microsoft is a different sort of company these days.  Starting back in 2014 they released the free community edition of Visual Studio.  Then in April of this year they launched the light weight and cross platform (and completely free) Visual Studio Code.  Today they announced the launch of Visual Studio Dev Essentials.

So what exactly does Dev Essentials include?

 

Tools

  • Visual Studio Community
  • Visual Studio Code
  • Visual Studio Express
  • Team Foundation Server Express

 

Of those products only Team Foundation Server is new I believe.  So mostly it’s a rebranding of the tools we’ve already got.  However it’s the add-ons that make the package.

 

Training

  • Pluralsight 6 month subscription
  • Xamarin University Mobile Training
  • WintellectNOW 3 month subscription
  • Microsoft Virtual Academy
  • HackHands Live Programming Help $25 Credit
  • Priority Forum Support

 

Cloud

  • Azure Credits ($25/month for 12 months)
  • Visual Studio Team Services account with 5 users
  • App Service Free Tier
  • PowerBI free tier
  • HackeyApp free tier
  • Application Insights free tier

 

For Mac Developers

  • Parallels Desktop Pro 3 months subscription
  • Parallels Acceess 3 months subscription
  • Windows Platform VM 60 days
  • Office Online Apps

 

Now many of these services are either limited time or coming soon, so not everything is available today and not everything is available for ever.  So if this program sounds interesting to you, head on over here for more information.

News, GameDev News

Month List

Popular Comments

Cocos2D HTML5 tutorial 2: Why it’s Hello World of course
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


6. June 2012

 

As promised in the last tutorial, in this tutorial we are going to jump in and do some coding.  We are going to implement the obligatory Hello World example using Cocos2D HTML, with a twist ( literally ).  I warn you up front, this is going to look a great deal more complex than it actually is.  There is a certain amount of boilerplate code you need to get up and running, but it really isn’t all that difficult in the end.  In a future game, you will just do a series of copy and pastes and be off to the races.

 

The following goes into a lot of detail, more so than future tutorials.  There is however a TL;DR summary at the end, so if you prefer, simply read the code examples then jump ahead to the summary at the bottom of the post for an understanding of exactly what’s going on.

 

To make things a bit easier on yourself, create your game project in the same folder you extracted the Cocos2D-html archive to.  If you followed my directions exactly in tutorial 1, this directory will be c:\wamp\www.  Create a new folder for your project, I called mine MyFirstApp. 

 

Now that your directory is created, we are going to be creating a couple files.  First we need to create an HTML web page that is going to host our game.  Following convention ( and so Apache will serve it as the default ), I called mine index.html.  Enter the following code:

 

<html> <body style="padding:0; margin: 0; background: #fff;"> <div style="text-align: center; font-size: 0"> <canvas id="gameCanvas" width="600" height="600"> Your browser does not support the canvas tag </canvas> </div> </body> </html> <script src="cocos2d.js"></script>

 

This is pretty much stock HTML code.  The styling in the body tag is so our canvas tag will be flush with the left side of the screen, and because I wanted a white background.  Only two items here are really important.  First is the canvas tag, we need at least one canvas tag, as this is where Cocos2D draws everything.  Why 600 pixels?  That’s (edit- was) the content width of my blog.  So obviously, make your canvas whatever size you want it to be.  Finally we include our cocos2d.js script.

 

This segues nicely into the next task, go ahead and create another text file, this one called cocos2d.js.  Inside that file we type:

 

(function () {
    var d = document;
    var c = {
        COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug
        box2d:false,
        showFPS:true,
        frameRate:60,
        tag:'gameCanvas', //the dom element to run cocos2d on
        engineDir:'../cocos2d/',
        appFiles:['MyFirstApp.js']
    };
    window.addEventListener('DOMContentLoaded', function () {
        //first load engine file if specified
        var s = d.createElement('script');
        s.src = c.engineDir + 'platform/jsloader.js';
        d.body.appendChild(s);
        s.c = c;
        s.id = 'cocos2d-html5';
    });
})();

 

You may notice that this code block ends with ();  This is a self executing anonymous function.  Basically that means after it is finished being defined, it will immediately be called.

 

So what exactly are we doing here?  First we care creating a configuration variable called c.  This file consists of a number of configuration settings for initializing the Cocos2D engine.  Lets take a quick look at each value:

 

COCOS2D_Debug: This controls the debug level Cocos2D engine. In release set to 0

box2d: Tells Cocos2D if it needs to initialize the box2d physics engine

showFPS: Enable/disable a frames per second counter being displayed each frame

tag: This is the HTML element that cocos2D will render to.  In our case, our canvas tag

engineDir: This is the directory the cocos2D libraries are installed in.  In our case, up one directory from cocos2d.js in the folder cocos2d

appFiles: This is an array containing all of the your script files.  If you add a js file to your project, add it to this array.  This causes it to be loaded by the loader.

 

Next we register an event handler that will be fired once the DOM has been loaded ( meaning the page is done loading and JavaScript is setup and ready ).  We then create a <SCRIPT> tag in our HTML page with the id ‘cocos2d-html5’ and add a reference to jsloader.js script as well as our configuration variable c.

 

At this point, the jsloader.js script now loads all of the various libraries required by cocos2d into the HTML file.  Once it is done loading all of the library files, it calls a user defined script named main.js. You need to create this file in the root of your project.

 

Now let’s go ahead and create main.js:

 

var cocos2dApp = cc.Application.extend({
    config:document.querySelector('#cocos2d-html5')['c'],
    ctor:function (scene) {
        this._super();
        this.startScene = scene;
        cc.COCOS2D_DEBUG = this.config['COCOS2D_DEBUG'];
        cc.setup(this.config['tag']);
        cc.Loader.shareLoader().onloading = function () {
            cc.LoaderScene.shareLoaderScene().draw();
        };
        cc.Loader.shareLoader().onload = function () {
            cc.AppController.shareAppController().didFinishLaunchingWithOptions();
        };
        cc.Loader.shareLoader().preload([
        ]);
    },
    applicationDidFinishLaunching:function () {
        var director = cc.Director.getInstance();
        director.setDisplayStats(this.config['showFPS']);
        director.setAnimationInterval(1.0 / this.config['frameRate']);
        director.runWithScene(new this.startScene());

        return true;
    }
});
var myApp = new cocos2dApp(MyFirstAppScene);

 

We are creating a new object by extending cc.Application.  If you are familiar with C++, Java or C# you may be looking at this code and thinking it is both vaguely familiar and different at the same time.  There is a good reason for that.  JavaScript isn’t really “object oriented” in the way you are familiar with, it is prototype based.  This is beyond the scope of what I can explain here, but basically there are no classes.  Instead there are “prototypes” that you clone and extend.  So essentially you define something once, which is then used as a prototype for creating “objects” in the future.  Clear as mud?

 

Essentially what we are doing here is defining our cocos2DApp object to extend the cc.Application prototype.  This is a pretty common behavior in working with Cocos2D, so hopefully you can wrap your head around it.  We then implement the ctor ( constructor ) and applicationDidFinishingLaunching.  Again, if you are used to C++ like languages, you can think of cocos2DApp as being derived from cc.Application, then overriding the default constructor and a virtual method.  If you aren’t a C++/C# or Java programmer, forget everything I just said. Smile

 

First, up is the ctor, which simply results in the creation of the prototype cc.Application which cocos2DApp extends.  super() can be a confusing concept to understand, for more details read this. ( warning, NSFW language ).  One thing to keep in mind, in JavaScript, the constructor ( or ctor ) is just another function, unlike in other languages. 

 

We pass the type of Scene we want to start our app with, we will be creating this in a moment.  This is value the parameter scene holds.  We then call _super() as described earlier.  Next we setup cocos using the values we set in the value c earlier in cocos2d.js.  Next we invoke the global Loader object via cc.Loader.shareLoader().  onloading is a call back that will be called when the loader is executing, which effectively renders the loading screen.  preLoad is an important function for loading user data files, which we will user in a later tutorial.

 

In applicationDidFinishLaunching ( which is predictably called when the application finishes launching! ), we initialize the Director object. Director is a global object that basically controls the execution of everything, we will be seeing a lot of it later on.  For now just realize that Director is very important.  Why will become clear in time.  The .getInstance() call is where the singleton part of the equation comes in.  It’s well beyond the scope of what I can go into, but for now just think about it as a globally unique shared variable.

 

The heart of our cocos2dApp though is the applicationDidFinishLaunching function.  This is a function that will be called once your cocos2dApp class is loaded, cocos2d is setup and it is what gets the party started.  First we tell the ( all important! ) Director if we want to display the frames per second counter on screen and that we want to update using the framerate specified in c configuration in cocos2d.js.  Next we tell Director to start running using the scene type we passed in to the constructor.  The director only ever has one scene at a time active, and as I said earlier, Cocos2D organizes your game Scene by scene.  This is the point where your (only) Scene is created and execution is started. 

 

Finally we create an instance of cocos2dApp named myApp and pass it the scene MyFirstAppScene.

 

Now lets create that scene object, create a file named MyFirstApp.js as such:

var MyFirstApp = cc.Layer.extend({
    init:function()
    {
        this._super();

        var s = cc.Director.getInstance().getWinSize();

        var layer1 = cc.LayerColor.create(new cc.Color4B(255, 255, 0, 255), 600, 600);
        layer1.setAnchorPoint(new cc.Point(0.5,0.5));

        
        var helloLabel = cc.LabelTTF.create("Hello world", "Arial", 30);
        helloLabel.setPosition(new cc.Point(s.width/2,s.height/2));
        helloLabel.setColor(new cc.Color3B(255,0,0));
        var rotationAmount = 0;
        var scale = 1;
        helloLabel.schedule(function()
            {
                this.setRotation(rotationAmount++);
                if(rotationAmount > 360)
                    rotationAmount = 0;
                this.setScale(scale);
                scale+= 0.05;
                if(scale > 10)
                    scale =1;
            });

        layer1.addChild(helloLabel);
        this.addChild(layer1);

        
        return true;
    }

});

var MyFirstAppScene = cc.Scene.extend({
    onEnter:function(){
        this._super();
        var layer = new MyFirstApp();
        layer.init();
        this.addChild(layer);
    }
})

Just like we did when creating our cocos2dApp, we are creating MyFirstApp by extending a Cocos2D prototype, in this case ccLayer.  If you have ever worked in a graphic application like Photoshop or GIMP, the concept of a layer should already be familiar to you.  If the term is new to you, think of a layer as an image or graphic, that might be transparent in parts.  You can layer ( thus the name ) layers over top of each other to create a compound image.  This image illustrates the concept as well as any I could find:

 

 

 

You can think of MyFirstApp as representing the entire collection of layers, which in the end will ultimately be drawn to our HTML canvas tag.

 

As I said, our canvas can be made out of a collection of layers, and the first thing we want to do is create a solid yellow layer.  That is what this call does:

var layer1 = cc.LayerColor.create(new cc.Color4B(255, 255, 0, 255), 600, 600);

We are creating a layer 600x600 in size ( the same as our canvas tag ), filled with the RGBA color 255,255,0,255.  These numbers represent the red, green, blue and alpha values respectively, as represented by a value from 0-255.  The alpha value can be thought of as the amount of transparency in the layer, in this case 100% opaque.  As you can see, we created our color with a call to cc.Color4B, you will see this naming convention quite often. 

 

Now that we have a solid yellow layer, we need to position it.  Positioning in Cocos2D might be a bit different from what you are used to.  Instead of positioning elements from the their top left, they are positioned by their center point by default.  Additionally Cocos2D coordinates start at the bottom left of the screen instead of the top left.  Therefore when we set the position of our layer, we want it to be the center of the screen.

 

Now we want to create our HelloWorld text, which we do by creating a cc.LabelTTF ( TTF = True Text Font ), with our string “Hello world” using the font family Arial and font size of 30.  We too want the Hello World label centered to the screen and we want it to be red in color.  We then declare two local variables rotationAmount and scale, which we will use in a second.

 

The next line is key, we are declaring a lambda ( or anonymous ) function that we pass as a parameter to the schedule function.  End end result is, the following code will be executed every update ( which we set to 60 times per second earlier ) as long as our scene is active.  Essentially what happens is Director calls our Scene ( MyFirstApp ) to update 60 times per second, and our Scene in turn calls the update function of each node that registered to be updated.  This line is registering the function that is going to be called during updating.  ( This is greatly simplifying the actual process, but will do for now ).  Essentially, all this function does is rotate the text and scale it until it is 10 times in size, at which point it starts over.

 

Finally, we add our Hello World label to our layer, and add our layer to our MyFirstApp variable.

 

Now we create our scene, MyFirstAppScene.  This is the value we passed in to the constructor cocos2dApp earlier.  MyFirstAppScene extends cc.Scene and overrides the OnEnter method, which is called when the scene is activated ( in the RunWithScene call ).  In this case, we simply call up to cc.Scene with a call to this._super(), then create an instance of our layer MyFirstApp and add it to our scene.  This causes our layer to be created and displayed.

 

Here are the end results of all our activity:

 

 

TL;DR overview of what just happened:

 

  1. index.html is loaded in the web browser
  2. Our canvas tag is defined
  3. cocos2d.js then loaded ( within index.html )
  4. cocos2.js creates a SCRIPT tag in our index.html, injects configuration settings as well as a reference to jsloader.js
  5. jsloader loads all of the required cocos2D libraries, then invokes main.js
  6. main.js loads cocos2D, preloads assets, initializes the director then runs our scene
  7. our scene MyFirstAppScene creates a new layer MyFirstApp

 

Your game is now running.  We will take a closer look at program execution and handling input shortly.

 

You can download the whole project here.  Simply extract it to your www folder and open index.html in your browser.

 

 

Read Tutorial 3

Programming , ,

blog comments powered by Disqus

Month List

Popular Comments