PDA

View Full Version : [AS3] Coding a Health BAR


...ENTER_FORUM,username)
01-18-2010, 08:41 AM
A little background story before i post my problem. I'm very, very, very new to flash and actionscript in general. But i was on kongregate a week or two ago and saw the Shootorials and decided i've played enough games it was time to make one, so i had started with AS2 for about 6 seconds before i realized that there was a newer AS3 and being that im new to this i should start with the most current form of the language.

Well i ended up cobbling together tutorials from about 3-4 sites to make what i've got so far a shooter where the animation changes based on the arrow key pressed and speed, boundaries, randomly produced enemies that target the ship and dodge bullets, and a health bar that does nothing -.-.

Inside my enemy class are the variables that should control my health bar
(enemy class variables)
private var HPbar:Number;

private var badHP:Number = 0;

private var attk:Number = (badHP)*.01 //because scalex expects decimals in AS3

private var update:Number;


(enterframe stuff)loop(e:Event) {


var HPbar = core.thebar.zooka.scaleX; /*inside my Onadd i set core=MovieClip(root) and under enemy class it's private var core:Object;*/

var update = HPbar - attk;

if (hitTestObject(core.sp)) {/

(blow up ship/remove event listeners stuff)
badHP=20;
update;
}

The enemy ships blow up just fine but the health bar doesn't move an inch.

Alternatively i tried removing all the health variables and just adding this to the HitTest core.thebar.zooka.gotoAndStop(currentFrame+1); and it worked sort of but it was acting...erratically it would empty the HP bar on first strike then it would jump to 20% HP frame, then 80% HP frame, then 60% then 0 again.

can anyone help me fix this or has a better way for interacting with the health bar?

IMPORTANT INFO ON THE HEALTH BAR:
I have it added to the stage from action from on the stage timeline(just like the enemies and hero ship)it's added with the name 'thebar'.

Because i worked on it using the AS2 shootorial as a guideline the MovieClip Health has 3 layers (the border, bar, and background) the bar which actually is the health Bar is a movieclip on the second layer of the movie clip Health so i call it like this:

core.thebar(its instance name from the action frame on the stage).zooka(the instance name i gave it under it's properties).(whatever)

k1k
01-18-2010, 08:51 AM
Unless I forgot to read something, I dont see your code actually resizing the sprite

...ENTER_FORUM,username)
01-18-2010, 08:54 AM
Unless I forgot to read something, I dont see your code actually resizing the sprite

alright so i can just make a new value for scaleX and it resizes the mc? i cant have

function w/e
scaleX=.5

how do i go about getting it to resize the health bar?

Mazoonist
01-18-2010, 09:10 AM
Post your real code (not pseudocode), and format it using the [ as ] and [ /as ] tags (take out the spaces).

...ENTER_FORUM,username)
01-18-2010, 09:14 AM
package {

import flash.events.Event;
import flash.display.MovieClip;
import flash.display.Sprite;

public class Aenemy extends MovieClip {
private var core:Object;
private var yd:Number;
private var xd:Number;
private var HPbar:Number;
private var badHP:Number = 0;
private var attk:Number = (badHP)*.01
private var update:Number;



public function Aenemy() {
addEventListener(Event.ADDED_TO_STAGE,onadd);
}

private function onadd(e:Event) {
core=MovieClip(root);
yd = core.sp.y-y;
xd = core.sp.x-x;






addEventListener(Event.ENTER_FRAME,loop);

}

private function loop(e:Event) {



var HPbar = core.thebar.zooka.scaleX;
var update = HPbar - attk;
var update = core.thebar.zooka.scaleX;


var angle:Number=Math.atan2(yd,xd);

y+=Math.sin(angle)*3;
x+=Math.cos(angle)*3;

if(y>335) {
y=-8;
}
if(y<-9) {
y=334;
}

if (hitTestObject(core.sp)) {





var boom:MovieClip = new explosion();
boom.x=x;
boom.y=y;
stage.addChild(boom);
removeEventListener(Event.ENTER_FRAME, loop);
core.removeChild(this);
badHP=20;
update;

}



for (var i:int = 0; i<core.bulletholder.numChildren; i++) {

var bulletTarget:Sprite=core.bulletholder.getChildAt(i );

var ris:Number=bulletTarget.y-y;
var run:Number=bulletTarget.x-x;
var dis:Number=Math.sqrt(Math.pow(ris,2)+Math.pow(run, 2));

if (dis<100) {
if (ris<0) {
y+=4.5;
}if(ris>0) {
y-=4.5;
}

}


if (hitTestObject(bulletTarget)) {
core.bulletholder.getChildAt(i).removeListeners();
core.bulletholder.removeChild(bulletTarget);

var boom:MovieClip = new explosion();
boom.x=x;
boom.y=y;
stage.addChild(boom);

removeEventListener(Event.ENTER_FRAME, loop);
core.removeChild(this);
}
}

}

public function removeListeners():void {
removeEventListener(Event.ENTER_FRAME, loop);
}
}
}

Mazoonist
01-18-2010, 09:19 AM
Probably what's happening though (among other things) is that you are not realizing that when you test for a hit and it comes back true, it KEEPS coming back true continually, because it's in an ENTER_FRAME event. So when you tell it to do something in response, it'll do that thing continually. If your framerate is 30 fps, it does it 30 times per second, which could quickly deplete your health bar indeed!

What you need to do is resolve the hit somehow. For example, you can set it up so that you only register the initial hit. Set up a boolean variable (example, call it "hitting") and test for it in addition to the hit Test:

var hitting:Boolean = false;

function everyFrame(event:Event):void {
if(mc1.hitTestObject(mc2) && hitting == false) {
hitting = true;
healthBar.width -= 5;
}
}

With a system something like the above, you only allow one hit to register until you resolve it somehow (pulling the objects apart is one obvious resolution) and when you do this other thing, then set your hitting variable back to false again, setting it up for another hit.

...ENTER_FORUM,username)
01-18-2010, 09:21 AM
I figured out a workaround. I removed the health bar movieclipd from the health movieclip ( i removed the actual bar from its borders).

I added it to the stage with the stage action frame ( i added it before the health borders so that they'd be on top).

it's addChild instance name is KP

Then i added this to the enemy class

core.KP.scaleX-=.2;

package {

import flash.events.Event;
import flash.display.MovieClip;
import flash.display.Sprite;

public class Aenemy extends MovieClip {
private var core:Object;
private var yd:Number;
private var xd:Number;
//private var HPbar:Number;
//private var badHP:Number = 0;
//private var attk:Number = (badHP)*.01
//private var update:Number;



public function Aenemy() {
addEventListener(Event.ADDED_TO_STAGE,onadd);
}

private function onadd(e:Event) {
core=MovieClip(root);
yd = core.sp.y-y;
xd = core.sp.x-x;






addEventListener(Event.ENTER_FRAME,loop);

}

private function loop(e:Event) {



// var HPbar = core.thebar.zooka.scaleX;
//var update = HPbar - attk;
//var update = core.thebar.zooka.scaleX;


var angle:Number=Math.atan2(yd,xd);

y+=Math.sin(angle)*3;
x+=Math.cos(angle)*3;

if(y>335) {
y=-8;
}
if(y<-9) {
y=334;
}

if (hitTestObject(core.sp)) {





var boom:MovieClip = new explosion();
boom.x=x;
boom.y=y;
stage.addChild(boom);
removeEventListener(Event.ENTER_FRAME, loop);
core.removeChild(this);
core.KP.scaleX-=.2; //what i changed to make it work.
//badHP=20;
//update;

}



for (var i:int = 0; i<core.bulletholder.numChildren; i++) {

var bulletTarget:Sprite=core.bulletholder.getChildAt(i );

var ris:Number=bulletTarget.y-y;
var run:Number=bulletTarget.x-x;
var dis:Number=Math.sqrt(Math.pow(ris,2)+Math.pow(run, 2));

if (dis<100) {
if (ris<0) {
y+=4.5;
}if(ris>0) {
y-=4.5;
}

}


if (hitTestObject(bulletTarget)) {
core.bulletholder.getChildAt(i).removeListeners();
core.bulletholder.removeChild(bulletTarget);

var boom:MovieClip = new explosion();
boom.x=x;
boom.y=y;
stage.addChild(boom);

removeEventListener(Event.ENTER_FRAME, loop);
core.removeChild(this);
}
}

}

public function removeListeners():void {
removeEventListener(Event.ENTER_FRAME, loop);
}
}
}

...ENTER_FORUM,username)
01-18-2010, 09:29 AM
Probably what's happening though (among other things) is that you are not realizing that when you test for a hit and it comes back true, it KEEPS coming back true continually, because it's in an ENTER_FRAME event. So when you tell it to do something in response, it'll do that thing continually. If your framerate is 30 fps, it does it 30 times per second, which could quickly deplete your health bar indeed!

What you need to do is resolve the hit somehow. For example, you can set it up so that you only register the initial hit. Set up a boolean variable (example, call it "hitting") and test for it in addition to the hit Test:

var hitting:Boolean = false;

function everyFrame(event:Event):void {
if(mc1.hitTestObject(mc2) && hitting == false) {
hitting = true;
healthBar.width -= 5;
}
}

With a system something like the above, you only allow one hit to register until you resolve it somehow (pulling the objects apart is one obvious resolution) and when you do this other thing, then set your hitting variable back to false again, setting it up for another hit.

This sounds like why the (currentFrame+1) function workaround was acting so "erratically" but i think the reason it wasn't working with the all that HPbar and badHP junk is what the other guy said it wasn't changing the value of the bars scaleX and so it was running 30 times per second it just wasn't doing anything. But if it had done something (like currrentFrame) i would've run into the same problem you just described and had my healthbar just instant depleting on contact.

Mazoonist
01-18-2010, 09:29 AM
Sorry, I wrote my post before I waited for your reply. So it looks like you are resolving the hit by removing the listener, which is fine. So maybe your problem is the scaleX thing. Try reducing the width instead. Set the registration point of the bar on the left hand side.

studio1
01-18-2010, 09:50 AM
To design interiors and exteriors, desginer furniture, etc. which meet our clients needs and their life style, of International standerd by adopting State-Of-the-art technology and innovative skills.
Nagesh S Singh
Directer
http://www.Studiosvelte.com

Dugout09
01-18-2010, 02:10 PM
hello,

I read up on your post and I thinking you want to add a health bar to your Hero or enemy on stage. The health bar depletes as the enemy or hero takes damage, then over time or on pick up of a health pack will regenerate the health back.

The line of code to set up the scaleX or scaleY of the health bar movieClip is quite simple. Whats not simple is everything else in between.


var warrior:Warrior = new Warrior();//this is a linkage MovieClip of the Hero in the game

var timerHealthReg:Timer = new Timer(5000);//every 5 seconds if health is lower than tempHealth the warrior.health will start to regenerate
var timerHealth:Boolean = false;

warrior.health;// this is the warriors current health through out the game
warrior.tempHealth;// this is the warriors total health and only changes if warrior for some reason incresses his total amount of health
warrior.healthReg;// this number is the amount of health per tick of our timer the warrior will reg.

//setup are function to call whenever are warrior has taken damage or health is depleted in some form. All we need to do is call this function
timerHealthReg.addEventListener(TimerEvent.TIMER, onTickHealthReg, false, 0, true);
function onTickHealthReg(evt:Event):void {
timerHealth = true;
healthReg();
}
//this funk is called from the funk above
function healthReg() {
if(warrior.health < warrior.temphealth) {
warrior.health += warrior.healthReg;
trace("This is health updating " + warrior.health);
//note: the healt bar is not a linked movieClip and is on stage
uiHealthBar.healthBar.scaleY = warrior.health / warrior.tempHealth;// <---- the code that will scaleY on the health bar
if(warrior.healthReg > warrior.tempHealth - warrior.health || warrior.tempHealth == warrior.health) {
timerHealth = false;
warrior.health = warrior.tempHealth;
timerHealthReg.removeEventListener(TimerEvent.TIME R, onTickHealthReg);
}
}
}



I'm not going into the function which will deplete the health for the code is the same but instead of adding +50 on timer tick, you are -50 when the warrior is taking damage or depleting his health. The code is the same to scaleY because of the +-.

Now, when you create the movie clip that will be your health bar on stage you need to remember the resgstration point needs far bottem if going to scaleY or far left if scaling X moving from left to right (left being 0 health and right being 100% or full).

Thanks,

Dugger, Dan

P.S. if you need futher help on this topic. Look into a Per-Loader bacily does the same thing only for bytes downloaded / bytes total.