Different objects with the same function IF Error -Actionscipt - actionscript-3

I am trying to create a drag and drop game.
I used an array and it works with drag and drop, but doesn't work with the IF function.
Instead, it shows me this error:
"TypeError: Error #1010: A term is undefined and has no properties.
at
Test_game_fla::MainTimeline/drop()[Test_game_fla.MainTimeline::frame1:38]"
Here is my code:
var s = 0;
score.text = s;
var mixed:Array = new Array;
mixed.push(orange);
mixed.push(cheese);
mixed.push(lobbio);
mixed.push(meat);
mixed.push(fish);
for (var i:uint = 0; i < mixed.length; i++) {
mixed[i].addEventListener(MouseEvent.MOUSE_DOWN, drag);
mixed[i].addEventListener(MouseEvent.MOUSE_UP, drop);
function drag(e)
{
e.target.startDrag();
}
function drop(e)
{
e.target.stopDrag();
if( (cheese.y > 50 && cheese.y < 150) && (cheese.x > 480 && cheese.x < 570) )
{
cheese.x = -50;
cheese.y = -50;
s = s + 10;
score.text = s;
}
if( (mixed[i].y > 50 && mixed[i].y < 150) && (mixed[i].x > 480 && mixed[i].x
< 570) )
{
mixed[i].y = -50;
mixed[i].x = -50;
s = s + 10;
score.text = s;
}
}
}

To explain what your actual problem is, it's the use of inline functions.
Inside your for loop, you define some functions (those are referred to as inline functions, and as mentioned in VC.One's answer, this is not a good practice - please follow their other advice as well).
Since those functions are defined inside the for loop block, every iteration you are actually creating a whole new function/object. When you create those functions, the ones called drop are referencing your iterator (i). BUT, those functions are not actually called until you MOUSE_UP. This mouse up trigger will happen long after the for loop has finished. At which point i will have a value of 5. Why 5? (as it only iterates from 0 - 4), because after every iteration i is incremented, so it will end up 1 higher than the last iteration.
Since there is no element at position 5 in your mixed array, you get the error.
To rectify the situation, follow the code example from the other answers (which break those functions out of the for loop)
Instead of referencing i, use the event's currentTarget property (which is a reference to the object that you attached the listener to).
Sprite(e.currentTarget).y

U can fix it like this.
var s = 0;
score.text = s;
var mixed:Array = new Array;
mixed.push(orange);
mixed.push(cheese);
mixed.push(lobbio);
mixed.push(meat);
mixed.push(fish);
for (var i:uint = 0; i < mixed.length; i++) {
mixed[i].addEventListener(MouseEvent.MOUSE_DOWN, drag);
mixed[i].addEventListener(MouseEvent.MOUSE_UP, drop);
}
function drag(e)
{
e.currentTarget.startDrag();
}
function drop(e)
{
var mix:Sprite = Sprite(e.currentTarget);
mix.stopDrag();
if( (cheese.y > 50 && cheese.y < 150) && (cheese.x > 480 && cheese.x < 570) )
{
cheese.x = -50;
cheese.y = -50;
s = s + 10;
score.text = s;
}
//Error in mixed[i] ; at last i = mixed.length mixed[i] is null.
//Event has a property "currentTarget" this can get u select target
if( (mix.y > 50 && mix.y < 150) && mix.x > 480 && mix.x < 570) )
{
mix.y = -50;
mix.x = -50;
s = s + 10;
score.text = s;
}
}

Some things to fix :
(1) Give your variables a data type. Saying var s = 0; suggests that s is a numerical variable, right? Well score.text expects a String not Number so you must use casting to convert. Try :
var s : int = 0; //define a numerical variable
score.text = String(s); //cast number into String type (for usage as text)
(2) Don't put your functions inside a For-loop!!! Don't even put functions inside other functions (unless you know what an Anonymous Function is, and you can justify needing it).
(3) You can shorten some code typing by :
Incrementing? Use s += 10 to avoid longer s = s + 10;. Can also be -=, /= etc.
If setting same value to multiple variables just chain like so: cheese.x = cheese.y = -50;
(4) Don't try to access mixed[i] by mixed.length. Since length is 5 at some point the compiler sees an instruction like : mixed[5].addEventListener...
However an array starts at zero for first item so you should understand the fifth item is really at mixed[4].addEventListener....
That other mixed[5].something (same as : mixed[mixed.length].something) does not exist.
PS : I would have thought that setting i < mixed.length would have protected against going over the array size, since if i must be smaller than .length then i == 5 could never happen.
Anyways... This code below is untested (no AS3 compiler here) but try the following :
var s : int = 0;
score.text = String(s);
var mixed:Array = new Array;
mixed.push(orange); mixed.push(cheese);
mixed.push(lobbio); mixed.push(meat); mixed.push(fish);
for (var i:uint = 0; i <= (mixed.length-1); i++)
{
mixed[i].addEventListener(MouseEvent.MOUSE_DOWN, drag);
mixed[i].addEventListener(MouseEvent.MOUSE_UP, drop);
} //end "For" loop
function drag(e) : void { e.target.startDrag(); }
function drop(e) : void
{
e.target.stopDrag();
if( (cheese.y > 50 && cheese.y < 150) && (cheese.x > 480 && cheese.x < 570) )
{
cheese.x = cheese.y = -50;
s += 10; //# achieves same thing as... s = s + 10;
score.text = String(s);
}
if( (Sprite(e.currentTarget).y > 50 && Sprite(e.currentTarget).y < 150) && (Sprite(e.currentTarget).x > 480 && Sprite(e.currentTarget).x < 570) )
{
Sprite(e.currentTarget).x = Sprite(e.currentTarget).y = -50;
s += 10;
score.text = String(s);
}
} //end Function "drop"

Related

Flash hangs when I execute this particular loop

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

AS3 hittest keeps hitting

I have the following problem:
I want to keep a score when i "hittest". I use the following code:
private function fnMoveMap():void
{
for (var i:int = 0; i < vPipeMax; i++)
{
var tmpPipe = _conMap.getChildAt(i);
//trace (tmpPipe.name);
if (tmpPipe._HIT.hitTestPoint(_P.x, _P.y, true))
{
tmpPipe.visible = false;
//stage.removeEventListener(Event.ENTER_FRAME, setScore);
vScores++;
txtScores.text = vScores.toString();
//break;
}
//reset pos
if (tmpPipe.x < 0)
{
//stage.addEventListener(Event.ENTER_FRAME, setScore);
tmpPipe.visible = true;
tmpPipe.x = 1050 - vXSpeed;
tmpPipe.y = randomRangeMC(minPipeY, maxPipeY);
//set score
//vScores++;
//txtScores.text = vScores.toString();
}
else
{
tmpPipe.x -= vXSpeed;
}
}
}
the var vScores keeps counts for 4 to 8 times.
How can i just count one?
The reason your vScores variable is incrementing by 4-8 is because you're looping multiple times with the for loop through vPipeMax.
You either need to restructure your code so that doesn't happen, or break out of the loop as soon as you increment the score.
Adobe's documentation on break: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/statements.html#break

as3 var not listening to x--

So Ive got this code:
function speedUp():void
{
trace ("speed", playerSpeed);
//checks if any boosts are on
if (boostCheck == false) {j = playerSpeed}
//making speed limit
if (playerSpeed < speedLimit)
{
playerSpeed ++;
}
//increasing speed limit
if (speedLimitInc == 100)
{
speedLimit++;
speedLimitInc = 1;
}
trace ("______________j", j);
speedLimitInc ++;
if (boostCheck == true)
{
for (var i:int = boost.length-1; i>=0; i--)
{
var tempBoostN:int = boost[i];
trace ("__________tempBoostN", tempBoostN);
if (tempBoostN >= 0)
{boostCheck = true; colBoolean = false; tempBoostN--;}
else
{
boostCheck = false;
player.y = player.height + 30;
colBoolean = true;
}
if (playerSpeed >= j)
{
if (tempBoostN >= 150)
{
playerSpeed = playerSpeed -1;
} else if (tempBoostN <= 150 && tempBoostN >= 30) {
playerSpeed = playerSpeed - 2;
}
tempBoostN--;
}
}
}
}
Im getting a problem with tempBoostN variable, more to point, its not listening to commands. When the var is, say, 200 (its defined as an int) and I do tempBoostN-- like you see in code, it just stays 200.
I have tried defining the var as a Number as etc.. but it stays the same.
I have also checked that the 200 is actually a Number not a string (if var is int the it cant hold a string, right?) by doing trace(temBoostN - 1); and that worked.
CODE EXPLANATION:
Function handles playerSpeed, first it does usual behaviour (increasing the speed and stuff).
After that (the part where I get the problem) checks for speed boosts activated and for each it decreases the speed back to normal speed when the boost is deactivated. var j holds playerSpeed without any boosts and is used to check if boosts ran out.
All the vars in the code are defined and working properly.
I think what you actually want to do is get the decrement reflected in boost[i]. What is the type of 'boost[i]'. I believe it's int and that's why changing tempBoostN isn't changing boost[i]. There are 2 ways around it:
(1) You put Number in boost[i], so tempBoostN = boost[i] is a assignment by reference as against a value copy being done in case of int
(2) re-assign boost[i] = tempBoostN at the end of loop.

AS3: Vector item isn't spliced

Hello I am creating a system with a gun that shoots bullet.
The update function is processed this way:
var b:Bullet;
var l:uint = bulletList.length;
var i:uint;
for (i = 0; i < l; i++) {
b = bulletList[i];
b.sprite.x += b.vx;
b.sprite.y += b.vy;
if (b.sprite.x > 1200 || b.sprite.x < -100 || b.sprite.y < -1000) {
deleteBullet(b);
bulletList.splice(i,1);
}
}
public function deleteBullet(b:Bullet) {
b.sprite = null;
b = null;
}
When I shoot a bullet and it goes of the edge it generates an error, and sometimes it creates a new one but that one doesn't have any motion at all. This is the error I get:
RangeError: Error #1125: The index 1 is out of range 1.
You're getting that error because you're splicing your array while in a for loop.
instead of using 'l' as your parameter for the for loop, use bulletList.length directly as every iteration it will look at the CURRENT length which will reflect anything spliced out of it. You'll also need subtract your iterator when splicing as that shifts all future indexes down by one.
for (i = 0; i < bulletList.length; i++) {
b = bulletList[i];
b.sprite.x += b.vx;
b.sprite.y += b.vy;
if (b.sprite.x > 1200 || b.sprite.x < -100 || b.sprite.y < -1000) {
deleteBullet(b);
bulletList.splice(i,1);
i--;
}
}

See if children of movieclip on stage

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