How do I get the hexadecimal value from a Color object in Actionscript 3.0? - actionscript-3

So I am making a music visualizer and I am trying to set the linestyle for my graphics to be a pre defined color! But I get an error when trying
var lineColor:Color = new Color(120,120,12);
graphics.lineStyle(lineThickness, lineColor);
1067: Implicit coercion of a value of type fl.motion:Color to an unrelated type uint.
So then I tried
var lineColor:Color = new Color(120,120,12);
graphics.lineStyle(lineThickness, lineColor.color);
But lineColor.color always returns 0! What do I do? I can't believe there is no built in API to take a color object and make it a compatible hexadecimal uint for graphics!
Any help would be much apprectiated!

Just use a method to return the hex value.
function get_uint_from_colour(red:int, green:int, blue:int) {
return red << 16 | green << 8 | blue;
}
So in your example:
graphics.lineStyle(lineThickness, get_uint_from_colour(120, 120, 12));
In response to your comment about needing to use a set of pre-defined Color objects, you will still need to (at some point) convert them to the type uint as this is the accepted data-type for the lineStyle method.
My suggestion would be to adjust the get_uint_from_colour method to accept a Color object. Like so:
function get_uint_from_colour(colour:Color) {
return int(colour.redMultiplier) << 16 | int(colour.greenMultiplier) << 8 | int(colour.blueMultiplier);
}
So in your code:
graphics.lineStyle(lineThickness, get_uint_from_colour(lineColor));
Please note that I have changed the name of my original method as I felt it better describes the function
Also, keep in mind that a Color object can hold much more information about itself than a standard Hex colour can - this superfluous information will be lost in the process of converting it.

Related

as3 add multiple MovieClips into random MovieClips

I'm trying to to do some dynamic MovieClips placement here. I've been trying for a couple'o days and I can't find the right way to do the trick. It's the continuation for this. I didn't manage to properly make my MC's appear in the triangle, so I've made a pyramid of rectangles (suits my case better, beacuse I can change each of'em, to better fit my desired shape - a not-so-regular triangle).
Here's the code with some comments:
import flash.events.MouseEvent;
import flash.display.MovieClip;
btn_toys_2.confirm.addEventListener(MouseEvent.MOUSE_UP, confirmToys);
var toysPlc:Array = new Array(); //an array for a bunch of rectangles
var toAdd:int = 100 //this is supposed to be dynamic, user defined
var toy:MovieClip = new shar_001; //an MC from a library
for (var j:int=0; j<33; j++){
toysPlc.push("tPl_" + j); //here I add that bunch of rects into an array
}
function confirmToys(e:MouseEvent):void{
for (var k:int=0; k<toAdd; k++){ //supposed to add an "toAdd" amount of "toys"
var p:int = Math.random()*toysPlc.length; //^do so in a random rect
toysPlc[p].addChild(toy); //supposed to place a toy in a random rect
toy.x = Math.random()*toysPlc[p].width; //positioning
toy.y = Math.random()*toysPlc[p].height; //positioning
}
}
The error I get is: TypeError: Error #1006: value is not a function.
What I DID manage is to place a single toy in a random of these rects, tho I don't remember how :)
Thanks in advance!
EDIT: null asked me to clarify the case, so here's the whole picture:
I've got:
- triangle-like MC (since a triangle MC is a rectangle for flash anyway, I've solved this by creating a pyramid of 33 rectangles, layered on each other);
- toys (multiple frames to change whenever I need to);
- text field (to input the quantity of desired toys);
- confirm button (to make the magic happen once clicked);
Now I need a user to input a 3-digit number in the input field, press "confirm", and 0.4 of that quantity is supposed to appear in the "triangle-like MC".
For example: user inputs a number: 600, the end value is 600*0.4=240. Now 240 "toys" are randomly spreaded between my 33 rectangles, within their width (which is different for every single one).
Hope that explains a bit more.
A simplified sample of what I need here.
Is there a way to fill an array with MovieClips rather than String values? That would be THE answer to this question here.
There is in fact more than one way:
Place all the instance names into the Array when you create it:
var rectangles:Array = [instanceName1, instanceName2];
there are no quotation marks, which create string literals. Just the names.
This approach quickly becomes impractical for large numbers of objects.
Given that the instance names have a number component, iterate through the names in conjunction with getChildByName(). I assume that this is what you were trying with in your question:
var rectangles:Array = []; // initialise empty array
for (var j:int=0; j<33; j++){
rectangles.push(getChildByName("tPl_" + j));
}
original answer
toysPlc.push("tPl_" + j); //here I add that bunch of rects into an array
No you don't. You are filling the Array with String objects. It's totally unrelated to any rectangle whatsoever.
Now this next line, tries to call a function on each String, which fails.
toysPlc[p].addChild(toy);
The above is equivalent to
"tPl_0".addChild(toy);
"tPl_1".addChild(toy);
// etc.
A String doesn't have that method addChild.

Getting an Int in another frame ActionScript 3.0

I am currently working on a casino game (for my school) but I am encountering a problem:
var a:int //this part is in frame 1
a = 10000
money.text = ""+a //this part is working
//this part is in another frame
lost_BTN.addEventListener(MouseEvent.CLICK, lost)
function lost (e:MouseEvent)
{
cash.text = ""+a -=50 //*1 (please see below)
}
*1) Scene 1, Layer 'Layer 1', Frame 6, Line 36 1050: Cannot assign to a non-reference value.
*1) Scene 1, Layer 'Layer 1', Frame 6, Line 36 1067: Implicit coercion of a value of type String to an unrelated type Number.
*1) Scene 1, Layer 'Layer 1', Frame 6, Line 36 1067: Implicit coercion of a value of type Number to an unrelated type String.
I cant seem to get the information out of 'a' in another frame.
It's because your doing some calculation with a in frame 6 where you want to place the text. You should tell Flash that a -= 50 should be interpreted as a String and you'll be good to go. If you change your code to this, it'll work:
function lost (e:MouseEvent)
{
cash.text = String(a -=50);
}
As #rvmook mentions in his answer and #SeRPRo in the comment. Your error is about operator precedence. That is, the order in which operations are happening. In your example, the addition of the empty string and the value of a are happening before the intended subtraction-assignment of 50 from a. The result is that you are trying to subtract the integer 50 from a string containing the string representation of the value of a.
A slight re-work of your code will make it work fine, either with the string cast as #rvmook suggests or by performing the calculation first and then assigning the string representation.
function lost (e:MouseEvent)
{
a -= 50;
lost.text = a.toString();
}
Remember that computers are dumb and need t be told exactly what to do.

translating hex values from ByteArray in AS3

I'm new to using ByteArray, and am trying to parse hex color values from an .ase (Adobe Swatch Exchange) using ByteArray in AS3. I can see position of the hex values using a hex editor, but don't know which methods to use to parse the hex value from there. Here are the values copied from the hex editor. The 2 color values are #ffffff and #cdcdcd:
ASEF........¿..........$...#.f.f.f.f.f.f..RGB.?Ä..?Ä..?Ä....¿..........$...#.c.d.0.0.c.d..RGB.?MÕŒ....?MÕŒ
I've made a weak initial attempt to get the first color, but am stuck here :
var byteA:ByteArray = _fr.data;
byteA.position=29;
var tb:ByteArray = new ByteArray()
var tA:Array= new Array(); //temp array
byteA.readBytes(tb,0,11);
trace("TB "+ tb[0]+":" +tb.toString())
Can somebody please show me how to parse out the color value, so it can be added to the temp array tA? As a bonus answer, since there can be multiple colors in a swatch, advice on a method to parse out all colors in a given .ase file would be greatly appreciated. Thanks in advance for helping me through this!
The ASEF defines colors using RGB, assuming each color is 8 bits (called a byte). That's 24 bits of information. Unfortunately, Flash's ByteArray doesn't have a method that reads just 24 bits. So, we'll read each byte individually and combine them later.
var byteArray:ByteArray = _fr.data;
//Skip past the garbage that isn't the color.
for (var index:int = 0; index < numberOfBytesUntilFirstColor)
{
byteArray.readByte();
}
var redValue:int = byteArray.readByte();
var greenValue:int = byteArray.readByte();
var blueValue:int = byteArray.readByte();
I'll let you calculate numberOfBytesUntilFirstColor as I'm not familiar with ASE file format.
If you want to store the value as an RGB integer, usable by Flash, do this:
var color:int = redValue;
color = color << 8;
color = color | greenValue;
color = color << 8;
color = color | blueValue;
The above code combines the individual color bytes into one 32 bit int (note, the high 8 bits are left as 0. Sometimes Flash uses the high 8 bits for the alpha, sometimes not.)

Passing Vector.<T> references as Object, casting causes a copy to be made

I'd like to be able to pass Vectors around as references. Now, if a method takes a Vector.<Object>, then passing a Vector.<TRecord>, where TRecord inherits directly from Object does not work. Where a method takes just plain Object; say vec: Object, then passing the Vector is possible. Once inside this method, an explicit cast at some stage is required to access vec as a Vector again. Unfortunately, a cast seems to make a copy, which means wrapping one up in multiple Flex ListCollectionViews is useless; each ListCollectionView will be pointing to a different Vector.
Using Arrays with ArrayCollection presents no such problem, but I lose out out the type safety, neatness (code should be clean enough to eat off of) and performance advantages of Vector.
Is there a way to cast them or pass them as references in a generic manner without copies being made along the way?
Note in this example, IRecord is an interface with {r/w id: int & name: String} properties, but it could be a class, say TRecord { id: int; name: String} or any other usable type.
protected function check(srcVec: Object): void
{
if (!srcVec) {
trace("srcVec is null!");
return;
}
// srcVec = (#b347e21)
trace(srcVec.length); // 4, as expected
var refVec: Vector.<Object> = Vector.<Object>(srcVec);
// refVec = (#bc781f1)
trace(refVec.length); // 4, ok, but refVec has a different address than srcVec
refVec.pop();
trace(refVec.length); // 3 ok
trace(srcVec.length); // 4 - A copy was clearly created!!!
}
protected function test(): void
{
var vt1: Vector.<IRecord> = new Vector.<IRecord>; // (#b347e21) - original Vector address
var vt2: Vector.<Object> = Vector.<Object>(vt1); // (#bbb57c1) - wrong
var vt3: Vector.<Object> = vt1 as Vector.<Object>; // (#null) - failure to cast
var vt4: Object = vt1; // (#b347e21) - good
for (var ix: int = 0; ix < 4; ix++)
vt1.push(new TRecord);
if (vt1) trace(vt1.length); // 4, as expected
if (vt2) trace(vt2.length); // 0
if (vt3) trace(vt3.length); // vt3 is null
if (vt4) trace(vt4.length); // 4
if (vt1) trace(Vector.<Object>(vt1).length); //
trace("calling check(vt1)");
check(vt1);
}
This is not possible. If a type T is covariant with type U, then any container of T is not covariant with a container of type U. C# and Java did this with the built-in array types, and their designers wish they could go back and cut it out.
Consider, if this code was legal
var vt1: Vector.<IRecord> = new Vector.<IRecord>;
var vt3: Vector.<Object> = vt1 as Vector.<Object>;
Now we have a Vector.<Object>. But wait- if we have a container of Objects, then surely we can stick an Object in it- right?
vt3.push(new Object());
But wait- because it's actually an instance of Vector.<IRecord>, you can't do this, even though the contract of Vector.<Object> clearly says that you can insert Object. That's why this behaviour is explicitly not allowable.
Edit: Of course, your framework may allow for it to become a non-mutable reference to such, which is safe. But I have little experience with ActionScript and cannot verify that it actually does.

Segfault Copy Constructor

My code is as follows:
void Scene::copy(Scene const & source)
{
maxnum=source.maxnum;
imagelist = new Image*[maxnum];
for(int i=0; i<maxnum; i++)
{
if(source.imagelist[i] != NULL)
{
imagelist[i] = new Image;
imagelist[i]->xcoord = source.imagelist[i]->xcoord;
imagelist[i]->ycoord = source.imagelist[i]->ycoord;
(*imagelist[i])=(*source.imagelist[i]);
}
else
{
imagelist[i] = NULL;
}
}
}
A little background: The Scene class has a private int called maxnum and an dynamically allocated Array of Image pointers upon construction. These pointers point to images. The copy constructor attempts to make a deep copy of all of the images in the array. Somehow I'm getting a Segfault, but I don't see how I would be accessing an array out of bounds.
Anyone see something wrong?
I'm new to C++, so its probably something obvious.
Thanks,
I would suggest that maxnum (and maybe imagelist) become a private data member and implement const getMaxnum() and setMaxnum() methods. But I doubt that is the cause of any segfault the way you described this.
I would try removing that const before your reference and implement const public methods to extract data. It probably compiles since it is just a reference. Also, I would try switching to a pointer instead of pass by reference.
Alternatively, you can create a separate Scene class object and pass the Image type data as an array pointer. And I don't think you can declare Image *imagelist[value];.
void Scene::copy(Image *sourceimagelist, int sourcemaxnum) {
maxnum=sourcemaxnum;
imagelist=new Image[maxnum];
//...
imagelist[i].xcoord = sourceimagelist[i].xcoord;
imagelist[i].ycoord = sourceimagelist[i].ycoord;
//...
}
//...
Scene a,b;
//...
b.Copy(a.imagelist,a.maxnum);
If the source Image had maxnum set higher than the actual number of items in its imagelist, then the loop would run past the end of the source.imagelist array. Maybe maxnum is getting initialized to the value one while the array starts out empty (or maxnum might not be getting initalized at all), or maybe if you have a Scene::remove_image() function, it might have removed an imagelist entry without decrementing maxnum. I'd suggest using an std::vector rather than a raw array. The vector will keep track of its own size, so your for loop would be:
for(int i=0; i<source.imagelist.size(); i++)
and it would only access as many items as the source vector held. Another possible explanation for the crash is that one of your pointers in source.imagelist belongs to an Image that was deleted, but the pointer was never set to NULL and is now a dangling pointer.
delete source.imagelist[4];
...
... // If source.imagelist[4] wasn't set to NULL or removed from the array,
... // then we'll have trouble later.
...
for(int i=0; i<maxnum; i++)
{
if (source.imagelist[i] != NULL) // This evaluates to true even when i == 4
{
// When i == 4, we're reading the xcoord member from an Image
// object that no longer exists.
imagelist[i]->xcoord = source.imagelist[i]->xcoord;
That last line will access memory that it shouldn't. Maybe the object still happens to exist in memory because it hasn't gotten overwritten yet, or maybe it has been overwritten and you'll retrieve an invalid xcoord value. If you're lucky, though, then your program will simply crash. If you're dealing directly with new and delete, make sure that you set a pointer to NULL after you delete it so that you don't have a dangling pointer. That doesn't prevent this problem if you're holding a copy of the pointer somewhere, though, in which case the second copy isn't going to get set to NULL when you delete-and-NULL the first copy. If you later try to access the second copy of the pointer, you'll have no way of knowing that it's no longer pointing to a valid object.
It's much safer to use a smart pointer class and let that deal with memory management for you. There's a smart pointer in the standard C++ library called std::auto_ptr, but it has strange semantics and can't be used in C++ containers, such as std::vector. If you have the Boost libraries installed, though, then I'd suggest replacing your raw pointers with a boost::shared_ptr.