Removing just a set of instances of an object from the scene - actionscript-3

I have a problem in ActionScript 3 with a project where I am to output a bunch of data in a diagram and as pure text. This is not the problem, though. The problem is that when the user changes the type of data he wants shown. I would then remove the currently shown columns in the diagram, and add new ones. But my code removes ALL columns, so that there is no diagram at all!
I've done it all in Flash CS5, and the columns are instances of an object I made (a rectangle) which I just add to the stage. All the instances are added to the container "container." When I want to remove them, and add new ones I use:
var container = new Sprite(); // The container for my diagram
function emptyContainer() {
if (container.numChildren > 0) {
container.removeChildAt(0);
}
}
Which works.
I have switch statement that adds the different columns based on user-input. The name of the object (the rectangle) is "soyle." The name of the instances is "stolpe"
(I am norwegian by the way, so that's the deal with those weird words)
function fChange(event:Event) {
textToBeReturned = "";
switch (treCbox.selectedItem.label) {
case "Furu":
for (var a = 1; a < table.length; a++ ){
textToBeReturned += "I år: " + table[a][0] + " - " + table[a][1] + " millioner trær." + "\n";
// Diagram
var stolpe = new soyle;
stolpe.width = table[a][1];
stolpe.x = 20;
stolpe.y = 100 + (a * 30);
container.addChild(stolpe);
// Description for the columns
var textbox = new TextField;
textbox.text = "År " + table[a][0];
textbox.x = stolpe.width + 30;
textbox.y = stolpe.y;
container.addChild(textbox);
}
break;
case "Gran":
for (var b = 1; b < table.length; b++ ){
textToBeReturned += "I år: " + table[b][0] + " - " + table[b][2] + " millioner trær." + "\n" ;
var stolpe = new soyle;
stolpe.width = table[b][1];
stolpe.x = 20;
stolpe.y = 100 + (b * 30);
container.addChild(stolpe);
// Description for the columns
var textbox = new TextField;
textbox.text = "År " + table[b][0];
textbox.x = stolpe.width + 30;
textbox.y = stolpe.y;
container.addChild(textbox);
}
break;
case "Lauvtre":
for (var c = 1; c < table.length; c++ ){
textToBeReturned += "I år: " + table[c][0] + " - " + table[c][3] + " millioner trær." + "\n" ;
var stolpe = new soyle;
stolpe.width = table[c][1];
stolpe.x = 20;
stolpe.y = 100 + (c * 30);
container.addChild(stolpe);
// Description for the columns
var textbox = new TextField;
textbox.text = "År " + table[c][0];
textbox.x = stolpe.width + 30;
textbox.y = stolpe.y;
container.addChild(textbox);
}
break;
}
txtReturn.text = textToBeReturned;
};
I wonder where to place my function for removing all children, to remove just those children that were added earlier. To matter where I place the function (at the start of fChange, at the beginning of each case) there is NO diagram shown, either new or old.
There is of course an array with the data, but I do not post it as it is irrelevant.
Thank you for your time, and in advance for your help! :)

Couple of problems here. I assume you want to remove all children from your container MC before adding new children inside your switch. (Tip for next time, try to post only the code your working with. The switch statement here is large and overwhelming. It's also not really relevant)
Your function emptyContainer does not actually remove all children, it only removes one at index 0. This needs to be inside of a loop.
function emptyContainer() {
while (container.numChildren > 0) { //changed the if to a while. This will run until there are no children left in container
container.removeChildAt(0);
}
}
You're going to want to call this first thing inside of your fChanged function
function fChange(event:Event) {
emptyContainer()
/* rest of function */
}
try this out and let me know how it works.

Related

Convert a decimal number to a fraction AS3

I'm trying to get to convert the decimals to a fraction so for example, I had written something such as var _pow:int = Math.pow(base,i) and if i turned out to be a negative number it would give out a decimal (example: 3 ^ -2) and I'm currently stuck trying to find a way to turn _pow into a franction (so _pow out of a 100) so I tried to do var _pow:int = Math.pow(base,i) * 100 which should stop it from being a decimal but it's not showing in the dynamic text, and this only happens if i is negative
package{
import flash.display.*;
import flash.events.MouseEvent;
public class name_ extends MovieClip{
public function _name_(){
btn.addEventListener(MouseEvent.CLICK, input)
base.restrict = "0-9\\.\\-";
pow.restrict = "0-9\\.\\-";
answer.multiline = true;
}
private function input(event:MouseEvent):void{
var pow = pow.text;
var base = base.text;
var answerText:String = "";
if(pow > 0){
for(var i = 1; i <= pow; i++){
_pow = Math.pow(base,i);
answerText += ("\n" + base + " exposant(power) " + i + " = "+ _pow );
answer.text = answerText;
}
}else{
for(i = 1; i <= pow; i++){
var _pow:int = Math.pow(base,i) * 100
answerText += ("\n" + base + " exposant(power) " + i + " = "+ _pow );
answer.text = answerText; //Dynamic text
}
}
}
}
}
Have you tried using an "if" statement? Something like if(i <= 0){code}.
You can also try using the Math.floor(number to be rounded down); or Math.ceiling(number to be rounded up)

Pairing a draggable object to a target object in AS3

I'm currently stuck with my approach below. I'm not entirely sure if using "hitTestObject" method is appropriate in pairing the pieces to their respective place. I was able to at least match the chess piece to their respective location (that's the best I can do and I feel i'm doing it wrong) but I'm now stuck in counting how many pieces are actually in their correct places. e.g. when I move the pawn to a different tile, it will still count as one, I also want to avoid duplicate counting, example, If pawn is already in the correct location, it will just count as 1, and if it was moved, then that count will be removed. Only count the pieces that are in the correct tile.
My goal here is to be able to make all the chess pieces draggable and determine if they're in their respective location. If ALL the chess pieces are in their location, it will trace or call a function.
Thank you!
import flash.events.Event;
import flash.display.MovieClip;
import flash.events.MouseEvent;
/* Declaring an X and Y variable to be used as a reset container */
var xPos: int, yPos: int;
/* Attaching event listeners for each chess piece */
addListeners(
king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8);
/* Getting the original x and y postion to be used as a reset */
function getPosition(currentTarget: Object): void {
xPos = currentTarget.x;
yPos = currentTarget.y;
}
/* Function to get the suffix value of an object. example, I need to get the value 4 from "pawn_4" */
function getLastCharInString($s: String, $pos: Number): String {
return $s.substr($s.length - $pos, $s.length);
}
/* A simple function that rotates the chess piece */
function lift(object: Object, rot: Number) {
object.rotation = rot;
}
function dragObject(e: MouseEvent): void {
getPosition(e.currentTarget);
lift(e.currentTarget, -10);
getChildByName(e.currentTarget.name + "_hs").alpha = 1;
e.currentTarget.startDrag();
}
/* This variable is supposed to hold the value of each piece that is correctly placed in each tile.
The total score should be 16 as there are 16 pieces. Only correcly placed piece should be added in the total score. */
var counter:int;
function stopDragObject(e: MouseEvent): void {
var curretTarget = e.currentTarget.name;
lift(e.currentTarget, 0);
/* Hide active hotspots */
getChildByName(e.currentTarget.name + "_hs").alpha = 0;
var multiplePieceSufix = Number(getLastCharInString(curretTarget, 1));
if (multiplePieceSufix >= 1) {
/* Boolean variables that checks whether the current piece is active*/
var isPawn: Boolean = false,
isBishop: Boolean = false,
isKnight: Boolean = false,
isRook: Boolean = false,
currentTargeName;
var widthDiff = getChildByName(e.currentTarget.name + "_hs").width - getChildByName(e.currentTarget.name).width / 2;
var heightDiff = getChildByName(e.currentTarget.name + "_hs").height - getChildByName(e.currentTarget.name).height / 2;
if (curretTarget.substr(0, 4) == "pawn") {
isPawn = true;
} else if (curretTarget.substr(0, 6) == "bishop") {
isBishop = true;
} else if (curretTarget.substr(0, 6) == "knight") {
isKnight = true;
} else if (curretTarget.substr(0, 4) == "rook") {
isRook = true;
}
if (isPawn == true) {
/* there are total of 8 pieces of pawn */
for (var w = 1; w < 9; w++) {
currentTargeName = this["pawn_" + w + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
/* For some reason the chess pieces are not aligning with their "_hs" version, I already checked their registry point and it seem to be normal.
so to fix, I had to manually add some hard coded values to adjust their location. */
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isBishop == true) {
for (var x = 1; x < 3; x++) {
currentTargeName = this["bishop_" + x + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 9;
e.currentTarget.y = currentTargeName.y + currentTargeName.height - 18;
}
}
} else if (isKnight == true) {
for (var y = 1; y < 3; y++) {
currentTargeName = this["knight_" + y + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isRook == true) {
for (var z = 1; z < 3; z++) {
currentTargeName = this["rook_" + z + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + 62;
}
}
}
} else {
if (e.target.hitTestObject(getChildByName(e.currentTarget.name + "_hs"))) {
/* Again, I'm not sure why the pieces are not aligning as intended.
modX and modY is a holder for the adjustment value. I'm not comfortable
seeing this approach myself, but I also run out of ideas how to fix it. */
var modX: Number, modY: Number;
if (e.currentTarget.name == "king") {
modX = 11;
modY = 53;
} else {
modX = 11;
modY = 29;
}
e.currentTarget.x = getChildByName(e.currentTarget.name + "_hs").x - modX;
e.currentTarget.y = getChildByName(e.currentTarget.name + "_hs").y + getChildByName(e.currentTarget.name + "_hs").height - modY;
}
}
/* This is supposed to add to the total score or count of how many pieces are placed correctly.
Thie problem with thi scounter, as it also counts any piece that is places to any "_hs" */
counter++;
trace(counter);
e.currentTarget.stopDrag();
}
function addListeners(...objects): void {
for (var i: int = 0; i < objects.length; i++) {
objects[i].addEventListener(MouseEvent.MOUSE_DOWN, dragObject);
objects[i].addEventListener(MouseEvent.MOUSE_UP, stopDragObject);
// hide hotspots
getChildByName( objects[i].name + "_hs" ).alpha = 0;
}
}
Source: Download the FLA here
--
Updates:
I have added comments in my code to clarify what I'm trying to accomplish.
I'm planning to do board game in flash which has similar function and behaviour to this. User can drag the object to a specified tile and check wether that object belongs there or not.
After reviewing your code, your question is quite broad. I'm going pair it down to what seems to be your main concern - the score / counting correctly moved pieces.
Right now, you do the following every time an object is dragged:
counter++;
This means that the counter will increment no matter where you drag the object, and no matter how times you drag the object. (so even if the piece was already in the correct spot, if you dragged it a second time it will still increment your counter).
What you need to do, is associate a flag with each object to indicate whether it is in the correct location or not, and set that flag to the appropriate value every time that object is done dragging.
Something like this:
//don't use target, use currentTarget
if (e.currentTarget.hitTestObject(currentTargeName)) {
e.currentTarget.correct = true; //since MovieClips are dynamic, you can just make up a property on them and assign a value to it.
//to fix your alignment:
e.currentTarget.x = currentTargeName.x + ((currentTargetName.width - e.currentTarget.width) * 0.5);
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}else{
//if the hit test is false, mark it as NOT correct
e.currentTarget.correct = false;
}
Then, later to know the current count, iterate over all the pieces and check their correct value. This would be much easier if all your pieces were in an array.
var allPieces:Array = [king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8];
function countCorrect():Boolean {
var ctr:int = 0;
for(var i:int=0;i<allPieces.length;i++){
if(allPieces[i].correct) ctr++;
}
return ctr;
}
trace(countCorrect() + " of " allPieces.length " are correct");
As an aside, this best way to do this would be with some custom class files. That would however require a complete refactoring of your code.
Also, you probably don't want to use hitTestObject, as even if a piece is mostly over a neighbor, it will still be true as long as 1 pixel of it's bound touch 1 pixel of the tile. Better would be to do a hitTestPoint on the tile, and pass in the center point of the piece (the the middle of the piece has to be touching the tile for it to count).
//a point that is the center of the events current target (the piece)
var point:Point = new Point();
point.x = e.currentTarget.x + (e.currentTarget.width * 0.5);
point.y = e.currentTarget.y - (e.currentTarget.height * 0.5);
if (currentTargetName.hitTestPoint(point)) {

Operations carry over on next random

function roll(){
randomNumber = Math.ceil(Math.random() * range);
randomNumber2 = Math.ceil(Math.random() * range);
randomNumber3 = Math.ceil(Math.random() * range);
dice1_mc.gotoAndStop(randomNumber);
dice2_mc.gotoAndStop(randomNumber2);
dice3_mc.gotoAndStop(randomNumber3);
num1 = int(randomNumber);
num2 = int(randomNumber2);
num3 = int(randomNumber3);
trace(num1);
trace(num2);
trace(num3)
}
function AddCheck(e:MouseEvent):void {
ans = num1+num2+num3;
if (displayText.text == String(ans)){
//score++;
trace("Correct");
trace(ans);
displayText.text ="";
score+=1;
displayScore.text = String(score);
opsymbol=0;
RandomizeOperation();
}else{
trace("answer is " + ans + "------")
clearTxt();
//RandomizeOperation()
}
}
function MultiCheck(e:MouseEvent):void {
ans = num1*num3;
if (displayText.text == String(ans)){
//score++;
trace("Correct");
displayText.text ="";
score+=1;
displayScore.text = String(score);
opsymbol=0;
RandomizeOperation();
}else{
trace("answer is " + ans + "------")
clearTxt();
//RandomizeOperation()
}
}
function SubCheck(e:MouseEvent):void {
ans = num1-num2-num3;
if (displayText.text == String(ans)){
//score++;
trace("Correct");
trace(ans);
displayText.text ="";
score+=1;
opsymbol=0;
displayScore.text = String(score);
RandomizeOperation();
}else{
trace("answer is " + ans + "------")
clearTxt();
//RandomizeOperation()
}
}
function RandomizeOperation(){
var oprange:uint = 2;
opsymbol = Math.ceil(Math.random() * oprange);
//opsymbol = 2;
//trace(opsymbol);
if(opsymbol == 1){
dice2_mc.visible= true;
trace(opsymbol + " addition");
enterAns_btn.addEventListener(MouseEvent.CLICK, AddCheck);
roll();
}
if(opsymbol == 2){
dice2_mc.visible= true;
trace(opsymbol + " subtraction");
enterAns_btn.addEventListener(MouseEvent.CLICK, SubCheck);
roll();
}
}
The operation carry over everytime the question changes. I dont know whats wrong.
example first question is 1+2+3 (which is 6) and the next question is Subtraction (3-3-1- RIGHT answer is suppose to be -1) but it add. i cant figure out whats wrong
Nothing is carrying over here. You're just not removing the eventListener for mouse from one type to another, instead you are adding to the already there MouseEvent(s). Two traces at once is a big clue:
You need inside { } of your if (opsymbol == 2):
//will remove ANY existing current listeners to some function
enterAns_btn.removeEventListener(event.type, arguments.callee);
//adds a new listener to some function for this new Check type
enterAns_btn.addEventListener(MouseEvent.CLICK, SubCheck);
Why it happens:
if (opsymbol == 1)
{
//CHECK ONE: enterAns_btn listens for ADD
enterAns_btn.addEventListener(MouseEvent.CLICK, AddCheck);
}
if (opsymbol == 2)
{
//CHECK TWO: enterAns_btn listens for SUBTRACT
enterAns_btn.addEventListener(MouseEvent.CLICK, SubCheck);
}
Because CHECK TWO happened after CHECK ONE, At this point you're now telling Flash that enterAns_btn must actually do two functions on mouse click.. Essentially it heard this command:
enterAns_btn.addEventListener(MouseEvent.CLICK, AddCheck); //added by check one
enterAns_btn.addEventListener(MouseEvent.CLICK, SubCheck); //added by check two
And thats why you get two traces results at once.. One for adding to give you the 7 and the other for subtracting to give the -1.. Hope it helps.

How do I compare a string in Flash to the name of a variable?

I'm not entirely sure if this is possible at all, but I'm trying to take a string in Flash and check to see if it is the same as the name of an already existing variable. Here is a piece of my code:
var randomNumber:int;
var randomNumberS:String;
var Mem1:String;
var Mem2:String;
randomNumber = Math.floor(Math.random()*3);
randomnumberS = ("Mem" + String(randomNumber));
TGiven.text = [the randomnumberS string, except as either the variable name Mem1 or Mem2]
Is this a possible task, and if not, is there a better way to perform this task? It would be very useful as I plan on making many more variables that start with Mem with higher and higher numbers.
It would be optimal if the variables were a member of a class or Object, to which you could evaluate whether they exist using hasOwnProperty().
For example:
var obj:Object = {
Mem1: "value1",
Mem2: "value2"
};
You could test whether obj has a property by name:
obj.hasOwnProperty("Mem1");
Applying your example using random numbers:
for (var i = 0; i < 100; i++) {
var randomNumber:int = Math.floor(Math.random() * 3);
if (obj.hasOwnProperty("Mem" + randomNumber))
trace("Mem" + randomNumber + " exists.");
else
trace("Mem" + randomNumber + " does not exist.");
}
You can also use the in keyword, such as:
"Mem1" in obj;
Using the same example:
for (var i = 0; i < 100; i++) {
var randomNumber:int = Math.floor(Math.random() * 3);
if (("Mem" + randomNumber) in obj)
trace("Mem" + randomNumber + " exists.");
else
trace("Mem" + randomNumber + " does not exist.");
}

How to remove/reload movieclip/graphic in Flash CS5 with AS3

I have a setupBoard(); and a setupBlocks(); in my function:
function init(e)
{
setupBoard();
removeEventListener(Event.ENTER_FRAME , init);
setupCat();
setupBlocks();
}
function setupBoard()
{
var columns:Array = new Array();
var i,j:int;
var _place:place;
for (i = 0; i < 11; i++)
{
columns = [];
for (j = 0; j < 11; j++)
{
_place = new place();
_place.thisX=i;
_place.thisY=j;
_place.thisDistance=Math.min(i+1,j+1,11-i,11-j)*11;
_place.y = 56 * i + 3;
_place.x = 5 + 71 * j + 35*(i%2);
_place.buttonMode=true;
_place.addEventListener(MouseEvent.CLICK, setBlock);
columns[j] = _place;
// SÆTTER TAL PÅ BRIKKERNE
_place.thisText.text = _place.thisDistance + " - " + _place.thisX + " : " + _place.thisY;
addChild(_place);
}
rows[i] = columns;
}
}
The "place" is the MovieClip
this function loads when the game launches and when the game is finish/completed..
the setupBoard, setup the board ofc, and the setupBlocks setup some movieclips, which contain some graphic.
Here's my question, how do I remove/reload all the blocks when the game enters that function again?
At the moment they are just placed upon each other, which I don't like at all.
If I understood correctly, what you want to do is remove all the previous blocks (from the last time you ran the setup function) when you run setup a second time.
To do that, you should create a function which loops your rows and columns Arrays, and for each Place object it find, it does the following: removes it from the stage, removes all Event Listeners, and finally sets it to null. Your function could look something like this (and you would call it just before calling setup again):
for (i = 0; i < rows.length; i++)
{
var column:Array = rows[i];
for (j = 0; j < column.length; j++)
{
var place:Place = column[j];
if (contains(place))
{
removeChild(place);
}
place.removeEventListener(MouseEvent.CLICK, setBlock);
place = null;
}
column = [];
}
row = [];
I just wrote that straight into the box, so it's not tested. But basically it does the three things necessary to get those objects removed from the view, and clears up anything that would stop them from being freed from memory by the garbage collector.
Hope that helps.
Debu