21 October 2012

The third installment of Citrus Engine tutorial series. Just like the article title, in this article I’ll show you how to create HUD for your Citrus Engine games.


=====================
If you want to read the other part, here are all the links:
1. Game Structure
2. Adding Screen Transition
3. Head-Up Display
4. Working with Data
5. Creating Level using Tiled Map Editor
=====================

In this tutorial, we’re going to create two types of HUD.

The first one is a fixed HUD, that have fixed position in the screen. And it will always on topmost of the game layer. Example usage: HUD to show player score, money earned, etc.

The other one is a dynamic HUD which can follow an object. For example, a health bar on top of hero’s or baddy’s head, and will stay on top of their head wherever they move.

And in this tutorial I’ll only show how to add HUD to your game. But when it comes to manipulate and or update its data, I’ll discuss them in the next part.

1. Fixed HUD
Enough talking, we will create a fixed HUD first as it’s simpler than the second one. It just a movieclip that overlay CE state.
First thing first, create the HUD view in Flash IDE.

hud

Well, I must admit that it’s an ugly HUD design. But at least it show enough information for the players.

Nothing special here, just put some dynamic text, give em a instance name, and add some beautiful red background and labels.

Finally put them onto the game. Open your game state class. Move to initialize() method. And after we call super.initialize(), put this code:
initHUD(); 

This is to make sure the HUD will not overlaid by CE objects.

The code inside initHUD() method:
private function initHUD():void
 {
     hud = new HUDMC();
     hud.levelx.text = "LEVEL " + String(level);
     hud.scorex.text = currentLevelData.getData(PlayerData.SCORE);
     hud.moneyx.text = currentLevelData.getData(PlayerData.MONEY);
     addChild(hud);
            
     pauseBtn = new PauseBtn();
     pauseBtn.x = pauseBtn.width / 2;
     pauseBtn.y = 350;
     pauseBtn.buttonMode = true;
     addChild(pauseBtn);
            
     endBtn = new EndBtn();
     endBtn.x = stage.stageWidth - endBtn.width / 2;
     endBtn.y = 350;
     endBtn.buttonMode = true;
     addChild(endBtn);
            
     pauseBtn.addEventListener(MouseEvent.CLICK, buttonClicked, false, 0, true);
     pauseBtn.addEventListener(MouseEvent.MOUSE_OVER, buttonOver, false, 0, true);
     pauseBtn.addEventListener(MouseEvent.MOUSE_OUT, buttonOut, false, 0, true);
            
     endBtn.addEventListener(MouseEvent.CLICK, buttonClicked, false, 0, true);
     endBtn.addEventListener(MouseEvent.MOUSE_OVER, buttonOver, false, 0, true);
     endBtn.addEventListener(MouseEvent.MOUSE_OUT, buttonOut, false, 0, true);
 }

Yep, we initialize all fixed HUD here and also some additional buttons.
Nothing more to explain here…

2. Dynamic HUD
This one need more work than its big brother, cause we can’t use a flash display object anymore to create it. We need to working with CE view classes, ie: CitrusSprite, SpriteArt, etc.

We will build a health bar that follow our Hero. So the very first step is create the view in Flash IDE:

hud2

There are two objects: background and bar. The background is just a bitmap image, while the bar is a MovieClip as we need some flash display object operation for this bar. For example, scaling em to make the bar shorter when the health is low/reduced, and make it longer when he pick a health bonus.

And don’t forget give the bar an instance name, so we can access it in the code.

To integrate it to the Hero class, first we need to create another class that extends Hero.as. We named it CustomHero.as.

And here are the class:
package src.objects 
{
    import com.citrusengine.objects.CitrusSprite;
    import com.citrusengine.objects.platformer.box2d.Hero;
    import src.data.CurrentLevelData;
    
    public class CustomHero extends Hero 
    {
        private var hpBar:CitrusSprite;
        
        public function CustomHero(name:String, params:Object=null) 
        {
            super(name, params);            
        }        
        
        override public function initialize(poolObjectParams:Object = null):void 
        {
            super.initialize(poolObjectParams);
            
            hpBar = new CitrusSprite("hp_bar", { view:HPBarMC } );
            _ce.state.add(hpBar);
        }
        
        override public function update(timeDelta:Number):void 
        {
            super.update(timeDelta);
            
            hpBar.x = x;
            hpBar.y = y - height / 2 - 10;
        }
        
        override public function destroy():void 
        {
            hpBar.kill = true;
            
            super.destroy();
        }
        
        public function getHPBar():CitrusSprite
        {
            return hpBar;
        }
    }
}

We only need to put some addition here. Yep, you can see it, a CitrusSprite object named hpBar. That is the hp bar we’re working on.
Simply instantiate it in the initialize() method. Give em name and view.

In the update() method, set its position so it will always follow hero’s movement. Vertical position will always same with the hero, while to make it always on top of hero’s head, just calculate hero topmost position and subtract it with some value as spacing (in this example, the spacing is 10 pixels).

Don’t forget to remove it when the hero destroyed.

Also I create a getter method to access this hp bar. Actually I can use a public access identifier for the hpBar variable, so no need to create this method. But, yeah, it’s just a matter of coding style, as I’m not a big fan of public properties…

And… Done…
Compile it and run it, and you’ll get this result:

As always, you can download the complete source code here:

3 comments:

  1. All the important classes, like GameOverMC, is missing from the source code,,

    ReplyDelete
    Replies
    1. It's inside the FLA file.
      FYI, it's Flash Pro project, but the coding is using Flash Develop.

      Delete