AS2 – Health Bars: Solid Bar Type

Health bars and pre-loaders work essentially the same way (continue to the end of the tutorial to learn how to apply this to a pre-loader bar), and they come in many varieties. The simplest health bar I can think of merely subtracts damage from the width or height of a solid bar. This type of health bar (what I call the solid bar type) is simple, easy, and (let’s face it) bland; but nevertheless, it’s a good place to start learning how to make them. To create the solid bar type, all you’ll need a movie clip containing a relatively bar-shaped graphic element, something to generate your damage, and a function to apply that damage by reducing the bar’s width or height.

Step 1:

For simplicity’s sake (as per my standard), I’ll start this tutorial with a new flash document (mine is 400px by 100px), but feel free to start yours however you feel comfortable. Next, create a new layer on your time line, name it “Actionscript” and lock it so you don’t accidentally put anything in it. Then name your other layer anything you’d like; I named mine “Stage” (see Fig. 1-1).

Figure 1-1

Figure 1-1

Once that’s done, I then began creating my health bar. Simply select the rectangle tool (R) (no stroke, I’ll explain later), a color of your choice, and draw your health bar. I made mine 340px wide by 20px high and red, but again, feel free to use any measurements you like. As a rule though, you want to make it longer in whichever direction you’re going to be reducing; so if you’re reducing the width, make it wider, but if you’re reducing the height, then make it taller.

Step 2:

Next, I selected my new art and converted it to a movie clip symbol (F8), naming it “bar_mvc” and setting it’s orientation to the upper left corner (this is important), then gave it the same instance name (see Fig. 2-1 and 2-2). Now, the orientation is important because when you subtract from the symbol’s dimensions, it will shrink in that direction, so be mindful of which direction you want it to shrink when choosing its orientation.

Figure 2-1

Figure 2-1

Figure 2-2

Figure 2-2

Step 3:

After that, I placed three (3) instances of Flash’s built-in button component on the stage; to do this, simply drag and drop them from the components window and onto the stage. Then I named them “light_hit_btn”, “moderate_hit_btn”, and “heavy_hit_btn”, labeling them “Light Hit”, “Moderate Hit”, and “Heavy Hit” respectively (see Fig. 3-1, 3-2, and 3-3).

Figure 3-1

Figure 3-1

Figure 3-2

Figure 3-2

Figure 3-3

Figure 3-3

This is by no means necessary; I only did this to create a user-dependent catalyst for generating different amounts of damage. I’m sure you have something else in mind for that task, so please feel free to alter the script as you require; but for now please observe the demonstration.

Step 4:

Now, with the bar and the three (3) buttons in place, it’s time to program this thing and give it some life. Basically we need two (2) things here; we need to generate a random number to represent damage, and we need to apply that damage to the health bar. So I selected my Actionscript layer, opened my Actionscript panel (F9) and entered the following code (just copy and paste, I’ll explain below):

/////////////////////////////////////////////////////////////////////////////////////////
// VARIABLES ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

var maxHealth:Number = new Number(340); // define maxHealth; set to 340 px
var lightHitMin:Number = new Number(10); // define lightHitMin; used when calling GenerateDamage in the light hit button
var lightHitMax:Number = new Number(lightHitMin * 2); // define lightHitMax; used when calling GenerateDamage in the light hit button
var moderateHitMin:Number = new Number(lightHitMax); // define moderateHitMin; used when calling GenerateDamage in the light hit button
var moderateHitMax:Number = new Number(moderateHitMin * 2); // define moderateHitMax; used when calling GenerateDamage in the light hit button
var heavyHitMin:Number = new Number(moderateHitMax); // define heavyHitMin; used when calling GenerateDamage in the light hit button
var heavyHitMax:Number = new Number(heavyHitMin * 2); // define heavyHitMax; used when calling GenerateDamage in the light hit button

/////////////////////////////////////////////////////////////////////////////////////////
// DEFAULTS /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

bar_mvc._width = maxHealth; // set the inital width of bar_mvc

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

function GenerateDamage (_min:Number, _max:Number):Void
{ // define the GenerateDamage function
	var myDamage:Number = Math.floor(Math.random()*(_max-_min))+_min; // generate a random number, save it in the variable "myDamage"
	trace("myDamage = " + myDamage); // send myDamage to output window for debugging
	bar_mvc._width -= myDamage; // subtract myDamage from the current width of bar_mvc
} // end the GenerateDamage function

/////////////////////////////////////////////////////////////////////////////////////////
// BUTTONS //////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

light_hit_btn.onRelease = function () 
{ // when "light_hit_btn" is released (after click)
	GenerateDamage(lightHitMin, lightHitMax); // execute GenerateDamage function with a damage range of 5-10
} // end function light_hit_btn.onRelease

moderate_hit_btn.onRelease = function ()
{ // when "moderate_hit_btn" is released (after click)
	GenerateDamage(moderateHitMin, moderateHitMax); // execute GenerateDamage function with a damage range of 10-20
} // end function moderate_hit_btn.onRelease

heavy_hit_btn.onRelease = function ()
{ // when "heavy_hit_btn" is released (after click)
	GenerateDamage(heavyHitMin, heavyHitMax);// execute GenerateDamage function with a damage range of 20-40
} // end function small_hit_btn.onRelease

For the explanation, let’s start with the variables at the top. I generally like to define all of my variables ahead of time unless they’re going to be temporary, such the temporary variables used in loops, or they are function-specific, such as myDamage within the GenerateDamage function. This used to be required with programming, it was called prototyping the variables, but these days it’s not really necessary. However, it’s a good idea because it can help keep track of your data while you program and it can help avoids scoping issues.

The maxHealth variable is set and then used to set the starting width of bar_mvc when the movie loads. If you change this variable, you will change the starting width of bar_mvc and thus give the character more or less initial health; but this must be done before you compile (publish) the program because the command that sets the width of bar_mvc only happens once, so changing it while the program is running wouldn’t do anything.

After that, I have the min and max variables that will be used when the function GenerateDamage is called later. Each of these variables has a specific purpose and use, and while I could just use static values in the function calls, I decided to use variables so that they could be changed later if need be with very little recoding. As you can see, the variable lightHitMin is the only variable with a static value. After that, each max variable is set to twice the value of its corresponding min value, which is set to equal the value of the previous max variable. With this, all I have to do it set one variable and all the rest will adjust accordingly. This has no real bearing on the health bar, but it’s a quick, simple way to control the different amounts of damage.

Next we have the function GenerateDamage which takes two (2) arguments (_min and _max). These arguments are used together to define the total range of the random number that it will generate using the Math.random() method. You see, Math.random() works by generating a decimal between 0.0 and 1.0. You can then modify this decimal by multiplying it by the maximum number you want to allow; so if you want to generate a number between 0 and 5, you’d multiply it by 5. On the other hand, if you want that range to be between 1 and 6 (to simulate a 6-sided die for example), you’d still multiply it by 5, but then add 1 to the product; changing the 0-5 range to 1-6.

In addition to Math.random(), we’ll also use Math.floor(), which rounds any decimal down to a nice, neat whole number. There’s really no problem with using decimals if you really want to be that precise, I just don’t generally do it unless there’s actually a reason for it. What’s more, using Math.floor() will limit the total number of possible products. 1-6 might actually have thousands of possible products if each number is accurate to the thousandths place (ie. 2.23, 4.91, 5.99, etc…). As a note, we could use Math.round(), which would round the number to the nearest whole, rather than always down, but that gives the very slight, but still possible chance of producing the upper limit, which, when incremented by 1, would break the upper limit. Now maybe your game doesn’t need to be that sensitive, but you might be surprised at the difference 1% can make (see Variation, below). Also, I know this seems a bit complicated and all, and yes, you could simply use random() instead of Math.random() to avoid having to round the product down (because random() only produces whole numbers). I use Math.random() just because it’s the standard, it maintains continuity in my code, and because it’s useful for more than just what we’re applying it to.

Either way, when we multiply the random number, we’ll actually be using the difference between the given maximum and minimum numbers. We do this to ensure that our final product is limited to the range between the given limits, rather than the maximum PLUS the minimum. For instance, if _min is 35 and _max is 40, and if we didn’t subtract _min from _max before multiplying, we’d end up with a range of 35 to 75 instead of 35 to 40. So just to make sure I’ve done it right, I included a quick trace to see exactly how much damage is being applied.

Then I subtract the damage from the current width of the health bar (bar_mvc), using the “-=” operator. This does not just set the value of the variable, this is a mathematical operator that subtracts the value given on the right side of the equation from the current value of the variable on the left, saving the new value in that same variable; it is the same as saying “subtract from itself” (something that would otherwise be written as var1 = var1 – value).

Now, you may notice as you test this movie, that the damage isn’t really a whole lot. Well that’s because we’re subtracting no more than 80 pixels from something that’s 340 pixels wide. A lot of other programmers would simply use a percentage to calculate damage, thus making it more effective (subtracting 80 PERCENT of the total health, rather than 80 PIXELS), and while it is quite effective, it’s not necessarily the best method. It all depends on what you’re doing with it. If you want your enemies to deal the same amount of damage no matter how big your health bar is, then use percentages, but if you want your character to have the ability to gain more health as the game is played, thus making old enemies not so deadly anymore, then you’ll want to subtract a static number that (as the health bar gets bigger) will be less and less effective.

Finally, the last thing on the script is the buttons, and they’re relatively simple. When the button is released after clicking, it will execute the GenerateDamage function with a specific range, which, as I said earlier, use variables to control. So as it stands, since I set lightHitMin to 10, the light hit will deal 10 to 20 points (read: pixels) of damage, the moderate hit will deal 20 to 40 points, and the heavy hit will deal 40 to 80 points.

Now, with this in place we can see how each “hit” will affect the health bar. You’ll notice it’s not much, and again that’s because we’re subtracting small numbers (10-80) from a very large number (340) (see Fig 4-1, 4-2, and 4-3).

Figure 4-1

Figure 4-1

Figure 4-2

Figure 4-2

Figure 4-3

Figure 4-3

Percentile Variation:

Now then, if you do want your character to have the same amount of health regardless of the size of the health bar, as I described above, you can apply the damages as percentages of the total (not current) width of your bar; but to do this, we’re going to change a few lines of code:

function GenerateDamage (_min:Number, _max:Number):Void
{ // define the GenerateDamage function
	var myDamage:Number = Math.floor(Math.random()*(_max-_min))+_min; // generate a random number, save it in the variable "myDamage"
	trace("myDamage = " + myDamage + "% (of " + maxHealth + ")"); // send myDamage to output window for debugging
	bar_mvc._width -= (myDamage*maxHealth)/100; // subtract myDamage from the current width of bar_mvc
} // end the GenerateDamage function

As you can see, I changed the trace within the GenerateDamage function (adding the maxHealth variable to the output), but more importantly, I changed the line that set’s the bar’s width. I calculated the percentage of damage by multiplying myDamage by the maxHealth, then dividing the product by 100. And now, not only does each attack seem more effective, the overall amount of damage each hit does will remain the same no matter how wide the bar is originally (see Fig 4-4, 4-5, and 4-6) (note: this is a variation of the original script; the remainder of this tutorial, however, will use the original script.)

Figure 4-4

Figure 4-4

Figure 4-5

Figure 4-5

Figure 4-6

Figure 4-6

Step 5:

Unfortunately, this method (and the variation) has a bug: if the damage being subtracted is greater than the remaining width, the operation fails and the width remains the same. So in order to handle reducing the health bar to or below 0, the operation must be wrapped with an “if…then” statement that will check to make sure there is enough health left to take the damage; and if not, it needs to do something to alert that the health bar is depleted.

So we need to alter the GenerateDamage function to check to see if the health bar has enough width to take the damage that was generated; so basically, if the damage being taken is greater than the remaining health, then the script needs to do something else:

function GenerateDamage (_min:Number, _max:Number):Void
{ // define the GenerateDamage function
	var myDamage:Number = Math.floor(Math.random()*(_max-_min))+_min; // generate a random number, save it in the variable "myDamage"
	if (myDamage > bar_mvc._width)
	{ // if the damage being taken is greater than the remaining health...
		bar_mvc._width = 0; // set width of bar_mvc to 0
		light_hit_btn.enabled = false; // diable the hit buttons
		moderate_hit_btn.enabled = false;
		heavy_hit_btn.enabled = false;
		trace("Game Over!"); // trace end game message
	} // end if the damage being taken is greater than the remaining health
	else
	{ // else (if the damage being takes is NOT greater than the remaining health)...
		trace("myDamage = " + myDamage); // send myDamage to output window for debugging
		bar_mvc._width -= myDamage; // subtract myDamage from the current width of bar_mvc
	} // end else (if the damage being takes is NOT greater than the remaining health)
} // end the GenerateDamage function

Now, in an actual game you might want something a little more interactive than just this (see Fig. 5-1) (note: if you are using the percentage variation, the “if…then” statement must use the same calculation as used to set the width of bar_mvc, reading “if ((myDamage*maxHealth)/100 > bar_mvc._width)” – rather than just “myDamage”).

Figure 5-1

Figure 5-1

Step 6:

That’s basically it, though it still looks a little boring, but that’s not impossible to fix. Now you can make this bar look like anything you want. You can even add graphics over top and behind it, and fully customize it to suit your game; all you need do is make sure you have the correct target path in the end and the code work like a charm.

Here’s an easy example:
First, select bar_mvc and create a new symbol with it (again). This will create a nested symbol; bar_mvc will still exist, but it will exist within the new symbol you are creating now. I called this new symbol “health_mvc”, and again I gave it the same instance name. Next, double click on that symbol to open it. Then you’ll need to create two (2) additional layers in this symbol’s time line, one above the layer with bar_mvc in it, and the other below that layer (refer to figure 1-1 for how to do this).

Next, just to keep everything easier to understand, it’s best to name your layers. I named my top layer “border,” the middle layer (the one with bar_mvc on it) “bar,” and the bottom layer “background.” It’s also a good idea at this point to lock the layer containing bar_mvc so that you don’t accidentally add anything else to it; this just helps keep each element separate and easier to handle.

Then on the bottom layer, I added a colored graphic of exactly the same size as bar_mvc; this will only show once damage has been applied and will help distinguish between the player’s remaining health and spent health; I made mine light gray. Now, if you plan to give yourself the option of changing the health bar’s overall width during your game (giving your character more health, or just resizing the health bar), you’ll need to make this a symbol as well, so you can always make it’s width match the max width of your health bar; I named mine “bar_bg_mvc” (and make sure it has the same orientation as bar_mvc). After that, on the top layer, add whatever borders or graphics you like (I made something quick and simple with semicircles). (see Fig. 6-1)

Figure 6-1

Figure 6-1

But before you’re finished, don’t forget to update the Actionscript to accommodate the new target path to your health bar. First, go back to the root time line by either clicking the blue arrow or the clapboard in the upper-left corner of the timeline panel (see Fig. 6-2) or double click anywhere outside all of the elements inside the symbol. (note: ignore the fact that figure 6-2 displays “health_meter_mvc” instead of “health_mvc” – that’s not the important part of the image.)

Figure 6-2

Figure 6-2

Then open your Actionscript panel (F9) to make the following changes (note the addition of “health_mvc” in some of the target paths):

/////////////////////////////////////////////////////////////////////////////////////////
// DEFAULTS /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

health_mvc.bar_mvc._width = maxHealth; // set the inital width of health_mvc.bar_mvc
health_mvc.bar_bg_mvc._width = maxHealth; // set the width of health_mvc.bar_bg_mvc

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

function GenerateDamage (_min:Number, _max:Number):Void
{ // define the GenerateDamage function
	var myDamage:Number = Math.round(Math.random()*(_max-_min))+_min; // generate a random number, save it in the variable "myDamage"
	if (myDamage > bar_mvc._width) 
	{ // if the damage being taken is greater than the remaining health...
		health_mvc.bar_mvc._width = 0; // set width of bar_mvc to 0
		light_hit_btn.enabled = false; // diable the hit buttons
		moderate_hit_btn.enabled = false;
		heavy_hit_btn.enabled = false;
		trace("Game Over! \n\n"); // trace end game message
	} // end if the damage being taken is greater than the remaining health
	else
	{ // else (if the damage being takes is NOT greater than the remaining health)...
		trace("myDamage = " + myDamage); // send myDamage to output window for debugging
		health_mvc.bar_mvc._width -= myDamage; // subtract myDamage from the current width of bar_mvc
	} // end else (if the damage being takes is NOT greater than the remaining health)
} // end the GenerateDamage function

Once that’s done, it should work fine. The damage will be applied to the health bar, leaving the border and background in tact (again, see Fig. 6-1). All you’ll need now is to create a script to make the movie do something interesting when the health bar reaches 0; but that part’s all up to you.

Mask Variation:

Another variation on this method is to use a mask, which is basically a graphic element placed on top of another graphic that only shows the bottom graphic where the top graphic exists. Think of it like a scope; you can only see what the scope is aimed at.

For this, I created health_meter_mvc just as I did in step 6, but rather than creating a border and a background, I created a mask layer and repeated a simple heart graphic over the entire length of the bar (see Fig 6-3 and 6-4). Then I right-clicked on the layer, which contains only the heart graphics, and selected the mask option (see Fig 6-5).

Figure 6-3

Figure 6-3


Figure 6-4

Figure 6-4


Figure 6-5

Figure 6-5

With that in place it gives the appearance that the health bar is a series of hearts and that each hit takes away a piece of those hearts. In reality it is doing nothing more than subtracting from the width of the health bar, but all we can see of that bar is through the hearts (see Fig 6-6).

Figure 6-6

Figure 6-6

Making a Pre-Loader:

Like I said earlier, a pre-loader is a lot like a health bar, it just works in the opposite way; rather than shrinking, the width grows. This is not because you’re adding anything to the width, with a pre-loader you’re setting the bar with the percentage of how much of the movie has been loaded.

To make a pre-loader, all you’ll need is an empty movie clip, the loader bar, and a script to analyze the percentage of how much of the movie is loaded. Basically, you load the flash movie into itself, into the empty movie clip (which you make invisible), then as it loads you use getBytesLoaded() and getBytesTotal() to calculate the percentage of the movie that is loaded, which you then pass to the width of your loader bar.

Now I know this is very vague, but this isn’t a loader bar tutorial, this is a health bar tutorial. For more information on making a loader bar, visit my Loader Bar Tutorial (coming soon), which can be found, with many others, on my Tutorials page.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.