Setting an movieclips image/background - actionscript-3

I have a button and a small area which is a movieclip.
What i need is, on button press it inserts an image into the movieClip, it would have to be docked into the whole movieclip area essentially.
I have looked through multiple posts yet they have an overwhelming amount of information that I cannot figure out, this is so far what i have done :
B_Background1.addEventListener(MouseEvent.CLICK, setBackground1);
function setBackground1(event:MouseEvent):void{
var firstPic:MovieClip = new C_1BackgroundPIC();
addChildAt(firstPic, C_MainStage);
}
As I understand it, it adds an event to the button, then in the function it creates a new movieClip instance which has the Picture inside of it, and then adds it to the "MainStage" although using C_MainStage is invalid thus doesn't work, it does add a picture if i just use 0 as the position but it then adds it to the position 0, which i dont want...

It's a good start. When you use addChildAt, it expects a number as the second parameter. Presumably, C_MainStage is your MovieClip (which isn't a number). Presumably you want the current display index of C_MainStage (not C_MainStage itself). This can be had by using getChildIndex
Look at the following:
function setBackground1(event:MouseEvent):void{
var firstPic:MovieClip = new C_1BackgroundPIC();
addChildAt(firstPic, getChildIndex(C_MainStage));
//now, you may need to also resize your picture so it fits in the bounds of C_MainStage, if so, you can do something like this:
if(firstPic.width >= firstPic.height){
//if firstPic is wider than it is tall
//set it's width to the same as C_MainStage
firstPic.width = C_MainStage.width;
//now, to keep the aspect ratio (in case they don't match), make the scaleY the same value as the new scaleX
firstPic.scaleY = firstPic.scaleX
}else{
//do the opposite as above since the height is larger than the width
firstPic.height = C_MainStage.height;
firstPic.scaleX = firstPic.scaleY;
}
//now, you may want to center firstPic in the C_MainStage bounds
firstPic.x = C_MainStage.x + ((C_MainStage.width - firstPic.width) * .5);
firstPic.y = C_MainStage.y + ((C_MainStage.height - firstPic.height) * .5)
}

Related

Send all instances of a container BEHIND everything else?

Found this topic: AS3 setChildIndex to front I'm trying to accomplish the exact opposite.
"addChildAt" doesn't work for me when I'm setting the container behind everything else or something along the lines. And as for stars themselves, I can't send them back anymore than layer 0 for some odd reason (it'll give me error 2006, stating "The supplied index is out of bounds"). Here's the code:
starsSpawn function:
var starContainer:MovieClip = new MovieClip();
addChildAt(starContainer, 20);
starContainer code:
function starsSpawn()
{
for(var i:int= 0; i < 30; i++)
{
var newStar = new starCode();
var scaleXY = Math.random()*(2)+0.1;
newStar.width = scaleXY;
newStar.height = scaleXY;
var positionX:Number = Math.random()*(stage.stageWidth + (1* newStar.width));
var randomY:Number = Math.random()*(stage.stageHeight - newStar.height);
newStar.x = positionX;
newStar.y = randomY;
starContainer.addChild(newStar);
}
}
Essentially how it works is that a container is set up and the for loop creates 30 stars, each with the outlined code.
When you addChildAt(myChildMC, 0); it gets added at index 0 and everything else gets bumped up. Z order indexes in AS3 are contiguous, meaning every space from zero to the highest z order must be filled. If I remove whatever is on layer 4, layer 5 will slide down to fill, and so on
And I don't think you can add something to index 20 unless all the other indexes have children in them. That may be what is causing your particular error. To add something to the top level just do addChild(myChild).
edit
Since it sounds like you have the concept of how z-order works in reverse in your mind, you probably are wanting to have the stars "in front" of everything else i.e. Always on top i.e. Always visible. To do that just do addChild(starsContainer) after all the other containers are added or Sprites or MovieClips. If you add something to the stage at runtime, just add the stars container again (this won't create a second container, it literally just changes the z-order if there is already a container by that name... this is an often misunderstood point).

in Flex/AS3 how can I highlight a datagrid row?

I am writing an application, using a datagrid. Various rows are differing colors based on the data. When the user selects a row the color becomes a few shades lighter.
Unfortunately one of the users doesn't think it is enough of a contrast and would like a more noticeable visual indicator. My two thoughts are to either;
A) Draw a rectangle around the entire row selected.
B) Add a column with an image that I hide or make visible based on whether the row is selected.
I went down path A. for a while and got to the point where in the function;
override protected function drawHighlightIndicator
I was able to identify when I was looking at the specific row, but I couldn't determine how to draw the rectangle.
So I backtracked and looked into B. I am able to create an Item renderer with an arrow, but I can't figure out how to turn it on & off when selected. I have a click event in the main module, but no way to reference back to the Item renderer component.
I could set a value in the array collection, and do a refresh, which will probably work, but that tends to move the selected row to the top of the datagrid display area.
So if anyone can help I on A or B would appreciate it. This is a DataGrid, not an AdvancedDataGrid.
Since you're using mx.controls.DataGrid, overriding drawHighlightIndicator could look like following example, which draws 1px red border around selection marker:
protected function drawHighlightIndicator(
indicator:Sprite, x:Number, y:Number,
width:Number, height:Number, color:uint,
itemRenderer:IListItemRenderer):void
{
var width:int = unscaledWidth - viewMetrics.left - viewMetrics.right;
var borderColor:uint = 0xff0000;
var g:Graphics = Sprite(indicator).graphics;
g.clear();
g.beginFill(borderColor);
g.drawRect(0, 0, width, height);
g.beginFill(color);
g.drawRect(1, 1, width - 2, height - 2);
g.endFill();
indicator.x = x;
indicator.y = y;
}

AS3 Clicking in "zones" of a picture

I have searched and simply cannot find what I need (if it exists).
A window will have a large picture.
The picture will be divided into zones (such as border lines that separate states on a map).
When a person clicks within a zone, then I will raise the appropriate event.
I've used AS3 with MXML to create a database program. All is working great except for this last step. I cannot figure out how the user is within a particular area of the picture when he clicks or when he touches.
I've read and tried to come up with an approach, and there must be (hopefully so) an easier way than the muddled nonsense I'm coming up with.
Thanks
VL
Are you drawing it in flash professional CS6? If so then why can't you just have the picture as a symbol and then just self divide the lines and make those divided areas into symbols that are children of the picture symbol. You could keep the individual state symbols right where they so that they stay true to the overall picture.
A first thought would be to make an instance of this picture symbol through the code, and then loop though all the children of that picture and add a click event to each one.
var picture:Picture=new Picture();
for(var i:int=0; i<picture.numChildren-1; i++){
picture.getChildAt(i).addEventListener(MouseEvent.CLICK, mouseEventHandler);
}
Please comment if I am missing something, or this does not work.
EDIT
Well, if you know the dimensions of the image, you could divide its width and height by 3(your number of rows and columns) and this is your zone dimensions. You then could take the mouse's click point relative to the top left of your picture and then divide its width by the zone with, and its height by the zone height, and then get its integer floor value, you could get which region it is. Code it below:
//This is all for a constat region list (like a window, or floor tiles, not things irregular)
import flash.display.Sprite;
var regionsX:int = 3; //Your number of windows across the row
var regionsY:int = 3; // across the column
var regions:Array = new Array(); // an array to hold the values that you will get from where the user clicks
// All of this used a 2D array method
for(var x:int = 0; x < regionX; x++) {
regions[regionsX] = new Array();
for(var y:int = 0; y < regionY; y++) {
regions[regionsX][regionsY] = "region(".concat(x).concat(",").concat(y);
// Here you make this equal to anything you want to get a value of,
//once the correct region is found (I just have a string version here for an example)
}
}
... // other stuff..
var picture:Picture = new Picture(); // your window picture
var regionWidth:Number = picture.width / regionsX; // Gets each region's width
var regionHeight:Number = picture.height / regionsY; // Get each regoin's height
...
picture.addEventListener(MouseEvent.CLICK, mouseEventListener); // add a click listener to the picture
function mouseEventListener(event:MouseEvent):void{
var mouseX:Number = picture.globalToLocal(event.stageX); // gets where the user clicked, and then converts it
//to the picture's cordinate space. ( 50,100 acording to the stage, could be (25,200) to the picture)
var mouseY:Number = picture.globalToLocal(event.stageY); // same for the Y
var regionIntX:Number = Math.floor(mouseX / regionWidth); // Dives the point by each region's width, and then
// converts it to a while integer. (For instance, if a region's width is 100 and you click at 288, then if you do the
// math, you clicked in the 3rd region, but it returns 2... why? (becaue the array counter starts at 0, so 0 is the 1st
// region, 1 is the second and so on...
var regionIntY:Number = Math.floor(mouseY / regionHeight); // Same for Y
var yourValue:String = regions[regionIntX][regionIntY]; // This returns that you initialy put into your 2d array
// by using the regionIntX and regionIntY for the array values. You have to decide what is stored in this array...
}
The simplest solution would be to add an event listener for MouseEvent.CLICK to the picture and in the handler check properties mouseX and mouseY of the picture. Define the bounds of each area in an XML or similar and check against current mouseX/Y to see which area has been clicked.

Loop an image in Flash

I want to have a scene where an image which is 5000 pixels high is moving up 5 pixels each frame-refresh. When the image is all up, I'd like to see the top of the image connected to the bottom of the image. This should be done untill the level is 'done'. How can I 'loop' such an Image?
You can create a copy of that image which you keep hidden/above and the trick is to update the position and loop accordingly so when one image goes bellow the screen it goes back on top and repeats.
Here's a basic snippet to illustrate the idea using the DisplayObject class and the scrollRect property:
//ignore this, you have your content already
var dummyContent:BitmapData = new BitmapData(100,100,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//important stuff starts here
var container:Sprite = addChild(new Sprite()) as Sprite;//make a container
container.scrollRect = new Rectangle(0,0,dummyContent.width,dummyContent.height);//set a scrollRect/'mask'
var part1:DisplayObject = container.addChild(new Bitmap(dummyContent));//add two copies
var part2:DisplayObject = container.addChild(new Bitmap(dummyContent));//of the same content
part2.y -= part2.height;//set the 2nd at the top of the 1st
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
//move both
part1.y += 5;
part2.y += 5;
//check if any reach the bottom so they can be moved back up
if(part1.y >= part1.height) part1.y = -part1.height;
if(part2.y >= part2.height) part2.y = -part2.height;
//the above can also be nicely placed in a loop if you plan on using more seamless looping clips/images
}
Obviously you will have different content, but the principle is the same.
If you're working with images, you can simply use BitmapData's copyPixels method:
var s:int = 5;//scroll speed
//make some content
var w:int = 100;
var h:int = 100;
var dummyContent:BitmapData = new BitmapData(w,h,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//prepare for stiching
var renderPos:Point = new Point();//position to render the current image to
var prenderPos:Point = new Point();//position to render the previous image (the 'hidden' copy above)
var render:BitmapData = new BitmapData(w,h,false);//create a bitmap data instance to render updated pixels int
addChild(new Bitmap(render));//and add it to the stage
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
renderPos.y = (renderPos.y+s)%h;//update the scroll position for the 1st part, % is used to loop back to 0 when the position gets to the content height
prenderPos.y = renderPos.y - h;//update the scroll position for the 2nd part (above)
render.lock();//freeze pixel updates
render.copyPixels(dummyContent,dummyContent.rect,renderPos);//copy pixels from the scroll position to the bottom
render.copyPixels(dummyContent,dummyContent.rect,prenderPos);//copy pixels from the top to the scroll position
render.unlock();//unfreeze/update ALL THE PIXELS
}
You can try to use a Rectangle object which changes height (height-scrollPosition) so you potentially access less pixels each time or you can manually work out single for loops using BitmapData's getVector method, but that's something to look into if performance is actually an issue for such a simple task and it's worth checking what's faster ( copy full bitmap rect vs copy partial bitmap rect vs manually copy values using vector )
Be warned, Flash cannot load an image greater than 16,769,025 pixels (or 4095x4095). The height of 5000 pixels will work as long as the width is not greater than 3353.
That said, I'd loop the image by keeping two copies of the image onstage, move both at the same time with a parent object, and reset to origin once your loop point is met.
Consider the following stage setup:
Stage ¬
0: MainTimeline:MovieClip ¬
0: Container:MovieClip ¬
0: img1:Bitmap
1: img2:Bitmap
Now moving container up, you'd just need to check that the looping second image reaches the origin point of the first image.
function onEnterFrame(e:Event):void {
Container.y = Container.y - 5;
if (Container.y < -5000) {
Container.y = -5;
}
}

Setting multiple depth layers in AS3

I get how to set depth in as3 - but with as2 i could begin multiple 'depth points' using numbers - where in as3 all i can seem to do is set this object to a higher/lower depth than that object. The problem is (when dealing with a stack of isometric boxes, which can be placed by the user on a grid in any order) i don't want to deal with the added complexity of having every element know where every other element is, then adjust appropriately.
What I'm trying to do is set up 6 total depth numbers/positions, one for each column in a 6 x 6 grid. So anything in column 1 will begin it's depth placement at say 500, anything in column 2 will begin its depth at 1000, column 3 would be 1500 and so on.
That way, the second i place an object on a particular column, it would tuck itself under, or place itself above all surrounding items in other columns, this to me is much much easier than somehow figuring out where 15 different sized boxes are, how they relate to one another, then figure out what depth order they need to go in.
Any ideas? as3 seems to have removed the ability to set a depth to a specific number :p
The approach can be simplified. You basically want to create 3 'container' clips and add them in order. The last one added is the top-most.
Bonus: if you want to rearrange, you can call addChild() on any clip (even already added ones) and that one will go to the top.
//// IMPORTANT STUFF ////
import flash.display.Sprite;
var top:Sprite = new Sprite;
var mid:Sprite = new Sprite;
var bot:Sprite = new Sprite;
addChild(bot);
addChild(mid);
addChild(top);
//// END IMPORTANT STUFF ////
// Move Stuff so we can visualize how this works.
// Then add some boxes so we can see what's going on.
mid.x = 20;
mid.y = 20;
bot.x = 40;
bot.y = 40;
// Add Top box
var t:Sprite = new Sprite;
t.graphics.beginFill(0xFF0000);
t.graphics.drawRect(0,0,100,100);
top.addChild(t);
// Add Middle box
var m:Sprite = new Sprite;
m.graphics.beginFill(0x00FF00);
m.graphics.drawRect(0,0,100,100);
mid.addChild(m);
// Add Bottom box
var b:Sprite = new Sprite;
b.graphics.beginFill(0x0000FF);
b.graphics.drawRect(0,0,100,100);
bot.addChild(b);