I am on an Autonomous GPS robot project. When I am running the below code after some time the esp32(devkit v1) reboots and this goes on repeating.
Pause for Startup... 3
Pause for Startup... 2
Pause for Startup... 1
Searching for Satellites
Searching for Satellites
GPS Waypoint 1 Set Waypoint #1: 0.000000 , 0.000000
Waypoint #2: 0.000000 , 0.000000
5 Satellites Acquired10.190620
76.424872
25.190620
47.424872
YOYYYYO
Go to Waypoint
E (98333) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (98333) task_wdt: - async_tcp (CPU 0/1)
E (98333) task_wdt: Tasks currently running:
E (98333) task_wdt: CPU 0: IDLE0
E (98333) task_wdt: CPU 1: async_tcp
E (98333) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x40148e07:0x3ffbc0d0 0x400df42b:0x3ffbc0f0 0x4008ab01:0x3ffbc110 0x4008930d:0x3ffbc130
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
Welcome
Autonmous Mode Initiated...
IP Address: 192.168.1.18
Compass setting done
iam here1
Pause for Startup...
Pause for Startup... 10
Pause for Startup... 9
Pause for Startup... 8
YOYYYYO
Go to Waypoint
Pause for Startup... 7
Pause for Startup... 6
Pause for Startup... 5
Pause for Startup... 4
Pause for Startup... 3
E (10128) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10128) task_wdt: - async_tcp (CPU 0)
E (10128) task_wdt: Tasks currently running:
E (10128) task_wdt: CPU 0: Tmr Svc
E (10128) task_wdt: CPU 1: IDLE1
E (10128) task_wdt: Aborting.
abort() was called at PC 0x400de07b on core 0
Backtrace: 0x4008cbf8:0x3ffbe170 0x4008ce29:0x3ffbe190 0x400de07b:0x3ffbe1b0 0x40084f01:0x3ffbe1d0 0x4000bfed:0x3ffbd060 0x4008a489:0x3ffbd070 0x400827d1:0x3ffbd090 0x40082843:0x3ffbd0b0 0x4008b825:0x3ffbd0d0 0x4008b924:0x3ffbd100 0x4008930d:0x3ffbd130
Rebooting...
ets Jun 8 2016 00:22:57
This is the msg that appears on the serial monitor. I tried debugging but can't find why this is happening.
The Code is really big, so I have uploaded only a part of it.
// CompaSerial Variables & Setup
HMC5883L compass;
int16_t mx, my, mz; // variables to store x,y,z axis from compass (HMC5883L)
int desired_heading; // initialize variable - stores value for the new desired heading
int compass_heading; // initialize variable - stores value calculated from compass readings
int compass_dev = 5; // the amount of deviation that is allowed in the compass heading - Adjust as Needed
// setting this variable too low will cause the robot to continuously pivot left and right
// setting this variable too high will cause the robot to veer off course
int Heading_A; // variable to store compass heading
int Heading_B; // variable to store compass heading in Opposite direction
int pass = 0; // variable to store which paSerial the robot is on
//*****************************************************************************************************
// GPS Locations
unsigned long Distance_To_Home; // variable for storing the distance to destination
int ac =0; // GPS array counter
int wpCount = 0; // GPS waypoint counter
double Home_LATarray[2]; // variable for storing the destination Latitude - Only Programmed for 5 waypoint
double Home_LONarray[2]; // variable for storing the destination Longitude - up to 50 waypoints
int increment = 0;
//*****************************************************************************************************
// HTML Page
AsyncWebServer server(80);
const char* ssid = "******";
const char* password = "******";
const char* PARAM_INPUT_1 = "input1";
const char* PARAM_INPUT_2 = "input2";
const char* PARAM_INPUT_3 = "input3";
const char* PARAM_INPUT_4 = "input4";
const char* PARAM_COMMIT = "commit";
double lati1;
double logi1;
double lati2;
double logi2;
// HTML web page to handle 4 input fields
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<h2>Autonomus GPS Robot Car<h2>
<h3> Submit your Destination coordinates</h3>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<style>
a {
border: 10px solid powderblue;
padding: 10px;
color: red;
font-family: verdana;
font-size: 150%;
}
</style>
</head>
<body>
<form action="/get" >
<br>
Waypoint 1 Latitude : <input type="text" name="input1">
<br>
<br>
Waypoint 1 Longitude: <input type="text" name="input2">
<br><br>
<br>
Waypoint 2 Latitude : <input type="text" name="input3">
<br>
<br>
Waypoint 2 Longitude: <input type="text" name="input4">
<br><br>
<input type="submit" value="Submit">
<br>
<br><br>
<br><br>
<a href="/go" >Go to Destination</a>
<br><br> <br><br>
<br><br>
<a href="/clear" > Clear waypoints</a>
</form>
</body>
</html>)rawliteral";
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
//*****************************************************************************************************
// Extras
#define autopilot 18
void gesturecontroll();
void getGPS();
void getCompass();
void Forward();
void Forward_Meter();
void Reverse();
void LeftTurn();
void RightTurn();
void SlowLeftTurn();
void SlowRightTurn();
void StopCar();
void setWaypoint();
void move();
void Startup();
void goWaypoint();
void clearWaypoints();
int blueToothVal;
int flag=0;
int button;
void setup()
{ Serial.begin(115200); // Serial 0 is for communication with the computer
Serial.println("Welcome");
pinMode(autopilot, INPUT);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
button = digitalRead(autopilot);
if (button == HIGH)
{ flag=15;
Serial.println("Manual Control initated");
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
// This is the mac address of the Slave in AP Mode
esp_wifi_set_mac(ESP_IF_WIFI_STA, &mac[0]);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
if (esp_now_init()!=0)
{
Serial.println("*** ESP_Now init failed");
while(true) {};
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
Serial.print("Aheloiioi"); // the remaining code for above part is not uploaded since when switch is pulled this part of code works perfectly
}
else{
S2.begin(9600, SERIAL_8N1, RXPin, TXPin); // Serial 2 is for GPS communication at 9600 baud - DO NOT MODIFY - Ublox Neo 6m
flag=0;
// pinMode(LED_BUILTIN, OUTPUT); // An LED indicator - Not Used
Serial.println("Autonmous Mode Initiated...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
CompaSerial////////////////////////////////////////////////////////////////////////////////////
Wire.begin(); // Join I2C bus used for the HMC5883L compass
//compass.init();
compass.begin(); // initialize the compass (HMC5883L)
compass.setRange(HMC5883L_RANGE_1_3GA); // Set measurement range
compass.setMeasurementMode(HMC5883L_CONTINOUS); // Set measurement mode
compass.setDataRate(HMC5883L_DATARATE_30HZ); // Set data rate
compass.setSamples(HMC5883L_SAMPLES_8); // Set number of samples averaged
compass.setOffset(0,0);
Serial.println("Compass setting done");
Startup(); // Run the Startup procedure on power-up one time
}
}
// Main Loop
void loop()
{ button = digitalRead(autopilot);
if (button == HIGH && flag==15)
{
}
else
{ Coordinates();
getGPS(); // Update the GPS location
getCompass(); // Update the CompaSerial Heading
//Ping(); // Use at your own discretion, this is not fully tested
}
}
void Coordinates()
{ Serial.println("i am here1");
// Send web page with input fields to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
// Send a GET request to <ESP_IP>/get?input1=<inputMessage>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
if (request->hasParam(PARAM_INPUT_2)||request->hasParam(PARAM_INPUT_1) ) {
// GET input1 value on <ESP_IP>/get?input1=<latitude>
latitude1 = request->getParam(PARAM_INPUT_1)->value();
latitude1Param = PARAM_INPUT_1;
// GET input2 value on <ESP_IP>/get?input2=<longitude>
longitude1 = request->getParam(PARAM_INPUT_2)->value();
longitude1Param = PARAM_INPUT_2;
// GET input3 value on <ESP_IP>/get?input3=<latitude>
latitude2 = request->getParam(PARAM_INPUT_3)->value();
latitude2Param = PARAM_INPUT_3;
// GET input4 value on <ESP_IP>/get?input4=<longitude>
longitude2 = request->getParam(PARAM_INPUT_4)->value();
longitude2Param = PARAM_INPUT_4;
}
else {
latitude1 = "No message sent";
latitude1Param = "none";
longitude1 = "No message sent";
longitude1Param = "none";
latitude2 = "No message sent";
latitude2Param = "none";
longitude2 = "No message sent";
longitude2Param = "none";
}
Serial.println(latitude1);
Serial.println(longitude1);
Serial.println(latitude2);
Serial.println(longitude2);
lati1=(latitude1.toFloat());
logi1=(longitude1.toFloat());
lati2=(latitude2.toFloat());
logi2=(longitude2.toFloat());
//Serial.println(lati,6);
//Serial.println(logi,6);
request->send(200, "text/html", "Command succesfuly sent""<br>Return to Home Page");
});
server.on("/go", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for go here
Serial.println("YOYYYYO");
goWaypoint();
request->redirect("/");
});
server.on("/clear", HTTP_GET, [] (AsyncWebServerRequest *request) {
//logic for clear here
Serial.println("fdfghgh");
clearWaypoints();
request->redirect("/");
});
server.onNotFound(notFound);
server.begin();
}
void getGPS() // Get Latest GPS coordinates
{ Serial.println("i am here2");
while (S2.available() > 0)
gps.encode(S2.read());
}
// *************************************************************************************************************************************************
void setWaypoint() // Set up to 5 GPS waypoints
{
//if ((wpCount >= 0) && (wpCount < 50))
if (wpCount >= 0)
{
Serial.print("GPS Waypoint ");
Serial.print(wpCount + 1);
Serial.print(" Set ");
Home_LATarray[ac] = lati1 ; // store waypoint in an array
Home_LONarray[ac] = logi1 ; // store waypoint in an array
Home_LATarray[ac] = lati2 ; // store waypoint in an array
Home_LONarray[ac] = logi2 ; // store waypoint in an array
Serial.print("Waypoint #1: ");
Serial.print(Home_LATarray[0],6);
Serial.print(" , ");
Serial.println(Home_LONarray[0],6);
Serial.print("Waypoint #2: ");
Serial.print(Home_LATarray[1],6);
Serial.print(" , ");
Serial.println(Home_LONarray[1],6);
wpCount++; // increment waypoint counter
ac++; // increment array counter
}
else {Serial.print("Waypoints Full");}
}
// *************************************************************************************************************************************************
void clearWaypoints()
{
memset(Home_LATarray, 0, sizeof(Home_LATarray)); // clear the array
memset(Home_LONarray, 0, sizeof(Home_LONarray)); // clear the array
wpCount = 0; // reset increment counter to 0
ac = 0;
Serial.print("GPS Waypoints Cleared"); // display waypoints cleared
}
// *************************************************************************************************************************************************
void getCompass() // get latest compass value
{
Vector norm = compass.readNormalize();
// Calculate heading
float heading = atan2(norm.YAxis, norm.XAxis);
if(heading < 0)
heading += 2 * M_PI;
compass_heading = (int)(heading * 180/M_PI); // aSerialign compass calculation to variable (compass_heading) and convert to integer to remove decimal places
}
void Startup()
{
Serial.println("Pause for Startup... ");
for (int i=10; i >= 1; i--) // Count down for X seconds
{
Serial.print("Pause for Startup... ");
Serial.println(i);
delay(1000); // Delay for X seconds
}
Serial.println("Searching for Satellites ");
Serial.println("Searching for Satellites ");
while (Number_of_SATS <= 4) // Wait until x number of satellites are acquired before starting main loop
{
getGPS(); // Update gps data
Number_of_SATS = (int)(gps.satellites.value()); // Query Tiny GPS for the number of Satellites Acquired
}
setWaypoint(); // set intial waypoint to current location
wpCount = 0; // zero waypoint counter
ac = 0; // zero array counter
Serial.print(Number_of_SATS);
Serial.print(" Satellites Acquired");
}
void goWaypoint()
{
Serial.println("Go to Waypoint");
//Serial.print("Home_Latarray ");
//Serial.print(Home_LATarray[ac],6);
//Serial.print(" ");
//Serial.println(Home_LONarray[ac],6);
//Serial1.print("Distance to Home");
//Serial1.print(Distance_To_Home);
//Serial1.print("ac= ");
//Serial1.print(ac);
while (true)
{ // Start of Go_Home procedure
// bluetooth(); // Run the Bluetooth procedure to see if there is any data being sent via BT
if (blueToothVal == 5){break;} // If a 'Stop' Bluetooth command is received then break from the Loop
getCompass(); // Update Compass heading
getGPS(); // Tiny GPS function that retrieves GPS data - update GPS location// delay time changed from 100 to 10
if (millis() > 5000 && gps.charsProcessed() < 10) // If no Data from GPS within 5 seconds then send error
Serial.println(F("No GPS data: check wiring"));
Distance_To_Home = TinyGPSPlus::distanceBetween(gps.location.lat(),gps.location.lng(),Home_LATarray[ac], Home_LONarray[ac]); //Query Tiny GPS for Distance to Destination
GPS_Course = TinyGPSPlus::courseTo(gps.location.lat(),gps.location.lng(),Home_LATarray[ac],Home_LONarray[ac]); //Query Tiny GPS for Course to Destination
/*
if (Home_LATarray[ac] == 0) {
Serial1.print("End of Waypoints");
StopCar();
break;
}
*/
if (Distance_To_Home == 0) // If the Vehicle has reached it's Destination, then Stop
{
StopCar(); // Stop the robot after each waypoint is reached
Serial.println("You have arrived!"); // Print to Bluetooth device - "You have arrived"
ac++; // increment counter for next waypoint
break; // Break from Go_Home procedure and send control back to the Void Loop
// go to next waypoint
}
if ( abs(GPS_Course - compass_heading) <= 15) // If GPS Course and the Compass Heading are within x degrees of each other then go Forward
// otherwise find the shortest turn radius and turn left or right
{
Forward(); // Go Forward
} else
{
int x = (GPS_Course - 360); // x = the GPS desired heading - 360
int y = (compass_heading - (x)); // y = the Compass heading - x
int z = (y - 360); // z = y - 360
if ((z <= 180) && (z >= 0)) // if z is less than 180 and not a negative value then turn left otherwise turn right
{ SlowLeftTurn(); }
else { SlowRightTurn(); }
}
} // End of While Loop
}
wdt is the watchdog timer. It's a timer that is used to detect whether your code has crashed. If it's not reset periodically it will throw an error and restart the ESP32. The timer needs to be reset frequently.
Notice that the error says that it was the async_tcp task which was running when the watchdog timer trigger. You're using the AsyncWeb server, which uses async_tcp.
When the async web server gets a page request, it calls your code. You have handlers for individual pages. Those handlers need to treat the calls to them the way we have to deal with loop() - if you spend 3 seconds or more without returning or calling delay() or yield(). This gives the underlying software the chance to reset the watchdog timer.
Review your web page handlers. Look for where you may spend a long time in them.
You'll find that you call goWayPoint() in your handler for '/go'. It has a loop in it that may block for 5 seconds. 5 seconds is too long - if that loop doesn't return or call delay() the watchdog timer will fire, which it does.
The easy fix is to add a call to delay() in the while(true) loop.
while (true)
{
delay(1);
this will let the underlying code reset the watchdog timer.
That won't help if other parts of your code (getCompass(), getGPS() or other things) take too long.
Ultimately you should refactor your code. You're doing too much work in the web server callbacks. That work should be done in independent tasks - perhaps in loop(). But that's a big project. Adding a call to delay(1) anywhere in a web server callback that you have a while loop or make take some time to do some processing is clumsy but should solve this problem.
Welcome to the String heap fracturing club:
String latitude1;
String latitude1Param;
String longitude1;
String longitude1Param;
String latitude2;
String latitude2Param;
String longitude2;
String longitude2Param;
String commitType;;
in combination with async webserver is a huge problem. I rewrote a ~15.000 lines application to get rid of strings (also in the used libraries) and since then no resets and reboots anymore. Hope this helps you in your project.
Use predifined fixed char arrays they will go to the stack and keep heap corruption low.Use functions like strcpy, strcat, itoa / atoi to build messages or retrieve values.
EDIT: replace String class with fixed char arrays example
char numBuffer [16] ={'\0'} // For 15 chars and the null terminator
char latitude1 [32] ={'\0'} // For 31 chars and the null terminator
.... some code here ....
strcpy (latitude1 , "No values here");
//or
strcpy (latitude1 , "Value 1: ");
itoa (SomeIntDataNumber, numBuffer,10);
strcat (latitude1, numBuffer) // append the converted SomeIntDataNumber
One more thing if you use memset, make sure you do proper memory management, also check the used libraries for heavy use of String class. Some libs work in a static environment quite well, using them in a web context crashes the ESP. I had to ditch some libs or at least rewrite them without String class.
Further reading: https://hackingmajenkoblog.wordpress.com/2016/02/04/the-evils-of-arduino-strings/
Final Tip: Try to commenting out / replacing with dummy chars all appearancies of the String class and try the code again.
ESP-IDF creats a watchdog timer for idle tasks in addition to any tasks doing your work. IE, it creates two extra tasks IDLE0 & IDLE 1 (one for each core), whose sole purpose is to do nothing, ie idle. These idle tasks simply feed the watchdog whenever its respective core is idling. Whenever any task, in Arduino or in ESP-IDF, as well as interrupt routines, run with a higher priority than the IDLE tasks without delaying or blocking sufficiently long/often enough (such as when executing in a tight while loop), it triggers the watchdog, because that core is now fully busy, meaning it is no longer idling often enough, meaning the idle "tasks" get starved, so they can't reset the watchdog. Your app_main() in ESP-IDF and loop() in Arduino, run with higher priorities than the IDLE tasks. This is the source of the problem.
You either have to make some call that blocks your code for atleast 10mS in sufficient intervals, or you have to call yield() or
vTaskDelay(NUMBER_OF_MILLISECONDS_TO_DELAY / portTICK_PERIOD_MS)
with a minimum of 10mS (otherwise, due to discreteness, it amounts to 0, ie no delay at all, thus won't work. You can work around this by increasing the scheduler frequency).
An alternative is fully disabling the watchdog, but this nullifies its uses.
There is a more elegant solution. If you do need something to consume all available CPU time, and don't want to bother with considerations of delay or blocking, and don't want to disable the watchdog, but don't want it to bark, then put all intensive code operations in its own function or set of functions, and call it/each using the following task creation function:
xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);
where your function has the following signature:
void someFunction(void* arg)
This won't trip the watchdog no matter what, because it uses the tskIDLE_PRIORITY priority. I'm not sure what value it has, but it seems greater than 10, because I tried 10 and it didn't work. Not sure if 11 did, which would be lower priority than the IDLE tasks. Note though, any code you place in someFunction(), won't execute at all except during times when the CPU is IDLE. So all your other code must still sleep/delay/block sufficiently enough to give it time to run. This is the ideal place for endless intensive code, such as motor control and PID control loops.
You can even do this in Arduino.
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.
I didnt know how to exactly ask the question in the title but I can explain it here. So I have this class for pawns in my game.
And in my main program i call a bunch of instances of it with different names.
var z1:ZeleniPijun = new ZeleniPijun();
var z2:ZeleniPijun = new ZeleniPijun();
Basicly I have functions for movement and other variables that I use in my code in the class.
I'm making a multiplayer game and z1 and z2 would be pawns that I move around.
Until now I have used Switch and by knowing the ID of the player and the pawn that was clicked I moved them around the board. That means I have a switch for selecting a player and a switch inside that switch for selecting a pawn. And every time it goes trough the switch it goes to the same code but with a "different name".
For example if I roll a 4 for pawn number 1 it does
z1.movePawn(4);
z1.location += 4;
and other stuff that I need it to do
and if I roll a 3 for pawn number 2 it does
z2.movePawn(4);
z2.location += 4;
and other stuff that I need it to do
I have to copy the same code 16 times and just change the name from z1 to z2 to z3 etc...
Is there anyway I can make a function that would do that for me?
Something like this:
public function doStuff(pawnName:String, number:int):void{
pawnName.movePawn(number);
pawnName.location = number;
and other stuff that I need it to do
}
and then I can just give it the parameters I want 16 times instead of copying the same code everywhere.
send to the doStuff function the object that you want to do changes like
public function doStuff(theObj:ZeleniPijun ):void{
theObj.movePawn(number);
theObj.location = number;
and other stuff that I need it to do
}
if you have many objects, put them in a collection, like an array an iterate on it something like
foreach (obj in collection){
doStuff(obj);
}
this is just more or less pseudo-code, but you get the idea
You can use the object ZeleniPijun as parameter and call the method passing the instance you want.
// example creating multiples objects
var numObjs : uint = 5;
var objectsControl : Vector.<ZeleniPijun> = new Vector.<ZeleniPijun>(numObjs);
var zeleninPijun : ZeleniPijun;
for (var i : int = 0; i < numObjs; i++)
{
zeleninPijun = new ZeleniPijun();
objectsControl[i] = zeleninPijun;
}
// if you want to animate one object
doStuff(objectsControl[0], 4);
// if you want to animate them all
for each (var zeleninPijunObj : ZeleniPijun in objectsControl)
{
doStuff(zeleninPijunObj, 4);
}
function doStuff(pawnObj:ZeleniPijun, location:int):void
{
pawnObj.movePawn(location);
pawnObj.location = location;
}
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.
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().