Probleme mit (For)Schleife

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Guten Tag,


    Mein Name lautet MrPawn.
    Und war habe ich ein Problem mit meinem Straßenreiniger Job :/


    public OnPlayerEnterCheckpoint(playerid)
    {
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !strcmp(SpawnCar_Type[GetPlayerVehicleID(playerid)], "Straßenreinigung", true))
    {
    print(".");
    DisablePlayerCheckpoint(playerid);
    DestroyDynamicObject(MuellObject[playerid]);
    new Float:Abstand = 500.0, Object = INVALID_OBJECT_ID;
    for(new i=0;i<MAX_RUBBISH;i++)
    {
    print("..");
    if(SRubbishInfo[i][RposX] == 0.0)continue;
    if(SRubbishInfo[i][RubbishObject] == INVALID_OBJECT_ID)continue;
    if(GetVehicleDistanceFromPoint(GetPlayerVehicleID(playerid), SRubbishInfo[i][RposX], SRubbishInfo[i][RposY], SRubbishInfo[i][RposZ]) < Abstand){
    print("...");
    Abstand = GetVehicleDistanceFromPoint(GetPlayerVehicleID(playerid), SRubbishInfo[i][RposX], SRubbishInfo[i][RposY], SRubbishInfo[i][RposZ]);
    Object = i;
    }
    if(Object != INVALID_OBJECT_ID) {
    SRubbishInfo[i][RubbishObject] = Object;
    print("....");
    MuellObject[playerid] = SRubbishInfo[i][RubbishObject];
    return SetPlayerCheckpoint(playerid, SRubbishInfo[i][RposX], SRubbishInfo[i][RposY], SRubbishInfo[i][RposZ], 4.5);
    }
    }
    return 1;
    }
    return 1;
    }
    Wenn man durch den Müll ( Checkpoint ) durchfährt, dann soll ein neuer kommen. Tut es aber nicht.
    Das Problem bei der ganzen sachen, ist: Jeder bereich wird aufgerufen, habs ja mit "." debuggen lassen :)

  • Überdenke deinen Quellcode:

    • Verwende GetVehicleDistanceFromPoint() einmalig und speichere das Ergebnis vor der if-Abfrage in einer Variable. So verhinderst du, dass du das Ganze doppelt berechnest. Das ist doch Unsinn!
    • So wie es mir scheint, setzt du einfach immer den selben Checkpoint. Du ermittelst keinen random Checkpoint, sondern nimmst einfach den ersten im Array, der in der Nähe ist. Daher ist auch die "Object" und "Abstand" Variable für die Tonne und unnötig.
  • Dann macht jedoch dein jetziger Quellcode keinen Sinn, denn du setzt den Checkpoint innerhalb der for-Schleife.



    // ...


    #define MAX_SWEEPING_DISTANCE (500.0)


    new Float:pos[3],
    Float:distance[2]
    index = -1;


    GetVehiclePos(GetPlayerVehicleID(playerid), pos[0], pos[1], pos[2]);
    for(new i = 0; i < sizeof(sweeperCheckpoints); i++) {
    distance[0] = getDistanceBetweenCoordinates(pos[0], pos[1], pos[2], sweeperCheckpoints[i][pos][0], sweeperCheckpoints[i][pos][1], sweeperCheckpoints[i][pos][2]);
    if((index == -1 && distance[0] <= MAX_SWEEPING_DISTANCE) || (index != -1 && distance[0] < distance[1])) {
    distance[1] = distance[0];
    index = i;
    }
    }


    if(index != -1) {
    SetPlayerCheckpoint(playerid, sweeperCheckpoints[i][pos][0], sweeperCheckpoints[i][pos][1], sweeperCheckpoints[i][pos][2], 4.5); // Yay!
    } else {
    SendClientMessage(playerid, -1, "Thank you for sweeping, however, there is no further task for you in this area!");
    }


    // ...


    Float:getDistanceBetweenCoordinates(Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2) {
    return floatsqroot(floatpower(floatabs(floatsub(x2,x1)), 2) + floatpower(floatabs(floatsub(y2,y1)), 2) + floatpower(floatabs(floatsub(z2,z1)), 2));
    }


    P.S.: Ungetestet! + Verwende eher die Größe des Arrays in der for-Schleife, wenn die Checkpoints im Quellcode definiert sind. Falls sie geladen werden, verwende einen Iterator (foreach!).

  • stock GetNearestRubbishID(veh, MAX_DISTANCE = 500.0){
    new Float:Distance[2]={-1,-1}, index = -1;
    for(new i; i != MAX_RUBBISH; ++i){
    if(!SRubbishInfo[i][RubbishObject])continue;
    Distance[0] = GetVehicleDistanceFromPoint(veh, SRubbishInfo[i][RposX], SRubbishInfo[i][RposY], SRubbishInfo[i][RposZ]);
    if((Distance[1] == -1 || Distance[0] < Distance[1]) && Distance[0] < MAX_DISTANCE){
    Distance[1] = Distance[0];
    index = i;
    }
    }
    return index;
    }
    stock DestroyRubbish(index){
    DestroyDynamicObject(SRubbishInfo[index][RubbishObject]);
    SRubbishInfo[index][RubbishObject] = 0;
    return 1;
    }


    Er muss nur Abfragen ob das Objekt die ID 0 hat um leere zeilen eines Arrays raus zu filtern da die Objekte mit der Ordnungszahl 1 anfangen, dies ist genauso wie bei dem Fahrzeugen.


    Ich hab ihm mal zwei Funktionen geschrieben die ihm helfen sollten, ide erste Funktionen filtert den nächsten Mülleimer raus und die zweite Funktion zum löschen.



    Verwendung:

    public OnPlayerEnterCheckpoint(playerid)
    {
    new veh = GetPlayerVehicleID(playerid);
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !strcmp(SpawnCar_Type[veh], "Straßenreinigung", true))
    {
    DisablePlayerCheckpoint(playerid);
    DestroyRubbish(MuellObject[playerid]);
    new id = GetNearestRubbishID(GetPlayerVehicleID(playerid));
    if(id == -1)return SendClientMessage(playerid,-1,"In deiner nähe gibt es keine Mülleimer");
    MuellObject[playerid] = id;
    return SetPlayerCheckpoint(playerid, SRubbishInfo[id][RposX], SRubbishInfo[id][RposY], SRubbishInfo[id][RposZ], 4.5);
    }
    return 1;
    }


    //edit kleiner Fehler gefunden

  • Das sind keine Mülleimer, und auserdem brauche ich diese Fehlermeldung nicht.
    Der einfach Grund ist, das dass System so verläuft das die Checkpoints da angezeigt werden wo Müll auf dem Boden liegt.
    Aber dankeschön, werds mal ausprobieren

  • Er muss nur Abfragen ob das Objekt die ID 0 hat um leere zeilen eines Arrays raus zu filtern da die Objekte mit der Ordnungszahl 1 anfangen, dies ist genauso wie bei dem Fahrzeugen.


    Das stimmt. Wäre eine Alternative zum Iterator im Falle, dass die Checkpoints geladen werden. Dann würde ich jedoch nicht "continue" beim Erreichen eines leeren Array-Indexes verwenden, sondern break, um die komplette Schleife abzubrechen. Es sei denn, es können während Runtime Lücken im Array entstehen.

  • abzubrechen. Es sei denn, es können während Runtime Lücken im Array entstehen.


    Wenn man sein Code anschaut ist es klar das Lücken während der Laufzeit entstehen , abgesehen davon hast du natürlich recht
    ein return reicht da auch, zum Thema iterator es gibt das memory_access plugin und bietet sich perfekt zur Verwaltung des Speichers an.


    MrPawn dann setze dort ein return 1; hin da sonst der Server abschmiert , wenn man auf einen negativen index eines arrays zugreifst

  • Wo soll ich da bitte etwas returen ?


    public OnPlayerEnterCheckpoint(playerid)
    {
    new veh = GetPlayerVehicleID(playerid);
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !strcmp(SpawnCar_Type[veh], "Straßenreinigung", true))
    {
    DisablePlayerCheckpoint(playerid);
    DestroyRubbish(MuellObject[playerid]);
    new id = GetNearestRubbishID(GetPlayerVehicleID(playerid));
    MuellObject[playerid] = id;
    return SetPlayerCheckpoint(playerid, SRubbishInfo[id][RposX], SRubbishInfo[id][RposY], SRubbishInfo[id][RposZ], 4.5);
    }
    return 1;
    }


    stock GetNearestRubbishID(veh, Float:MAX_DISTANCE = 500.0){
    new Float:Distance[2]={-1.0,-1.0}, index = -1;
    for(new i; i != MAX_RUBBISH; ++i){
    if(!SRubbishInfo[i][RubbishObject])continue;
    Distance[0] = GetVehicleDistanceFromPoint(veh, SRubbishInfo[i][RposX], SRubbishInfo[i][RposY], SRubbishInfo[i][RposZ]);
    if((Distance[1] == -1 || Distance[0] < Distance[1]) && Distance[0] < MAX_DISTANCE){
    Distance[1] = Distance[0];
    index = i;
    }
    }
    return index;
    }


    stock DestroyRubbish(index){
    DestroyDynamicObject(SRubbishInfo[index][RubbishObject]);
    SRubbishInfo[index][RubbishObject] = 0;
    return 1;
    }


    Bei jeder Funktion wird doch ein Wert zurück gegeben :)

  • public OnPlayerEnterCheckpoint(playerid)
    {
    new veh = GetPlayerVehicleID(playerid);
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !strcmp(SpawnCar_Type[veh], "Straßenreinigung", true))
    {
    DisablePlayerCheckpoint(playerid);
    DestroyRubbish(MuellObject[playerid]);
    new id = GetNearestRubbishID(GetPlayerVehicleID(playerid));
    if(id == -1)return 1;
    MuellObject[playerid] = id;
    return SetPlayerCheckpoint(playerid, SRubbishInfo[id][RposX], SRubbishInfo[id][RposY], SRubbishInfo[id][RposZ], 4.5);
    }
    return 1;
    }



    if(id == -1)return 1;


    wie bereits erwähnt


    Zitat

    und auserdem brauche ich diese Fehlermeldung nicht.


    Zitat

    MrPawn dann setze dort ein return 1; hin da sonst der Server abschmiert , wenn man auf einen negativen index eines arrays zugreifst



    schmiert dein server sonst ab, da du auf einen negativen index zugreifst SRubbishInfo[-1][RposX]