Creating a fairy tale

Since we are dealing with a dragon here, it seems only fair that the environment should also be out of a fairy tale. Hence, we will build our environment with a castle, a midnight sky full of twinkling stars, and a few dark silhouettes. Since we will need this exact same environment in our other major scene, that is, the game world, it's a good idea to separate it out into another class. Thus, we have the FairytaleManager class defined in the fairytaleManager.js file:

var MAX_SCROLLING_SPEED = 6;
var CASTLE_SPRITE_Y = -50;
var SILHOUETTE_SPRITE_Y = 100;
var MAX_STARS = 15;

function FairytaleManager(parent)
{
  // save reference to GameWorld
  this.parent = parent;
  this.screenSize = parent.screenSize;
  // initialise variables
  this.castleSpriteSize = cc.SIZE_ZERO;
  this.castleSprites = [];
  this.lastCastleIndex = 0;
  this.silhouetteSpriteSize = cc.SIZE_ZERO;
  this.silhouetteSprites = [];
  this.lastSilhouetteIndex = 0;
}

First, we declare a few global quantities that we will require. The constructor function for FairytaleManager is fairly straightforward. We will maintain a reference of the parent, which could be either MainMenu or GameWorld. You will find arrays named castleSprites and silhouetteSprites. These arrays store the sprites for our magnificent, infinitely long castle walls and silhouettes. Don't tell the dragon that the castle is infinitely long just yet!

Let's take a look at the code:

FairytaleManager.prototype.init = function() {
  // this makes a nice midnight sky
  var background = cc.LayerGradient.create(cc.c4b(15, 15, 25, 255), cc.c4b(84, 83, 104, 255));
  this.parent.addChild(background, E_ZORDER.E_LAYER_BG);

  this.createCastle();
  this.createSilhouette();
  this.createStars();
};

We also have an init function for convenience. This is where we begin to create our fairy tale environment—starting with the midnight blue sky, the castle, silhouettes, and the stars.

Building an infinitely long castle in 20 lines of code

Yes it is possible to build an infinitely long castle in 20 lines of code, especially when you have a powerful engine doing all the heavy lifting for you. Let's look at the createCastle function:

FairytaleManager.prototype.createCastle = function() {
  // record size of the castle wall sprite
  this.castleSpriteSize = cc.SpriteFrameCache.getInstance().getSpriteFrame("dhbase").getOriginalSize();
  // initial position
  var nextPosition = this.castleSpriteSize.width * 0.5;
  // fill up one & a half screen
  while(nextPosition < this.screenSize.width * 1.5)
  {
    // create castle wall sprite and add it to the parent's batch node
    var castleSprite = cc.Sprite.createWithSpriteFrameName("dhbase");
    castleSprite.setPosition(cc.p(nextPosition, CASTLE_SPRITE_Y));
    this.parent.spriteBatchNode.addChild(castleSprite, E_ZORDER.E_LAYER_CASTLE);
    // store this sprite...we need to update it
    this.castleSprites.push(castleSprite);
    // the next wall depends on this variable
    nextPosition += this.castleSpriteSize.width;
  }
  // we need this to position the next wall sprite
  this.lastCastleIndex = this.castleSprites.length-1;
};

We begin by recording the size of each sprite that will be tiled to form the castle wall into the castleSpriteSize variable. Then in a loop, we create sprites and position them next to each other so as to create the seamless castle wall.

Notice that we're adding these sprites to the spriteBatchNode of the parent class. We shall take advantage of the fact that we have just one texture here by batch rendering sprites together. Also, pay attention to the additional parameter we pass to the addChild function: the z-order. As you may know, the z-order dictates the order in which nodes will be rendered on the screen. Thus, a node with a smaller z-order is rendered before a node with a larger z-order. The z-order enum E_ZORDER is defined in gameworld.js as follows:

var E_ZORDER = {
  E_LAYER_BG:0,
  E_LAYER_STARS:2,
  E_LAYER_SILHOUETTE:4,
  E_LAYER_CASTLE:6,
  E_LAYER_TOWER:8,
  E_LAYER_PLAYER:10,
  E_LAYER_HUD:12,
  E_LAYER_POPUPS:14
};

Subsequently, we push the sprite into the array and increment the nextPosition variable so that the next wall is correctly positioned. Finally, store the index of the sprite placed at the end; we will use this shortly. A similar function, called createSilhouette, is also written to create the continuous chain of silhouettes. The technique used there is identical to the one used above, so I will skip explaining it.

The technique we just implemented to create a continuous, "tiled" layer of sprites in this chapter is implemented because of a limitation in the Cocos2d-html5 version of the engine. In the C++ version, one would normally modify the texture parameters of a sprite causing it to repeat a texture seamlessly within the sprite. But doing that involves setting some OpenGL parameters, as shown in the following code:

// setup the texture to repeat
  ccTexParamstex_params;
  tex_params.minFilter = GL_NEAREST;
  tex_params.magFilter = GL_NEAREST;
  tex_params.wrapS = GL_REPEAT;
  tex_params.wrapT = GL_REPEAT;
  sprite_->getTexture()->setTexParameters(&tex_params);

In HTML5, this would translate into WebGL (the JavaScript API for OpenGL) parameters. Since WebGL may not always be supported on the target device's browser, we cannot use that technique to repeat a texture within a sprite.

Adding the stars

We have a midnight sky, a castle, and some silhouettes. But how can there be a midnight sky without stars? Let's add some stars in the createStars function:

FairytaleManager.prototype.createStars = function() {
  // random number of stars...this night sky always changes
  var numStars = MAX_STARS + Math.floor(Math.random() * MAX_STARS);
  for(var i = 0; i < numStars; ++i)
  {
    var star = null;
    // either big star or small
    if(Math.random() > 0.5)
      star = cc.Sprite.createWithSpriteFrameName("dhstar1");
     else
       star = cc.Sprite.createWithSpriteFrameName("dhstar2");

     // random position
     var position = cc.p(Math.random() * this.screenSize.width, Math.random() * this.screenSize.height);
     star.setPosition(position);
     // twinkle twinkle randomly star
     var duration = 1 + Math.random() * 2;
     var action = cc.RepeatForever.create(cc.Sequence.create(cc.DelayTime.create(duration*2), cc.FadeOut.create(duration), cc.FadeIn.create(duration)));
     star.runAction(action);
     // add this too the batch node as well
     this.parent.spriteBatchNode.addChild(star);
  }
};

We begin by randomly deciding the number of stars in our midnight sky. Then in a loop, we randomly decide between big ("dhstar1") and small ("dhstar2") stars and position them randomly as well. All that randomness must surely add a bit of fairy tale essence to our game. Finally, we repeat a random duration fade-in and fade-out sequence on each star for that magical touch. "Twinkle twinkle randomly stars!"

Well, it looks like we have a magical midnight sky full of stars and a magnificent castle. But the dragon looks quite silly flying without actually moving. So let's help him out by setting things into motion.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.133.160