AS3 Error 1063 - with (seemingly) correct number of Arguments - actionscript-3

So I've been toying with the idea of building a game, and at this point I'm just trying to get a basic framework down for a tile-based over-world, like in Pokemon or others.
The issue I'm having now is an absurd one; after fixing several other errors I'm still getting ArgumentError #1063 in two different places, and in both cases I pass the right amount of arguments in (both are constructors) and the error tells me I passed in 0.
Here's pertinent code for the first one:
public function Main()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, act, false, 0, true);
key = new KeyObject(stage);
overWorld = new Map(stage);
stage.addChild(overWorld);
}
(overWorld is a Map var, declared above with public var overWorld:Map;)
and:
public function Map(stageRef:Stage)
{
key2 = new KeyObject(stageRef);
currentMap = MapArrays.testMap;
x = 0;
y = 0;
initializeTiles();
}
I'm calling the Map() constructor with the stage reference that it needs, and it's spitting out this as the error:
ArgumentError: Error #1063: Argument count mismatch on Map(). Expected 1, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Main()
In addition, that initializeTiles() function holds the second of these two errors. Here's the code for that:
public function initializeTiles()
{
for(var i:int = 0; i < 25; i++)
{
for(var j:int = 0; j < 20; j++)
{
var temp:String = ("tile"+i+"_"+j);
this[temp] = new Tile(currentMap, (i+10), (j+10), (i * 30), (j * 30))
}
}
}
and the Tile() constructor:
public function Tile(mapArr:Array, inX:int, inY:int, xpos:int, ypos:int)
{
mapArray = mapArr;
arrX = inX;
arrY = inY;
x = xpos;
y = ypos;
determineTile();
}
This is the error that spits out (500 times, 20x25):
ArgumentError: Error #1063: Argument count mismatch on Tile(). Expected 5, got 0.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at Map()
at Main()
Just to explain some, mapArr/mapArray/currentMap are Arrays of ints that describe the active mapset, inX/arrX is the x location of a given tile within the map (inY/arrY is of course the y location), and xpos and ypos are just where the tile sits on the screen (each tile is 30px by 30px). determineTile() just looks up the int mapArray[arrX][arrY] and changes the tile's attributes and image accordingly. MapArrays is a public dynamic class I created and imported in the Map class with import MapArrays;
Anyways, any help with this issue would be much appreciated. I can edit to post more code if someone thinks there may be an issue somewhere else, but these are the only places the constructors are called and the first 501 errors in my output (there are a few more, but they are because these constructors failed as they are null reference errors). I've been stuck here for a hefty chunk of time tweaking things slightly and nothing has worked thus far, and I don't see anywhere else where someone is getting this error while using the right amount of arguments.
Thanks in advance.

If you have any Tile or Map instances placed on the stage, those instances would be instantiated by Flash at run-time by calling the constructor (just like when you create an instance of Tile by calling new Tile(...).
Since your Tile and Map classes have custom constructors (that take parameters), Flash cannot create an instance of those display objects because it doesn't know what to pass as input parameters to the constructor - this is why you get the error.
Usually it's best not to put anything on the stage that has code backing it up - just create those instances from code and add them to the stage at run-time. This is extra work but it keeps your setup cleaner.

Related

Actions with a list of instances - AS3

what is the best way to do an action with many instances at the same time?
Lets say I have 50 movieclip instances called A1 to A50, and I want to run an action with only A20 to A35.
For example:
(A20-A35).gotoAndStop(2)
You want an algorithm operation called loop. You are not able to abstractly address things in bunches at once, but you can loop and iterate the bunch one by one which produces basically the same result. Please read this: https://en.wikipedia.org/wiki/Control_flow#Loops When you need to do a quantity of similar operations it is always loop.
With regard to your problem:
// Loop iterator from 20 to 35 inclusive.
for (var i:int = 20; i <= 35; i++)
{
trace("");
// Compose the name of the MovieClip to retrieve.
var aName:String = "A" + i;
trace("Retrieving the MovieClip by name", aName);
// Retrieve the instance by its instance name.
var aChild:DisplayObject = getChildByName(aName);
// Sanity checks about what exactly did you find by that name.
if (aChild == null)
{
// Report the essence of the failure.
trace("Child", aName, "is not found.");
// Nothing to do here anymore, go for the next i.
continue;
}
else if (aChild is MovieClip)
{
// Everything is fine.
}
else
{
// Report the essence of the failure.
trace("Child", aName, "is not a MovieClip");
// Nothing to do here anymore, go for the next i.
continue;
}
// Type-casting: tell the compiler that the child is actually
// a MovieClip because DisplayObject doesn't have gotoAndStop(...)
// method so you will get a compile-time error even if you are
// sure the actual object is a valid MovieClip and definitely has
// the said method. Compile-time errors save us a lot of pain
// we would get from run-rime errors otherwise, so treasure it.
var aClip:MovieClip = aChild as MovieClip;
trace(aClip, "is a MovieClip and has", aClip.totalFrames, "frames.");
if (aClip.totalFrames < 2)
{
// Nothing to do here anymore, go for the next i.
continue;
}
// Now you can work with it.
aClip.gotoAndStop(2);
}
Now that you understand the while idea step by step, if you are sure all of them are present and all of them are MovieClips you can go for a shorter version:
for (var i:int = 20; i <= 35; i++)
{
(getChildByName("A" + i) as MovieClip).gotoAndStop(2);
}
UPD: You can as well address children with square bracket access operator.
for (var i:int = 20; i <= 35; i++)
{
// You can skip type-casting as this["A" + i] returns an untyped reference.
this["A" + i].gotoAndStop(2);
}
Yet there are differences and complications. Method getChildByName(...) always returns a DisplayObject with the given name (or null if none found). Square brackets operator returns an untyped OOP field of the current object.
It will not work with dynamically added children (unless you pass their references to the respective fields).
It will not work if "Automatically Declare Stage Instances" publish option is off.
Finally, this["A" + 1] and A1 are not exactly the same because the latter could refer to a local method variable rather than object member.
I'm not saying that square brackets are evil, they're as fine, yet, as always, programming is not a magick thus understanding what you are doing is the key.

Actionscript3 to Arduino: sending a 'newline' character after an array of integers

I want to send an array of integers from an as3 app I'm writing in Flash Pro, to an Arduino Uno which will use them to continuously position and re-position 5 servos. So sending 15 integers will position the 5 servos, then re-position them, then reposition them again, then loop back to the first position and so on. Then I would send a new array replacing the old one whenever I wanted to.
So I've got my tinkerproxy configured between them ok (thanks to Mike Chambers and others) and I've written both sides so they appear to work ok when interfacing with their serial monitors. But I can't get em talking to each other properly.
My problem is simple ... I think ... It's how to get as3 to send a 'newline' or some other 'end' signal with or after the array so that the Arduino sketch (using serialEvent and parseInt to get the integers when they are sent), on receiving it, can jump past parseInt and do something else - in this case go to the loop and control these pesky servos.
Probably far too much code attached and I hope somebody can help. I'm pretty inexperienced, you may have guessed....
ARDUINO
/*
this sketch developed from arduino Tutorials ReadASCIIString + SerialEvent
serialEvent can receive an array - 'buff' - of values from serial monitor
loop can get those values and print some of them to prove it
but I can't get Flash Pro (as3) to send the array: something to do with end of message character?
*/
#include <Servo.h>
int buff[100];//an array to hold integers from serial(arbitrary larger than ever needed size)
int j; //used to increment serial integer receipt in serialEvent
int patternLength;//=# of integers delivered over serial port, if followed by E or newline
void setup()
{
Serial.begin(9600);
Serial.setTimeout(2147483647);//25 days! so parseInt doesn't default to sending zeros every second
Serial.println("ready to go");//prints ok
}
void loop()
{
for(int i=0; i<patternLength-4; i=i+5)//feed sets of 5 integers into 5 servos then repeats
Serial.println(buff[i]);//prints 1st, 5th, 10th etc integer then repeats
delay(1000);//so I can see it happening slowly enough
}//loops indefinitely until serialEvent interrupts to send new buff array values
void serialEvent()
{
while(Serial.available()>0)
{
buff[j] = Serial.parseInt();
Serial.println(buff[j]);//prints all integers sent if eg ','sent after last one
j++;
//if (Serial.read() == '\n')//works if serial monitor is set to 'newline' on sending
if (Serial.read() == 'E')//works if no 'newline' + sending eg 1,2,3,4,5,6,7,8,9,10E
//BUT how to send the equivalent of one of the above two 'endings' from Flash???
//so that this part of the code executes
{
patternLength = j;
Serial.println("go to loop");
j=0;//reset the index so next array sent replaces this one in 'buff'
}
}
}
FLASH PRO ACTIONSCRIPT as3
/*
Simple Example that connects to an Arduino (via TinkerProxy) and sends
an array of integers for it to use. That doesn't work......
adapted from FlashBlink Created by Mike Chambers:
http://www.mikechambers.com/blog/2010/08/04/getting-started-with-flash-and-arduino/
*/
import flash.events.Event;
import flash.display.Sprite;
import flash.net.Socket;
//import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
//import flash.events.SecurityErrorEvent;
import flash.utils.Endian;
import flash.events.MouseEvent;
//my example of an array of integers I want to send to the arduino
var pattern:Array = [10,11,12,13,14,15,16,17,18,19,20];
//socket we will use to connect to TinkerProxy
var _socket:Socket;
//Address where TinkerProxy is located. Will usually be
//localhost / 127.0.0.1
var _proxyAddress:String = "127.0.0.1";
//port TinkerProxy is listening on
var _proxyPort:uint = 5331;
function onAddedToStage():void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
//create a Sprite to add to the stage.
//This will be a simple button
var s:Sprite = new Sprite();
//draw a green square in the Sprite
s.graphics.beginFill(0x00FF00);
s.graphics.drawRect(0,0, 200,100);
s.graphics.endFill();
//Add Sprite to the display list
addChild(s);
//position it
s.x = 50;
s.y = 50;
//listen for when the user clicks the Sprite
s.addEventListener(MouseEvent.CLICK, onClick);
_socket = new Socket();
//Register for socket events
//socket connected
_socket.addEventListener( Event.CONNECT, onConnect );
//socket closed
_socket.addEventListener( Event.CLOSE, onClose );
_socket.endian = Endian.LITTLE_ENDIAN;
//connect
_socket.connect(_proxyAddress, _proxyPort);
}
//called when we connect to the proxy server
function onConnect(event:Event):void
{
trace("Socket Connected");
}
//called when the user clicks the button on stage
function onClick(event:MouseEvent):void
{
trace("onClick");
//make sure we are connected to the socket
if(!_socket.connected)
{
//if not, don't do anything
trace("You must be connected to send a command to the Arduino.");
return;
}
var ENDOF:String = "E";
for(var j:int = 0; j < pattern.length; j++)
{
_socket.writeUTFBytes(pattern[j]); //send pattern array to Arduino
trace(pattern[j]);//trace what I think I've just sent
}
//then send something as a last character - not an integer.
_socket.writeUTFBytes(ENDOF);//send this string value to arduino
trace("should have just sent an E, and sends an: " + ENDOF);
//but how do I send this E conjoined to the last integer of the pattern array
//so that Arduino responds by jumping out of serialEvent back to the loop?
//flush the socket. Not really necessary, but here for forward compatibility.
_socket.flush();
}
//called when the socket is closed
function onClose(event:Event):void
{
trace("Socket Closed");
}
onAddedToStage();
Your AS3 looks fairly spot on. One minor point, in onAddedToStage() you're removing an event listener from the stage which you never registered for. If you really want that code to only fire once the timeline is added to the stage, replace line 114 with with following:
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage)
As for your Arduino code , I'm not versed in the language it uses (some sort of C?), so feel free to ignore the following if you know better.
You didn't encapsulate your for loop on lines 22 thru 24
You started encapsulating your while loop on line 30, but forgot to close it on line 34
You declared j, but didn't initialized its value until line 44 after it was to be used in your while loop on line 33.
Finally, to answer your core question. You're already aware a newline is written as \n, so it would seem you're having difficulty reading this from Serial.read(). After reading the documentation, I couldn't find any datatype it comes out as, so I'm assuming you're dealing with either a ByteArray or a String. Assuming it's a string, my first instinct would be to just split it into an Array with String.split(), but that's not a function available to String API. Others (however) have written it, and I believe it would simplify the issue, assuming Strings & Ints can happily co-exist in those object types.
Conversely, since you already know the size of these numbers come in quintets, rather than use a while loop (line 29), you could just use a for as follows:
#include <Servo.h>
int buff[100];
int j;
int patternLength;
void setup() {
Serial.begin(9600);
Serial.setTimeout(2147483647);
Serial.println("ready to go");
}
void loop() {
for(int i=0; i<patternLength-4; i=i+5) {
Serial.println(buff[i]);
delay(1000);
}
}
void serialEvent() {
if (Serial.available() > 0) {
// This gaurantees we only pull the first 15 Ints into our buff array
for (int k=0; k<15; k++) {
buff[j] = Serial.parseInt();
Serial.println(buff[j]);
j++;
}
patternLength = j;
Serial.println("go to loop");
j=0;//reset the index so next array sent replaces this one in 'buff'
}
}
If the above misses the mark for you, you may want to debug the value you're actually reading from the Stream and testing for in your if statement on line 37 with:
Serial.println("Reading: " + Serial.read());
Hope it helps.
-Cheers

ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.

Please, I need help trying to remove bullets and enemies from my stage. I am very new to programming. Thank you.
I receive the following error message:
ArgumentError: Error #2025: The supplied DisplayObject must be a child
of the caller. at flash.display::DisplayObjectContainer/removeChild()
at Main/fl_EnterFrameHandler() at
flash.utils::Timer/_timerDispatch() at flash.utils::Timer/tick()
The code where debug sent me.
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class Main extends MovieClip
{
var enemyShipTimer:Timer;
var coinTimer:Timer;
var playerscore:Number = 0;
var enemies:Array;
var bullets:Array;
public function Main()
{
enemyShipTimer = new Timer(1000);
enemyShipTimer.addEventListener("timer", fl_EnterFrameHandler);
enemyShipTimer.start();
coinTimer = new Timer(1000);
coinTimer.start();
enemies = new Array ();
bullets = new Array ();
}
function fl_EnterFrameHandler(event:Event):void
{
var enemyinstance = new enemy_ks();
stage.addChild(enemyinstance);
enemies.push(enemyinstance);
trace(enemies.length);
for (var count=0; count<enemies.length; count++)
{
for (var bcount=0; bcount<bullets.length; bcount++)
{
if (enemies[count].hitTestObject(bullets[bcount]))
{
removeChild(enemies[count]);
enemies.splice(count, 1);
removeChild(bullets[bcount]);
bullets.splice(bcount, 1);
}
}
score_ks.text = " " + playerscore;
}
}
}
}
EDIT: Reread your code and noticed the real error is actually that you are adding to the stage but removing from your Main sprite. You need to match those up. You cannot remove an object from a parent if it is not actually a child of that object.
The points below still need to be addressed as well, otherwise you may end up with other errors.
Your issue is with your loop. In your loop, you adjust the array length on each successful hit test but you never adjust the count of the loop.
So think of it like this.
You start with:
count = 0;
length = 10;
Now say you run a loop for count < length and you splice at count == 4 and count == 7. In your current scheme, you will only hit the following objects (using the original index)
0 1 2 3 4 6 7 9
Notice that you don't hit index 5 or 8. When you modify the array like that and don't modify the count, you end up skipping over certain items. After splicing index 4, the original index 5 moves to 4 and everything else moves back one as well. So when you move to index 5, you are actually reading the original index 6.
Very simple fix for this is to just adjust your counts as you splice.
if (enemies[count].hitTestObject(bullets[bcount]))
{
removeChild(enemies[count]);
enemies.splice(count, 1);
count--; //subtract 1 from the count
removeChild(bullets[bcount]);
bullets.splice(bcount, 1);
bcount--; //subtract 1 from the bcount
}
That will ensure your count actually hits every object. You could also use a for each loop to handle this, though that type of loop is slower than a standard for loop depending on application.
Additionally, a DisplayObject can only be removed from a DisplayObjectContainer if it is actually a child of that container. If it is not, it will error out. So I believe you may also be running into an issue where your array does not fully line up with what is on the stage and you are trying to remove an object that doesn't actually exist as a child of the parent
As a minor aside, you should avoid adding children directly to the stage unless you have a real reason to do so. Instead, add it directly to the application object's display list using the this keyword, or simply addChild().

Supplied DisplayObject must be a child of the caller

I get this error once in a while for a specific object. For some reason, this issue seems to start when I spawn 2 of this object instead of one. I basically have enemies that drops coins and one enemy drops 2. When I pick them up at the same time I start getting this error.
public function removeCoin(){
removeEventListener(Event.ENTER_FRAME, moveCoin);
if(this.parent){
this.parent.removeChild(this);
}
parentMC.level.spawnedCoins.splice(this, 1);
}
This is the function called by the collision check when there is a collision between the player and the coin. The issue usually starts when I pick up two coins at once from this function.
var dropCoin:Number = Math.random() * 100;
if(dropCoin > 40){
var newCoin1:coin = new coin(parentMC);
var newCoin2:coin = new coin(parentMC);
newCoin1.x = x+7;
newCoin1.y = y;
parentMC.level.levelObjects.addChild(newCoin1);
parentMC.level.spawnedCoins.push(newCoin1);
newCoin2.x = x-7;
newCoin2.y = y;
parentMC.level.levelObjects.addChild(newCoin2);
parentMC.level.spawnedCoins.push(newCoin2);
}
Edited the code.
That error means that the item you're trying to remove from the display list (by calling removechild) either isn't on the display list, or isn't a child of the object your calling removeChild on.
Without analyzing all your code, a quick check can fix your problem likely.
Change you existing chunk of code:
if(this != null){
parentMC.lvl1.levelObjects.removeChild(this);
}
to this:
if(this.parent){
this.parent.removeChild(this);
}
This checks if 'this' has a parent, if so, it removes itself from it's parent.
I think your problem might be:
parentMC.level.spawnedCoins.splice(this, 1);
If spawnedCoins is just an array then splice should take 2 integer args startIndex and deleteCount relevant adobe help page
By passing an object what I think is happening is that it is casting the object to an int, value of '1' (i.e. not null).
What I think you want instead is parentMC.level.spawnedCoins.splice(parentMC.level.spawnedCoin.indexOf(this), 1);

stage.removeChild throwing an error

I've built a simple snake game that uses a Main class (this is my document class), a Snake class and a Food class. The Main class makes a new object of the Snake class, and another of the Food class. Within both the Snake and Food classes, I'm making sprites like so:
var segment:Sprite = new Sprite();
segment.graphics.beginFill(0xFFFFFF);
segment.graphics.drawRect(0, 0, 10, 10);
segment.filters = [new GlowFilter(0xFF6699, .50, 3, 3, 2, 2, false, false)];
segment.graphics.endFill();
segment.x = x;
segment.y = y;
this.stage.addChild(segment);
this.segments.push(segment);
The snake's body is stored in an array of sprites called segments. You can see from that code I'm making a new sprite to extend the length of the snake and pushing it to the segments array. I do something similar for any food items, except within the food class I've defined the food sprite as public var foodSprite:Sprite; because I only need one on the stage at a time.
Now, when I call the gameOver() method from the Main class (where I have my game loop), I want to call stage.removeChild() on each of the snake segments and the food sprite. I tried doing this:
for(var i:Number = 0; i < this.snake.segments.length; i++)
{
stage.removeChild(this.snake.segments[i]);
}
But I get this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main/gameOver()
From what I know this should work, as this.snake.segments[i] points to a sprite, the one which I want to remove from the stage.
What could be going wrong here? Thank you.
EDIT: I guess it's also worth noting that segments is defined as:
public var segments:Array = new Array;
Please see comments on this answer for the actual solution.
Try this:
for(var i:Number = 0; i < snake.segments.length; i++)
{
var seg:Sprite = snake.segments[i] as Sprite;
if(seg.parent)
seg.parent.removeChild(seg);
}