actionscript issue adding shape to container - actionscript-3

I don't know how to describe this problem but I will try to be clear enought. I am doing an actionscript exercise where I have a DisplayObjetct Container defined as Sprite, and what I want is to add ramdomizely circles with a random radio length between 50 and 100.
The Container called "gameZoneContainer_sp" has been added to the displaylist in the Main class, and everytime the user change the size of the stage the container set its new values of width and height.
Here is the code of what i am saying:
private function refreshScreen(ev:Event= null ):void{
// Remember: we can know stage dimensions accessing to:
// stage.stageWidth
// stage.stageHeight
//CONSTANTS DEFINITION OF MARGIN
const margen:Number=25;
//LOCAL VARIABLES DEFINITION
var cercleWidth:Number, cercleHeight:Number;
var invaderWidth:Number, invaderHeight:Number;
var containerWidth:Number, containerHeight:Number;
var logoWidth:Number, logoHeight:Number;
//STORING DIMENSIONS
cercleWidth=addCercle_bt.width;
cercleHeight=addCercle_bt.height;
invaderWidth=addInvader_bt.width;
invaderHeight=addInvader_bt.height;
containerWidth=gameZoneContainer_sp.width;
containerHeight=gameZoneContainer_sp.height;
logoWidth=logoUOC_sp.width;
logoHeight=logoUOC_sp.height;
//SET HORIZONTAL POSITION OF THE ELEMENTS
addCercle_bt.x=(stage.stageWidth/2)+margen;
addInvader_bt.x=(stage.stageWidth/2)-(invaderWidth+margen);
gameZoneContainer_sp.x=margen;
logoUOC_sp.x=stage.stageWidth-(logoWidth+margen);
//SET VERTICAL POSITION OF THE ELEMENTS
addCercle_bt.y=stage.stageHeight - (cercleHeight+margen);
addInvader_bt.y=stage.stageHeight-(invaderHeight+margen);
gameZoneContainer_sp.y=logoHeight+margen*2;
logoUOC_sp.y=margen;
//SET DIMENSIONS OF CONTAINER gameZoneContainer_sp
gameZoneContainer_sp.width=stage.stageWidth-(margen*2);
gameZoneContainer_sp.height=stage.stageHeight-(margen*4)-invaderHeight-logoHeight;
}
/* THIS METHOD ADD A CIRCLE TO THE CONTAINER gameZoneContainer_sp */
private function addCercle(ev:MouseEvent):void {
// Create new instance of Cercle
// and add it to gameZoneContainer_sp
//CONSTANT DEFINITIONS
const minRadio:Number=50, maxRadio:Number=100;
//LOCAL VARIABLES DEFINITIONS OF RADIO, COLOR AND CIRCLE
//THE RADIO CHOOSE A RANDOM VALUE BETWEEN 50 AND 100
var radio:Number=minRadio+(maxRadio-minRadio)*Math.random();
var color:uint=Math.random() * 0xFFFFFF;
var cercle:Cercle=new Cercle(color,radio);
//
var minPosX:Number=radio;
var maxPosX:Number=gameZoneContainer_sp.width/2;
var minPosY:Number=radio;
var maxPosY:Number=gameZoneContainer_sp.height-(minPosY);
// SET POSITION OF THE CIRCULE INSIDE THE CONTAINER
cercle.x= minPosX + (maxPosX-(2*minPosX))*Math.random();
cercle.y= minPosY + (maxPosY-(2*minPosY))*Math.random();
cercle.drawCercle();
gameZoneContainer_sp.addChild(cercle);
refreshScreen(ev);
//TRACING RESULTS...
trace ("Added cercle!");
trace ("alto del contenedor: "+gameZoneContainer_sp.height);
trace ("Posicion x: "+cercle.x);
trace ("radio: "+radio);
}
//DEFINITION OF THE CIRCLE CLASS
public class Cercle extends Sprite {
private var _color:uint;
private var _radio:Number;
public function Cercle(color:uint,radio:Number){
super();
/* THE CLASS ACCEPT HEX VALUES.*/
_color= color;
_radio=radio;
init();
}
public function init():void{
drawCercle ();
}
//METHOD TO DRAW A CIRCLE
public function drawCercle():void{
var circle:Shape=new Shape();
circle.graphics.beginFill(_color,1);
circle.graphics.drawCircle(0,0,_radio);
addChild(circle);
}
}
Here is my problem:
When I add a circle it seems to be fine until I change the dimensions of the windows (the scene). Everytime I update the dimensions, the event execute the method refreshScreen from the main class which update the dimensions and positions of all elements in scene, but after that if i add a new circle, it change the container, and that is wrong because what I want is to add the circle IN the container.
Hope is not too long. Please any help would be great!
Thank you in advance!!
************ HERE GOES THE SOLUTION ********************
//METHOD TO ADD A CIRCLE TO THE CONTAINER
private function addCercle(ev:MouseEvent):void {
// Create new instance of Cercle
// and add it to gameZoneContainer_sp
const minRadio:Number=50, maxRadio:Number=100;
var radio:Number=minRadio+(maxRadio-minRadio)*Math.random();
var color:uint=Math.random() * 0xFFFFFF;
// CHANGES///////
// gameZoneContainer_sp IS 400X400 ORIGINALLY AND WE WANT TO PUT AN INSTANCE OF CIRCLE OBJETCT
// cercle.x WILL PLACE IN minPosX = radio y maxPosy = 400 - radio
// TAKING INTO ACCOUNT THAT ITS RADIO IS cercle.width/2
// cercle.x WILL PLACE IN minPosX = cercle.width/2 y maxPosy = 400 - cercle.width/2
// (SAME FOR y)
var cercle:Cercle=new Cercle(color,radio);
// Cercle scale correction
//cercle.width= radio/(gameZoneContainer_sp.width/400);
//cercle.height= radio/(gameZoneContainer_sp.height/400);
// Cercle positionning
cercle.x = cercle.width/2 + ((400-cercle.width)*Math.random());
cercle.y = cercle.height/2 + ((400-cercle.height)*Math.random());
// PROPORTION CORRECTIONS
//cercle.width = (2*radio)*gameZoneContainer_sp.width/400;
//I ADD IT TO THE CONTAINER
gameZoneContainer_sp.addChild(cercle);
trace ("Added cercle!");
trace ("alto del contenedor: "+gameZoneContainer_sp.height);
trace ("Posicion x: "+cercle.x);
trace ("radio: "+radio);
}

This is what I think is going on. You basically have 2 problems.
You're adding circles using math meant to adjust for the position of the game window, but you don't need that if you are adding it to the game window container. This is resulting in circles that are being added too far to the right.
Something about your Air setup is making the screen contents scale to show all the contents resulting in everything shrinking. (If we fix the first problem, this one will become inconsequential).
So instead of:
cercle.x = minPosX ...etc
do:
cercle.x = Math.Random()*gameZoneContainer_sp.width;
Do likewise for the y value.
You see, the local origin point of an objects container will be that objects (0,0) point locally. So the top left corner of this game container will be the cercle's (0,0) point and therefore there is no need to adjust it to the right by the amount that you do using minPosX. This is assuming you have not made your game container offset from the default somehow (i.e. When you created the rectangle, you did so using (0,0,width,height) and not something like (xOffset,yOffset,width,height)).

Related

Dynamically draw rectangle between the Dragable objects in AS3

My aim is to highlight the area between the two dragable objects inpoint_mc and scrub_outpoint_mc, so i had created a rectangle between these points, i need to resize this rectangle based on the dragpoints, which indicates the distance between Inpoint and Outpoint, i tried my level best unfortunately i can acheive it
private function startScrubbingIN(_arg1:MouseEvent){
trace("scrubBarIsMovingIN");
this.cueCard.stage.addEventListener(MouseEvent.MOUSE_UP, this.stopScrubbingIN);
this.cueCard.stage.addEventListener(MouseEvent.MOUSE_MOVE, this.scrubBarIsMovingIN);
this.scrubbing = true;
var _local2:Rectangle = new Rectangle(this.controls_mc.progressBar_mc.x, this.controls_mc.inpoint_mc.y,
this.controls_mc.scrub_outpoint_mc.x-this.controls_mc.progressBar_mc.x, 0);
// now we're limiting in point to current position of out point
this.controls_mc.inpoint_mc.startDrag(false, _local2);
this.controls_mc.addChild(_seekIndicator);
_seekIndicator.graphics.beginFill(0x990000);
_seekIndicator.graphics.drawRect(this.controls_mc.inpoint_mc.x, this.controls_mc.progressBar_mc.y,
this.controls_mc.scrub_outpoint_mc.x-this.controls_mc.progressBar_mc.x, 12);
trace("_seekIndicator"+ _seekIndicator);
// _seekIndicator.width = this.controls_mc.scrub_outpoint_mc.x+ this.controls_mc.inpoint_mc.y;
}
it giving me the result as like the attached image
but the red rectangle need to be shrink itself between the 2 Points
The rectangle should be redrawn only after you stop dragging, or when you move mouse while dragging. Don't forget to call _seekIndicator.graphics.clear() to delete old rectangle. And finally, use this.controls_mc.scrub_outpoint_mc.x and this.controls_mc.inpoint_mc.x for borders, because you're saying the rectangle should be between the in and out point MCs, while you use this.controls_mc.progressBar_mc.x in width.
private function scrubBarIsMovingIN(e:MouseEvent):void {
// the startDrag dragged one of the sliders already
// existing code skipped, if any
_seekIndicator.graphics.clear();
_seekIndicator.graphics.beginFill(0x990000);
_seekIndicator.graphics.drawRect(this.controls_mc.inpoint_mc.x, this.controls_mc.progressBar_mc.y,
this.controls_mc.scrub_outpoint_mc.x-this.controls_mc.inpoint_mc.x, 12);
}
Should do.

AS3 display object height not reported correctly

This should be simple. What am I missing?
Create a Sprite (container), put it on the displaylist, add a new Sprite (rect) to container.
Change height of the child (rect).
Height values of both parent (container) and child (rect) are not reported correctly although rendered correctly.
Thanks for your assistance.
var container:Sprite = new Sprite();
addChild(container);
[Embed(source = "../lib/rectangle.swf")] // height is 100
var Rect:Class;
var rect:Sprite = new Rect();
trace(rect.height); // 100 is correct before placement in container
container.addChild(rect);
trace(rect.height); // 100 is correct after placement in container
trace(container.height); // 0 is not correct; should be 100
rect.height = rect.height + 100; // renders correctly at new height
trace(rect.height); // 100 is not correct; should be 200
trace(container.height); // 0 is not correct; should be 200
Apparently your container is not on the stage display list. If a measured DisplayObject is not on the display list (anywhere), its dimensional properties are not properly recalculated, when its own display list is altered. This is apparently to save time for Flash engine to process building of a complex MovieClip frame or any other complex container faster, and recalculation is only done if the container is placed to stage. The resolution is to place the object to be measured to stage (anywhere, anyhow), gather its properties then remove it from stage. An example:
trace(this.stage); // [object Stage] - to make sure we can access stage in here
var sp:Sprite=new Sprite();
var b:Bitmap=new Bitmap(new BitmapData(100,100));
trace(sp.width); // should return 0
trace(sp.height); // 0 also
sp.addChild(b);
trace(sp.height); // 0 again
trace(b.height); // should return 100, as the bitmap data is specified
// as well as in your case, the class's width and height are precalculated
addChild(sp);
trace(sp.height); // returns 100, as expected
removeChild(sp);
trace(sp.height); // 100, stored
sp.removeChild(b);
trace(sp.height); // should also return 100, while there's no content in the sprite
There is also another possibility, width of an object off stage can be in the negative, the solution is again the same - put object on stage, get width, remove object from stage.

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;
}
}

AS3 sprite with rectangle is empty and returns 0 for width and other properties

I have an array of sprites:
for (i = 0; i < 3; i++) {
var newLine:Sprite = new Sprite();
newLine.graphics.beginFill(0xFFFFFF);
newLine.graphics.drawRect((uiSizeX * (.25 + .25 * i)) + (doorSizeX - lineLengths[0][i]) / 2, uiSizeY * .5, lineLengths[0][i], lineHeight);
newLine.name = "lines" + i;
lines.push(newLine);
}
I later add each to a background Sprite:
for (i = 0; i < 3; i++) {
uiContainer.addChild(doors[i]);
uiContainer.addChild(lines[i]);
}
And later wish to change the width of the rectangles contained in each. When I set the width property using the array reference:
lines[i].width = lineLengths[trialNumber][i];
The rectangle moves towards the center of the stage and uiContainer. Trying to set the x value results in even stranger behavior. I've gathered from answers to other questions that this is because the sprite is empty, which is confusing since it seems like it should have a rectangle in it. How do I access or change the properties of the rectangle or make it so the sprite is not empty?
Never try to directly change the width or height of a sprite, unless you really really have to, because it leads to all sorts of unexpected behavior.
If you want to resize the sprite, then redraw the rectangle:
var sprite = lines[i];
sprite.graphics.beginFill(0xFFFFFF);
sprite.graphics.drawRect(newWidth, newHeight);
Also don't forget to call endFill:
sprite.graphics.endFill();
You should probably wrap all this logic into a separate class so that you can redraw your sprites more easily. Even better, create a class that extends Sprite and that contains all the logic to redraw/resize.

actionscript 3 position textfield N pixels from bottom or 90% from top

I'm new to actionscript 3. I want to create a textfield that is either N number of pixels from the bottom of the stage or 90% from the top of the stage.
Basically i want the textfield to always appear near the bottom of the stage. What property of the TextField() object do I configure to achieve this?
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90);
myTextField.y = newPositionY;
}
Now if you want to account for the height of the actual text for whatever reason, you change it to this:
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90) - myTextField.textHeight;
myTextField.y = newPositionY;
}
Remember the origin of the field is top left, so the bottom of the text will appear at myTextField.x + myTextField.textHeight;.
Also, you can listen for the RESIZE event on the stage and update your TextField like so:
stage.addEventListener(Event.RESIZE, onStageResized);
function onStageResized(e:Event):void
{
updateTextPosition();
}