Please do forgive me if this question is very stupid, but I couldn't figure out what to do, which is why I ask it.
Here, I declared a small white square as a movieclip symbol(Dot) and I wish to generate it after a specific gap on the entire screen.
So, when I execute this (test it) code on Flash CS6, it hangs. After that I will be forced to end the program without doing anything further.
import flash.ui.*;
stop();
Mouse.hide();
var ctX:int = 0,ctY:int = 0,done:Boolean = false;
var base:Object = MovieClip(root);
this.addEventListener(Event.ENTER_FRAME, eFrame);
function eFrame(event:Event):void
{
while (done == false)
{
var dots:Dot = new Dot ;
dots.x += (50 * ctX);
dots.y += (50 * ctY);
ctX++;
if (ctX == 11)
{
ctX = 0;
ctY++;
}
else if (ctX == 11 && ctY == 10)
{
done = true;
break;
}
stage.addChild(dots);
}
}
Thank you in advance.
I have attached a screenshot of the situation.
The loop will never finish because the condition for done=true is ctX==11, but ctX==11 causes ctX=0 in the first condition:
if (ctX == 11) // when ctX is 11
{
ctX = 0; // ctX is reset to 0
ctY++;
}
else if (ctX == 11 && ctY == 10) // so you will never have ctX=11 here
{
done = true;
break; // (Tip: you don't need `done` since `break` exits the loop)
}
You could fix this by swapping the conditions, but I think this use of a while loop is unnecessarily complex and fragile. Why not just use two for loops:
for (var ctX:int = 0; ctX < 11; ctX++) {
for (var ctY:int = 0; ctY < 11; ctY++) {
var dots:Dot = new Dot();
dots.x = (50 * ctX);
dots.y = (50 * ctY);
stage.addChild(dots);
}
}
This is much clearer and less fragile because the loops are fixed length.
You could even do it with one for loop and a little math, but you lose some clarity:
for (var i:int = 0; i < 11 * 11; i++) {
var dots:Dot = new Dot();
dots.x = (50 * (i % 11));
dots.y = (50 * int(i / 11));
stage.addChild(dots);
}
Related
I created some MovieClips and put all of them on the stage. I'm trying to move a random MovieClip, using it only once, but at the same time I need to know which one it is because it will conflict with other tween effects. Is there an easy way to do that?
Here is what I've tried:
var biryukseklev1, ikiyukseklev1, ucyukseklev1, dortyukseklev1, besyukseklev1:int;
var assignavalue1, assignavalue2:int;
stage.addEventListener(Event.ENTER_FRAME,survivordondurlev6);
function survivordondurlev6(e:Event) {
if (biryerlessurlev1 == 0) {
biryukseklev1 = 764;//36
} else if (biryerlessurlev1 == 1) {
biryukseklev1 = 680;//120
} else if (biryerlessurlev1 == 2) {
biryukseklev1 = 596;//204
} else if (biryerlessurlev1 == 3) {
biryukseklev1 = 512;//288
} else if (biryerlessurlev1 == 4) {
biryukseklev1 = 428;//372
}
if (assignavalue1 == 0 && rabbitstatus.text.length < 2) { //Make sure to not used before
var my:Tween = new Tween(rabbit, "y", Back.easeInOut, rabbit.y, rabbit.y -biryukseklev1, 3, true);
rabbitstatus.text = "okfull";
} else if((assignavalue1 == 1 && birdstatus.text.length < 2){ //Make sure to not used before
var mys:Tween = new Tween(bird, "y", Back.easeInOut, bird.y, bird.y -biryukseklev1, 3, true);
birdstatus.text = "okfull";
}
}
If you want to keep track of which clips you've animated, then you'll have to have some way of iterating through them. The easiest list would be an Array, though how you mark them as "animated" is up to you. If you never plan on animating them again, then simply removing the ones that you've animated, and leaving the rest for later will work.
Below is example code, which you should be able to run in a new scene. You should be able to apply it to your needs with some small edits.
import fl.transitions.Tween;
import fl.transitions.easing.*;
// We'll keep track of which blocks still need to be animated by including them in this list
// Once we animate a block, we remove it from the list.
var pool:Array = [];
// Populate the stage with blocks.
for (var i:int = 0; i < 30; i++) {
var block:Sprite = createBlock();
addChild(block);
block.y = 50;
if (i > 0) { block.x = block.width * i; }
pool.push(block);
}
// Create an interactive button.
var txt:TextField = new TextField();
txt.text = "Do something";
addChild(txt);
txt.addEventListener("click", animateNext);
function createBlock():Sprite {
// Creates a single, randomly colored block.
var block:Sprite = new Sprite();
block.graphics.beginFill(random(0x000000, 0xFFFFFF));
block.graphics.drawRect(0,0,16,16);
block.graphics.endFill();
return block;
}
function random(low:Number, high:Number):Number {
// Returns a random number between the low and high numbers.
return Math.floor(Math.random() * (1+high-low)) + low;
}
function animateNext(e:Event):void {
// Do this 5 times.
for (var i:int = 0; i < 5; i++) {
// As long as we have blocks in the pool...
if (pool.length > 0) {
// Pick a random block from the pool
var index:int = random(0, pool.length-1);
// Animate it
new Tween(pool[index], "y", Back.easeInOut, pool[index].y, pool[index].y + 50, 3, true);
// Remove it from the pool so it isn't picked again
pool.splice(index, 1);
} else {
// Otherwise, break the loop.
break;
}
}
}
I have tried 2 different pseudocodes, from both Wikipedia and MIT, eventually both give me the same results:
sometimes, like on these screenshots, traversing loops forever because somehow there appears a link back somehow:
I include code in AS3:
{
private function searchPath(e:MouseEvent = null):void
{
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].role = Node.IDLE_NODE;
if (!endNode || !beginNode) return;
beginNode.role = Node.BEGIN_NODE;
endNode.role = Node.END_NODE;
openSet.push(beginNode);
beginNode.g = 0;
beginNode.f = beginNode.h = heuristicCost(beginNode, endNode);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void
{
if (openSet.length)
{
// searching for minimal f score node
var current:Node = openSet[0];
for (var i:int = 0; i < openSet.length; i ++)
if (openSet[i].f < current.f)
{
current = openSet[i];
}
current.role = Node.CURRENT_NODE;
// remove current node from openset
openSet.splice(openSet.indexOf(current), 1);
// walking through neighbours
for each(var neighbour:Node in current.neighbours)
{
if (neighbour == endNode)
{
neighbour.parentNode = current;
highlightPath(neighbour);
return;
}
if (current.g + heuristicCost(current, neighbour) >= neighbour.g)
continue;
neighbour.g = current.g + heuristicCost(current, neighbour);
neighbour.h = heuristicCost(neighbour, endNode);
neighbour.f = neighbour.g + neighbour.h;
// if neighbour is in the closed set or is in the openthen skip it
if (!(closedSet.indexOf(neighbour) > -1) && (openSet.indexOf(neighbour) < 0))
{
openSet.push(neighbour);
neighbour.parentNode = current;
}
}
// add current node to the closed set
closedSet.push(current);
}
else
{
while (closedSet.length) closedSet.pop();
trace("No solution");
removeEventListener(Event.ENTER_FRAME, update);
}
}
private function highlightPath(current:Node):void
{
var tp:Vector.<Node> = new Vector.<Node>();
tp.push(current);
while (current.parentNode) //this loops forever in situations from screenshots, because there's a link back
{
tp.push(current.parentNode);
current.role = Node.PATH_NODE;
current = current.parentNode;
}
current.role = Node.PATH_NODE;
while (openSet.length) openSet.pop();
while (closedSet.length) closedSet.pop();
for (var i:int = 0; i < nodes.length; i ++)
nodes[i].g = nodes[i].h = nodes[i].f = Infinity;
removeEventListener(Event.ENTER_FRAME, update);
}
}
Don't pay attention to the distances! That path is optimal, the nodes that are closer aren't connected(I hided connections on screenshots).
And also, forgot to mention that begin node on the screenshots is black, not orange.
Sorry, guys, I made a very silly mistake, I forgot to reset my parentNodes of Nodes to null after first run.
You should set neighbour.parentNode = current when you set neighbour.g. Right now you're setting parentNode to the first node that pushes neighbor onto the openSet
Also you will get much better performance if you use the proper data-structures (a set for closedSet; a priority-queue for openSet)
I have been banging away on this issue for a long time now and I would love someone to whack me upside the head. I feel like I am so close, but you know how that is.
I have a drag and drop game, 8 options and 5 are correct. I want the user to drag 5 items from the 8 to the right of the screen. When they reach 5, it gives them a result. Right or Wrong (to keep the process moving I am not making them keep re-trying). Well, at this point in my code, everything is working well, except, when the end comes it only shows the right answer no matter what they drag. Please help.
I hope this is clear, thanks for any advice. I already appreciate you if you even read this.
import flash.display.MovieClip;
var cor_mc:correct_items_mc = new correct_items_mc;
var nopeAnswers:incorrect_items = new incorrect_items;
var policies:Array = [policy_0,policy_1,policy_2,policy_3, policy_4,policy_5,policy_6, policy_7];
var correct_choices:Array = [0,2,4,5,6];
var selected_items:Array = [];
for (var i:int = 0; i < policies.length; i++) {
var mc:MovieClip = policies[i];
mc.buttonMode = true;
mc.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag);
mc.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop);
mc.home_x = mc.x;
mc.home_y = mc.y;
mc.is_correct = correct_choices.indexOf(i);
}
function fl_ClickToDrag(event:MouseEvent):void
{
event.currentTarget.startDrag();
setChildIndex(MovieClip(event.currentTarget), numChildren - 1);
}
function fl_ReleaseToDrop(event:MouseEvent):void
{
var dropIndex:int = policies.indexOf(event.currentTarget);
var target:MovieClip = event.currentTarget as MovieClip;
target.stopDrag();
if (target.hitTestObject(bucket_mc)) {
selected_items.push(target);
trace(selected_items);
target.x = bucket_mc.x;
target.y = bucket_mc.y + selected_items.length * 60;
} else { // no match ... false
target.x = target.home_x;
target.y = target.home_y;
}
if (selected_items.length === correct_choices.length)
{
for (i = 0; i < correct_choices.length; i ++)
{
var cur_choice = correct_choices[i];
if (!selected_items.indexOf(cur_choice)) {
addChild(nopeAnswers);
nopeAnswers.x = 0;
nopeAnswers.y = 100;
} else {
addChild(cor_mc);
cor_mc.x = 0;
cor_mc.y = 100;
}
}
}
}
From the Manual indexOf returns -1 if the element is not found rather than a boolean false.
Change the condition to:
if (selected_items.indexOf(cur_choice) < 0){
....
}
Also if any of your first 4 correct values have NOT been selected you still continue looping and so will still output cor_mc if the final correct item was selected. You need to stop the loop once you find a correct answer missing:
if (selected_items.indexOf(cur_choice) < 0) {
addChild(nopeAnswers);
nopeAnswers.x = 0;
nopeAnswers.y = 100;
break;
} else {
addChild(cor_mc);
cor_mc.x = 0;
cor_mc.y = 100;
}
I have a large number of objects (472) that require a timer used to check how long it takes between state changes of a variable. The code below is what I have so far but that many timers running definitely impacts the performance of the application, is there a better optimised way of measuring this?
import flash.utils.Timer;
var active_:Boolean;
var matched:Boolean;
var vacated:Boolean;
var circ:Shape=new Shape();
this.addChild(circ);
circ.x = 0;
circ.y = 0;
var circRad:Number = 5;
var mat= new Matrix();
var busyColors = [0xFFFF00,0xFFCC00];
var idleColors = [0xCCCCCC,0x000000];
var matchedColors = [0x0099FF,0x0066FF];
var vacatedColors = [0xFF0000,0x990000];
var busyAlphas = [1,1];
var idleAlphas = [0.5,0.5];
var ratios = [0,255];
var prev:int = 0;
var time:Timer = new Timer(1000,0);
//time.start();
mat.createGradientBox(2*circRad,2*circRad,0,-circRad,-circRad);
circ.graphics.lineStyle();
if (active_ == false)
{
if (prev != 0)
{
setAverage(prev,false);
prev = 0;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,idleColors,idleAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && matched == true)
{
if (prev != 1)
{
setAverage(prev,true);
prev = 1;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,matchedColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && vacated == false && matched == false)
{
if (prev != 2)
{
setAverage(prev,true);
prev = 2;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,busyColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
else if (active_ == true && vacated == true)
{
if (prev != 3)
{
setAverage(prev,true);
prev = 3;
}
circ.graphics.clear();
circ.graphics.beginGradientFill(GradientType.RADIAL,vacatedColors,busyAlphas,ratios,mat);
circ.graphics.drawCircle(0,0,circRad);
circ.graphics.endFill();
}
function setAverage(i:int, a:Boolean)
{
time.stop();
switch (i)
{
case 0 :
break;
case 1 :
MovieClip(root).avgMat.push(uint(time.currentCount));
break;
case 2 :
MovieClip(root).avgBusy.push(uint(time.currentCount));
break;
case 3 :
MovieClip(root).avgVac.push(uint(time.currentCount));
break;
}
if(a == true){
//time.reset();
//time.start();
}
}
Commented out the timer starts because of the issue.
You can make public function like "tick()" at yours objects and call it in loop from 1 general timer outside.
Consider doing the following:
in the top, import getTimer
import flash.utils.Timer;
Create a variable containing the starting time (instead of doing timer.start) do this:
var timerStart : int = getTimer();
and instead of doing this: time.currentCount
Simply do this:
(getTimer() - timerStart) / 1000
Good luck.
you could change all the timers with addEventListener of type EVENT FRAME
var counter:Number = 0;
addEventListener(Event.ENTER_FRAME, counting);
function counting (e:Event):void
{
counter++
}
So counter will increment on every frame. Now you have to find fps. Now multiply fps by time that you want timer to run after. So it's should look like this:
var counter:Number = 0;
addEventListener(Event.ENTER_FRAME, counting);
function counting (e:Event):void
{
counter++
if(counter == 60) //60 fps means this line will run after 1 sec.
{
//do something
}
If(counter == 120) //60 fps; 2 sec
{
//do something
}
}
This method is much more accurate and the system will not be so overloaded. This can especcially help you for setting up the stage using addChild, when you need a delay after the animation is started.
You can make more of this 'timers', but that depends on the demands of the game, but i'm sure that it will work faster than hundreths of timers.
I am creating a platformer with as3 and need to see if children of the movieclip _boundaries are on the stage or not, that way I can remove them and lower the counter so that more will continually generate. So far all I have is below. Please help, been stuck on this for a couple of weeks.
var ObjectArray:Array = [];
var ChildrenColliding:Boolean = false;
var onStageCount:Number = 0;
function generateObjects():void{
if(_vx > 0 && onStageCount < 20){
var Square:MovieClip;
Square = new mcSquare();
Square.x = Math.random() * 1000 + (Math.abs(_boundaries.x) + 50);
Square.y = Math.random() * stage.stageHeight/2.5 + (stage.stageHeight/2.5);
ObjectArray.push(Square);
_boundaries.addChild(Square);
onStageCount += 1;
}
for(var i in ObjectArray){
Square[i] = Square.name;
for(var a in ObjectArray){
if(ObjectArray[i].hitTestObject(ObjectArray[a]) && a != i){ChildrenColliding = true;}
while(ChildrenColliding){
ObjectArray[i].x += (ObjectArray[a].height + 25);
ObjectArray[i].y += (ObjectArray[a].width + 25);
ChildrenColliding = false;
if(ObjectArray[a].hitTestObject(ObjectArray[i]) && a != i){ChildrenColliding = true;}
}
}
}
//CHECK TO SEE IF CHILDREN ARE ON STAGE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(var w in ObjectArray){
if(_boundaries){
onStageCount -= 1;
trace("removed");
_boundaries.removeChild(ObjectArray[w]);
ObjectArray.splice(w, 1);
}
}
}
You may need to use the localToGlobal method to determine the position of the Square Objects. Something like:
for (var w in ObjectArray) {
if (_boundaries) {
var sq:MovieClip = ObjectArray[w];
var pnt:Point = _boundaries.localToGlobal(new Point(sq.x, sq.y));
if (pnt.x <= 0 || pnt.x >= _boundaries.stage.stageWidth ||
pnt.y <= 0 || pnt.y >= _boundaries.stage.stageHeight) {
// remove square
onStageCount -= 1;
trace("removed");
_boundaries.removeChild(ObjectArray[w]);
ObjectArray.splice(w, 1);
}
}
}
On a side note for general best practice, reserve words starting with capital letters for class names (like MovieClip, Sprite, or MyCustomClass) and use camelCase for variable names. It's helpful when working with other devs to promote best practice.
Hope this helps.
Try this:
//CHECK TO SEE IF CHILDREN ARE ON STAGE!!!!!!!!!!
for(var w in ObjectArray){
if(_boundaries && _boundaries.contains(ObjectArray[w])){
onStageCount -= 1;
trace("removed");
_boundaries.removeChild(ObjectArray[w]);
ObjectArray.splice(w, 1);
}
}