[guide] Flash hud
<div class="IPBDescription">Positioning elements - .fla and code</div>I'm a programmer but have never touched flash - I've only just started poking around with it. I'm creating a custom HUD and thought of a nifty way to position elements in a way that will work with any screen res.
The idea behind this code is that my canvas is 640x480 and I can position my elements however I like and the code will use the offsets (in this example the offset from the right of the screen) to position elements correctly in-game. It means I can just move the stuff around the canvas and leave the code to take care of repositioning it ingame.
The code also only positions the elements once, when the hud loads.
I also thought a .fla would be handy for any other noobs to get started with, because I haven't seen anyone else post one.
Here it is ingame. Still a WIP, naturally:
<a href="http://imgur.com/Kaptk.jpg" target="_blank"><img src="http://imgur.com/Kaptk.jpg" border="0" class="linked-image" /></a>
Code:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->onEnterFrame = function ()
{
if (not _root.locationsSet)
{
shpReticle._x = Math.floor(Stage.width / 2);
shpReticle._y = Math.floor(Stage.height / 2);
shpHealth._x = Math.floor(Stage.width - (640 - shpHealth._x));
shpHealth._y = Math.floor(Stage.height - (480 - shpHealth._y));
txtHealth._x = Math.floor(Stage.width - (640 - txtHealth._x));
txtHealth._y = Math.floor(Stage.height - (480 - txtHealth._y));
_root.locationsSet = true;
}
txtHealth.text = lua("PlayerUI_GetHealth");
}<!--c2--></div><!--ec2-->
<a href="http://www.mediafire.com/file/mmg0oygrmyt/marine_hud.fla" target="_blank">Click here to download the .fla as a starting point for your own hud</a>
Also, note that this relies on a method for getting player health which isn't in the standard engine test. I'm working on this HUD for a mini-mod :)
The idea behind this code is that my canvas is 640x480 and I can position my elements however I like and the code will use the offsets (in this example the offset from the right of the screen) to position elements correctly in-game. It means I can just move the stuff around the canvas and leave the code to take care of repositioning it ingame.
The code also only positions the elements once, when the hud loads.
I also thought a .fla would be handy for any other noobs to get started with, because I haven't seen anyone else post one.
Here it is ingame. Still a WIP, naturally:
<a href="http://imgur.com/Kaptk.jpg" target="_blank"><img src="http://imgur.com/Kaptk.jpg" border="0" class="linked-image" /></a>
Code:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->onEnterFrame = function ()
{
if (not _root.locationsSet)
{
shpReticle._x = Math.floor(Stage.width / 2);
shpReticle._y = Math.floor(Stage.height / 2);
shpHealth._x = Math.floor(Stage.width - (640 - shpHealth._x));
shpHealth._y = Math.floor(Stage.height - (480 - shpHealth._y));
txtHealth._x = Math.floor(Stage.width - (640 - txtHealth._x));
txtHealth._y = Math.floor(Stage.height - (480 - txtHealth._y));
_root.locationsSet = true;
}
txtHealth.text = lua("PlayerUI_GetHealth");
}<!--c2--></div><!--ec2-->
<a href="http://www.mediafire.com/file/mmg0oygrmyt/marine_hud.fla" target="_blank">Click here to download the .fla as a starting point for your own hud</a>
Also, note that this relies on a method for getting player health which isn't in the standard engine test. I'm working on this HUD for a mini-mod :)
Comments
You could do it in flash, but depending on what you mean exactly a shader might be more appropriate.
The solution (in the skulk bite -> hide crosshair example) is very straight forward. Your weapon will expose a GetShowCrosshair() function, which in turn will be exposed by the Player class. This would be called by a function in PlayerUI.lua.
The flash code is nice and simple:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->shpReticle._visible = lua("PlayerUI_GetShowCrosshair");<!--c2--></div><!--ec2-->
I mean, that's some great news to me since I work on Flash for a living, but... what the hell ?! I mean... SWF files in something else than FlashPlayer ?!!
So, so, so... NS2 doesn't handle every flash functionality just like you might expect it would. Here's my test report :
<b>BITMAPS</b> :
They're handled, pretty good in fact. Scale is in, Rotation is in. PNG alpha channel is in. The fun fact is that even if you do NOT tick "allow smoothing" on bitmap properties, you get some really cool anti alias effect on it. Actually it'll look far worse on FlashPlayer than in NS2. So don't worry.
<b>MOVIECLIPS</b> :
They loop as they should. They're still independent from the main timeline playback.
<b>TIMELINE</b> :
As I thought, NS2 is only reading ONCE action script because timeline is only 1 frame long. And that's a special case in Flash, since it assumes there's no timeline at all on the stage. If you build a SWF with only 1 fame, and put it in FlashPlayer, you won't be able to access "play" or "loop" or even "rewind" in the contextual menu. With 2+ frames on timeline, you get a looping flash file that contains a timeline and everything it comes with.
A little test demonstrate that code was read everytime its frame was played.
<b>SHAPE TWEENS</b> :
Hehe, they work, but these are ugly, yuck ! Stripes appear on shapes, stripes that hollow them. Kinda strange, but that's it. To prevent that bug from happening, you just have to "precompute" (or kinda) the shape tween : you select every frame on the tween and press "F6". This will create keyframes on every frame according to the tween. Then you select all those frames (every "green" frames), right click, and "remove tween".
... oh and interpolation functions work. If you set +100 easing, it will ease the tween at +100, like it should.
<b>LINES AND SHAPES</b> :
They do work, but it's strange they're so aliased. It seems they're rasterized at LOW quality, but they're not. Not exactly. Concerning lines, thickness just doesn't work at all. Though, line styles will work (solid lines, but also dashed lines or stupid ones like ragged lines, etc.)
<b>GRADIENTS</b> :
Didn't check
<b>GRAPHICS</b> :
Didn't completely checked those, but they should work just fine since flash totally trash them when publishing. Every frame inside Graphics is merged with the main timeline. So it's like you've never used any symbol.
But still, I didn't check them :) so...
By the way, rsd, it looks like you've exported every asset you've created in the .fla file's library. It's unnecessary. You only have to do this if you plan on dynamically call and create visual effects (i.e. particules, popup screens, etc.). And even in that case, that's not the only way to do it :)
In our case, you just didn't need to export those movieclips. I checked.
<!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->By the way, rsd, it looks like you've exported every asset you've created in the .fla file's library. It's unnecessary. You only have to do this if you plan on dynamically call and create visual effects (i.e. particules, popup screens, etc.). And even in that case, that's not the only way to do it :)
In our case, you just didn't need to export those movieclips. I checked.<!--QuoteEnd--></div><!--QuoteEEnd-->
I don't have a clue what you're talking about :(
I just hit file -> publish. I know nothing about flash, at all. No clue what you mean by exporting assets.
From where did you took your .fla file ?
And by the way... how can we put our hands on the other .fla files ? do we have to guess their content and create them ourself ?
Like CXZman I am also wondering where you can gather information on what you are able to display on the HUD. From the looks of it its coded in ActionScript 2. And there are some features I would like to try out. CXZman you have done some good research on that. :)
Oh, btw. You can use the "onResize" function instead of "onEnterFrame" if I remember correctly.
<div class='codetop'>CODE</div><div class='codemain' style='height:200px;white-space:pre;overflow:auto'>onResize = function()
{
if (not _root.locationsSet)
{
shpReticle._x = Math.floor(Stage.width / 2);
shpReticle._y = Math.floor(Stage.height / 2);
shpHealth._x = Math.floor(Stage.width - (640 - shpHealth._x));
shpHealth._y = Math.floor(Stage.height - (480 - shpHealth._y));
txtHealth._x = Math.floor(Stage.width - (640 - txtHealth._x));
txtHealth._y = Math.floor(Stage.height - (480 - txtHealth._y));
_root.locationsSet = true;
}
txtHealth.text = lua("PlayerUI_GetHealth");
}</div>
<b>onResize</b> method : just doesn't work.
<b>TEXTFIELDS</b> : I can't get one working. I tried many things, I just can't show any text. Even static textfield !! (which are drawn and kept as vector shapes inside the SWF file). How did you do that rsd ?
<b>MOVIES</b> : that was more of a joke. As you might guess, you can't throw any FLV file in there and expect it to work. And... well, you guessed right.
I also found out strange behavior about flash version. I used to test my SWF files on flash player 8 version, but it seems today it's only working with flash player 6. Dunno what's happening.
1.) Resizing layouts
Since the NS2 has a windowed mode, you DO have to watch each frame for sizing if you want your UI to work correctly.
Set your FLA up as such:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Stage.scaleMode = "noScale";
Stage.align = "TL";<!--c2--></div><!--ec2-->
Then use the Stage.width and Stage.height parameters to size your UI correctly
2.) Text objects
You need to have the font that you are using in the fonts directory. Any font that doesn't ship with NS2 goes in the "fonts" directory in your mod
Do Not Embed Fonts! They are not used!
Font size tops out at ~120 px. Scaling operations don't work on fonts. Rotation operations don't work on fonts.
The autoSize parameter from flash 8 is supported. TextFormatter is NOT supported.
Alpha operations on a parent movieclip, while not effective on text in Flash 6 WILL work in the game.
3.) Publish to Flash 6 using ActionScript 2
AS3 isn't supported, and using anything higher than Flash 6 gets dicey. If you start seeing random XML elements pop up in your text strings, you're publishing too high.
4.) Build a simple lua interface wrapper in your flash project
You can check for the existence of the "lua" object in your code and use fake data while prototyping
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->function ScoreboardUI_GetRedScores() : Array
{
if (undefined == lua)
{
var a:Array = new Array();
for (var i:Number = 0; i < 3; ++i)
{
a.push("name" + String(i));
a.push(i);
a.push(i + 1);
a.push(i + 2);
a.push(i * 80);
}
return a;
}
else
{
return lua("ScoreboardUI_GetRedScores");
}
}<!--c2--></div><!--ec2-->
5.) We added some stuff
Check current mouse button status:
_lbutton, _mbutton, _rbutton
Replace 1st bitmap in object with one defined in lua:
replaceBitmap(name)
Before loading the swf in lua, be sure to use the Client.BindFlashTexture(name, file) command
6.) Don't trust what you see running from Flash itself
Testing your code often in the game can help stop problems early. There are subtle differences in the interpreters, for instance:
number + undefined == number in Flash
number + undefined == undefined in NS2
And:
Flash toStrings undefined string as ""
NS2 toStrings undefined string as "undefined"
The player itself is the open-source gameswf library with some custom additions. It can be painful at times.
Thank you HenryJK for all the intel. :)
Haven't had a chance to do any more coding / poking around for a bit. Need to make some time to get back into it.
Few things I didn't understand :
- When you mention that changing _alpha on a movieclip that has a textfield child, does it mean that if we systematically put textfield in movieclip, we can freely adjust alpha ?
- What do you mean by "TextFormatter is NOT supported" ? Can't we change font/size/color/style at runtime ?
- I actually didn't understand A THING in the fifth part "We added some stuff" :) Could you explain it a little more please ?
For my Galaga mod I want to do something flashy that would require around 30-40 elements. I can duplicate the stuff easily but for future reference just wanted to know if there was a way to spawn an element and designate the size and origin, then be able to destroy it.
ie. textHealth = createHudElem( 256, 256, 0, 0 )
Is there a specific list of API functions for ActionScript NS2?
<ul><li>attachMovie( id :String , instanceName :String , Zlevel :Number)</li><li>createEmptyMovieClip( instanceName :String , Zlevel :Number)</li></ul>
attachMovie is used to call a symbol you've built with Adobe Flash and exported for runtime in the file's library. You can basically create templates or basic assets, name them with an id name, that you feed as first param in attachMovie().
createEmptyMovieClip lets you build an entire visual element from scratch (since it is create empty).
I didn't test them, you might want to check them out.
Yes.
<!--quoteo(post=1768655:date=Apr 25 2010, 12:18 PM:name=CXZman)--><div class='quotetop'>QUOTE (CXZman @ Apr 25 2010, 12:18 PM) <a href="index.php?act=findpost&pid=1768655"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->- What do you mean by "TextFormatter is NOT supported" ? Can't we change font/size/color/style at runtime ?<!--QuoteEnd--></div><!--QuoteEEnd-->
You can change color via the textColor = 0xRRGGBB method, but font/size and color can't be changed at runtime currently.
<!--quoteo(post=1768655:date=Apr 25 2010, 12:18 PM:name=CXZman)--><div class='quotetop'>QUOTE (CXZman @ Apr 25 2010, 12:18 PM) <a href="index.php?act=findpost&pid=1768655"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->- I actually didn't understand A THING in the fifth part "We added some stuff" :) Could you explain it a little more please ?<!--QuoteEnd--></div><!--QuoteEEnd-->
1.) _lbutton, _rbutton, and _mbutton return the up or down status of the user's mouse buttons
2.) replaceBitmap(name)
Take an MC, put a placeholder bitmap in it. In the same mc add another layer and write:
replaceBitmap("blah");
This will go out to lua and replace the instance of that bitmap with whatever you've defined as "blah" with the lua command
Client.BindFlashTexture("blah", "iamafile.png")
This is the kind of thing you need for any content like maps, which you generally don't/will never have when you're creating the swf.
For my Galaga mod I want to do something flashy that would require around 30-40 elements. I can duplicate the stuff easily but for future reference just wanted to know if there was a way to spawn an element and designate the size and origin, then be able to destroy it.
ie. textHealth = createHudElem( 256, 256, 0, 0 )
Is there a specific list of API functions for ActionScript NS2?<!--QuoteEnd--></div><!--QuoteEEnd-->
Largely anything you can do in Flash v6 is supported.
The <a href="http://www.adobe.com/support/flash/action_scripts/actionscript_dictionary/" target="_blank">Actionscript Dictionary</a> may be of help to you.
<!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->1.) _lbutton, _rbutton, and _mbutton return the up or down status of the user's mouse buttons<!--QuoteEnd--></div><!--QuoteEEnd-->
I figured that out :) I guess these properties returns true or false(or maybe "up" "down") if that button is pressed or not... but what are the classes involved in there ?
Stage ? MovieClip ? Mouse ? or are they global properties ?
<!--quoteo--><div class='quotetop'>QUOTE </div><div class='quotemain'><!--quotec-->2.) replaceBitmap(name)
Take an MC, put a placeholder bitmap in it. In the same mc add another layer and write:
replaceBitmap("blah");
This will go out to lua and replace the instance of that bitmap with whatever you've defined as "blah" with the lua command
Client.BindFlashTexture("blah", "iamafile.png")<!--QuoteEnd--></div><!--QuoteEEnd-->
Oh man :) is that the only way to dynamically import bitmaps into flash ? Like in "bye bye mister loadMovie()" ? :(
2.) Right now, yes.
Anyone know why HTML formatting would show with strings entered on the text box?
<img src="http://img139.imageshack.us/img139/9366/ns2ingameflashtextforma.jpg" border="0" class="linked-image" />