- Cocos2d-x Game Development Blueprints
- Karan Sequeira
- 607字
- 2021-07-16 13:47:57
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.
- SQL Server 從入門到項目實踐(超值版)
- Learning NServiceBus(Second Edition)
- Docker進階與實戰
- Java高并發核心編程(卷2):多線程、鎖、JMM、JUC、高并發設計模式
- JavaScript Unlocked
- 從學徒到高手:汽車電路識圖、故障檢測與維修技能全圖解
- Jupyter數據科學實戰
- H5頁面設計:Mugeda版(微課版)
- Frank Kane's Taming Big Data with Apache Spark and Python
- 大學計算機基礎
- Oracle實用教程
- Unity 5.X從入門到精通
- SwiftUI極簡開發
- R的極客理想:量化投資篇
- Visual Basic程序設計基礎