Laden...

Mehrere Klassenobjekte in Main Klasse mit einer List überprüfen

Erstellt von BlackArtC# vor 7 Jahren Letzter Beitrag vor 7 Jahren 2.765 Views
B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren
Mehrere Klassenobjekte in Main Klasse mit einer List überprüfen

Hallo Leute,

ich habe momentan 2 Klassen in meinem Projekt(Main Klasse und eine Bricks Klasse).

In der Mainklasse erzeuge ich eine List<Bricks> welcher ich dann mehrere Klassenobjekte hinzufüge und dann per for Schleife Werte festlege.

z.B

      
 for (int i = 0; i < 10; i++)
            {
                for (int j= 0; j < 4; j++)
                {
                    FirstStage[i, j] = new Bricks();
                    FirstStage[i, j].LoadBricks(this.Content, "BreakOutTile1");

                }
            }

Das klappt auch soweit gut. Jetzt muss ich aber die Position der Bricks Objekte überprüfen und wenn diese mit meiner eingestellten Position übereinstimmen, sollen diese Objekte gelöscht werden und nichtmehr angezeigt werden.

Jetzt dachte ich mir ich speicher die Position nochmal in einer seperaten Liste, überprüfe diese dann mit der eingestellten Position und lösche dann an der "i" Stelle jeweils aus der Positions Liste und aus der FirstStage Liste die Werte.

Gibt es da ne bessere Möglichkeit, klappt das so oder habe ich grad ne Denkblockade?

Vielen Dank, Gruß

**EDIT habe es hinbekommen, jedoch werden jetzt alle Werte aufeinmal gelöscht, wenn diese nicht von hinten einzelnd gelöscht werden. Also wenn ich den 0. Index lösche, wird alles danach auch gelöscht 😕

1
124 Beiträge seit 2012
vor 7 Jahren

Hallo,

wieso nutzt du ein Array wenn du schreibst das du eine Liste hast?

Der Code drumherum wäre noch interessant.

normal müsste das ja so aussehen:


List<Bricks> FirstStage = new List<Bricks>();
for (int j= 0; j < 4; j++)
{
     FirstStage.Add(new Bricks().LoadBricks(this.Content, "BreakOutTile1"));
}

Gruß

3.003 Beiträge seit 2006
vor 7 Jahren

Nunja, inline wird nur funktionieren, wenn LoadBricks auch ein Objekt zurückgibt. Ich wäre mehr Fan von so etwas hier:


private IEnumerable<Bricks> GetBricks(content <<typ ist nicht ersichtlich, selbst einfügen>>)
{
      for(var i = 0; i < 4; i++)
      {
          var newBrick = new Bricks();
          newBrick.LoadBricks(content, "BreakOutTile1");
          yield return newBrick;
          //oder schöner, inline:
         yield return new Brick().LoadBricks(content, "BreakOutTile1");
      }
}

(Geschmackssache.)

@BlackArt: dein Array ist zweidimensional (was schon designtechnisch nicht so toll ist). Was meinst du mit 0. Index?

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

Hallo Leute, erstmal danke für die Antwort. Damit es ein wenig klarer wird ich benutze Monogame für die Entwicklung eines kleinen Spieles. Das sind die relevanten Codezeilen(habe es jetzt ohne "2D" Array gemacht):

       
for (int i = 0; i < graphics.GraphicsDevice.Viewport.Width/128; i++)
            {
                breakOut.Add(new Bricks());
                breakOutPosition.Add(new Rectangle());

                breakOut[i].LoadBricks(Content, "BreakOutTile1");
            }


    for (int i = 0; i < breakOut.Count; i++)
            {
                breakOutPosition[i] = breakOut[i].SetRectangles(i);
                
            }


for (int i = 0; i < breakOut.Count; i++)
            {
                if (ball.Collision(breakOutPosition[i]))
                {
                    ball.Turn(0);
                    breakOutPosition.Remove(breakOutPosition[i]);
                    breakOut.Remove(breakOut[i]);

                    if (i > 0)
                        i -= 0;
                }

So in der ersten Code Spalte füge ich der breakOut und breakOutPosition List jeweils 10 "Typen" zu. Mit breakOut_.LoadBricks lade ich dann die Grafik welche dargestellt werden soll.

In der zweiten Codespalte, weise ich der breakOutPosition Liste die Rectangles der erstellten breakOut "Grafiken" zu. (Also nach meinem Wissen nimmt eine List nur einen Typ an, deswegen brauche ich nochmal eine Liste für die Rectangles - die Rectangles sind einfach nur zur Kollisionerkennung vorhanden, da man das mit einfachen Texturen anscheinend nicht machen kann).

Die dritte Codespalte prüft den "Ball" auf Kollision mit einem der Rechtecke welche sich in der breakOutPosition Liste befindet. Dann prallt der Ball ab und die Objekte der beiden Liste werden an der i.ten Stelle gelöscht. Das i-=1 soll i einfach nur verringern, da die Objekte ja jetzt nach unten rutschen und ich nichts verpasse mit dem prüfen.

Was jetzt mein eigentliches Problem ist:

Egal wo mein Ball Objekt aufprallt, es wird immer das letzte Objekt gelöscht und dementsprechend rutschen die Elemente in der Liste immer weiter "nach oben". Also brauche ich irgendeinen "Platzhalter" damit die Objekte auch richtig gezeichnet werden.

Hier hat der Grüne "Ball" den 4. Balken getroffen, aber der 5. ist verschwunden. Eigentlich sollte der 4. verschwinden und der 5. bleiben.

Ich hoffe ihr versteht was ich meine,

Gruß

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

Okay Leute, sorry für den Stress aber ich habe mein Fehler gefunden. Die "Rectangles" wurden einmal mit festen Werten der breakOutPosition zugewiesen und beim zeichnen wurden dann immer wieder neue Rectangles angelegt. Somit tritt dann eben immer das ein, was bei mir das Problem ist.

Wenn ich jetzt in der Draw Methode die breakOutPosition als Parameter übergebe, klappt es wunderbar.


 for (int j = 0; j < breakOut.Count; j++)
            {
                breakOut[j].DrawBricks(spriteBatch, new Vector2(j * 128, 0),breakOutPosition[j]); //new Rectangle(j * 128, 0, 128, 16));            
            }

Hatte bis jetzt noch nie so Projekte mit mehreren Klassen wo alles zu allem einen Bezug hat.

Trotzdem danke!!

J
251 Beiträge seit 2012
vor 7 Jahren

So aus Interesse. Worin besteht darin der Sinn?


if (i > 0)
      i -= 0;

Immerhin steht doch dort:
Wenn i größer 0 ist, dann subtrahiere i um 0

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

Naja sagen wir du hast 5 Objekte in der Liste {A0,A1,A2,A3,A4};

Wenn du jetzt ne for schleife machst , i = 0 und du löschst diesen Wert, dann sieht deine Liste so aus: {A1,A2,A3,A4}. Das bedeutet wenn der Ball "theoretisch" mit A0 und A1 kollidiert, würde A1 erst im nächsten Schleifen durchlauf gelöscht werden, da er im vorherigen ja auf 0 gerutscht ist und somit ausgelassen wird, da i ja schon 0 war. Deswegen nochmal i auf null und alles überprüfen(wird auch nur bei einer Kollision ausgeführt).

Habe das gestern als Konsolenanwendung programmiert um zu schauen wie ich das am besten mache und dort war es zumindest so, dass manchmal noch ein Wert in der Liste stand, obwohl dieser raus sollte. Aber keine Garantie das ich das richtig verstanden habe.

W
872 Beiträge seit 2005
vor 7 Jahren

Ich habe das ganze nicht so 100 % verstanden - aber gefühlt solltest Du nicht mit Listen, sondern mit einem Dictionary arbeiten.
Die Position ist dabei der Key. Wenn Du dann Deinen Ball bewegst, dann musst Du prüfen, ob entweder der Key, der neuen Position schon vorhanden ist oder nicht. Wenn ja, dann entfernst Du den Ball und das Objekt an der Stelle des neuen Key oder wenn nicht entfernst Du nur den alten Key und fügst das Ball mit dem neuen Key wieder hinzu.

C
224 Beiträge seit 2009
vor 7 Jahren

Nachfolgender Code ist Fehlerhaft:


for (int i = 0; i < breakOut.Count; i++)
{
    ...
    breakOut.Remove(breakOut[i]);
    ...
}

Grund: nach dem Entfernen hat sich die Liste geändert

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

@Weismat danke für den Tipp, kannte ich vorher gar nicht ^^. Werde ich mir mal demnächst anschauen.

@CoLo Danke für deine Antwort, aber was ist jetzt genau fehlerhaft das sich die Liste ändert?
Es ist ja mein Ziel das die Liste sich ändert ^^ und so klappt es auch wie es soll 😃

C
224 Beiträge seit 2009
vor 7 Jahren

@ BlackArtC#



        private void button3_Click(object sender, EventArgs e)
        {
            List<string> list = new List<string>();
            list.Add("A");
            list.Add("B");
            list.Add("C");
            list.Add("D");
            for (int i = 0; i < list.Count; i++)
            {
                System.Diagnostics.Debug.WriteLine(list[i]);
                list.Remove(list[i]); //list.RemoveAt(i); macht das Gleiche
            }
            System.Diagnostics.Debug.WriteLine(list.Count.ToString());
        }

        //  Debug-Ausgabe:
        //  A
        //  C
        //  2


Versuche das mal nachzuvollziehen. Dann siehst Du es 😉

16.807 Beiträge seit 2008
vor 7 Jahren

@CoLo Danke für deine Antwort, aber was ist jetzt genau fehlerhaft das sich die Liste ändert?
Es ist ja mein Ziel das die Liste sich ändert ^^

Du kannst keine Liste ändern während Du über sie iterierst.
Das "funktioniert" hier aus Glück weil Du for verwendest. Mit foreach würde es Dir um die Ohren fliegen.

Der Folgefehler bei for ist jedoch, dass Dein Index nicht mehr der ist, wie er vor Beginn war.
Entweder Du wirst damit in einen IndexOutOfRange laufen oder Du überspringst einen Eintrag.
Beides ned so dolle.

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

Hallo, also ich möchte mal jetzt behaupten das es eigentlich doch so läuft wie es soll z.B



List<int> Recs = new List<int>();

            Recs.Add(new int());
            Recs.Add(new int());
            Recs.Add(new int());
            Recs.Add(new int());

            Recs[0] = 1;
            Recs[1] = 2;
            Recs[2] = 2;
            Recs[3] = 1;

            for (int i = 0; i < Recs.Count; i++)
            {
                Console.WriteLine(Recs[i]);
                //Ausgabe: 1 2 2 1
            }



       for (int i = 0; i < Recs.Count; i++)
            {
                if (Recs[i] == 2)
                {
                    Recs.RemoveAt(i);
                    i -= 1;
                }
            }

            Console.WriteLine();

            foreach (var item in Recs)
            {
                Console.WriteLine(item); 
                //Ausgabe ohne i-=1 : 121
                // Ausgabe mit i-=1 : 11
            }

Also ausgelasen wird da ja nichts und wie man an der Ausgabe sehen kann, hat die Liste am ende 2 Objekte weniger. Versteht mich nicht falsch, ich befülle keine Liste und lösche sie im gleichen Zug wieder, ich vergleiche lediglich eine Position mit den Werten in meiner Liste und lösche diesen "Eintrag". Da alles von der Listengröße abhängig ist, wird sie nächstes mal auch weniger durchlaufen. Also tut mir leid wenn ich gerade den Fehler nicht verstehe 😕

**Edit

@CoLo

Wenn man bei deinem Code auch das i-=i macht, kommt bei mir am Ende ein Listen Count von 0 raus. Also wird alles gelöscht wie gewollt.



   List<string> list = new List<string>();
            list.Add("A");
            list.Add("B");
            list.Add("C");
            list.Add("D");
            for (int i = 0; i < list.Count; i++)
            {
                Console.WriteLine(list[i]);
                list.Remove(list[i]); //list.RemoveAt(i); macht das Gleiche
                i -= 1;
            }

            Console.Title = Convert.ToString(list.Count); //Ausgabe 0

2.207 Beiträge seit 2011
vor 7 Jahren

Hallo BlackArtC#,

du tanzt auf der Liste rum, die du manipulierst.

[FAQ] Listenelemente suchen und entfernen

Gruss

Coffeebean

3.003 Beiträge seit 2006
vor 7 Jahren

Dir muss doch aufgefallen sein, dass du die Zählvariable in deiner for-Schleife manipulieren musstest, damit das funktioniert:


 i -= 1;

Mit anderen Worten musstest du etwas nachkorrigieren, weil du ansonsten einen Index angesprochen hättest, den es nicht mehr gab, weil du im Schritt vorher ein Element aus der Liste genommen hast, die du im nächsten Schritt wieder abrufst. Kommt dir das nicht selbst komisch vor?

Der Punkt ist:


for(int i = 0; i < irgendwas; i++)
{
    i--;
}
//ist dasselbe - und zwar nicht nur vom Ergebnis, sondern von der Auführung her! -  wie
while(list.Any()) 
   list.Remove(list.First());
//...nur unübersichtlicher.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

@LaTino Also mir ist klar das ich ohne i-- einen falschen Index anspreche, deswegen habe ich es ja auch rein geschrieben und in meinem Beispielcode mit den 2 Ausgaben "gezeigt".

Komisch kommts mir jetzt nicht umbedingt vor, da es ja so funktioniert wie ich es will.

Aber ich habe schon verstanden das man das nicht so machen soll.

Danke Coffeebean für den Link:)

Gruß

16.807 Beiträge seit 2008
vor 7 Jahren

Es funktioniert vielleicht technisch, vielleicht funktioniert die Logik für Deinen getesteten Fall aufgrund Glück, da es hier weniger eine Rolle spiel.
Im Rahmen einer ordentlichen Implementierung und Anbetracht der Gesamtlogik ist es aber falsch.
Das sollte Dir nach ein wenig Überlegen auch auffallen. Du kannst Dich aber natürlich auch bockig stellen, die Ratschläge ignorieren und mit der Zeit in einen Fehler laufen, den Du nicht sofort erkennst.

3.003 Beiträge seit 2006
vor 7 Jahren

@LaTino Also mir ist klar das ich ohne i-- einen falschen Index anspreche, deswegen habe ich es ja auch rein geschrieben und in meinem Beispielcode mit den 2 Ausgaben "gezeigt".

*grien* Wir reden immer noch etwas aneinander vorbei. Du hast, als du das i zurückgesetzt hast, eine Endlosschleife gebaut, ok? Dort steht effektiv:

  • nimm eine Zahl und setze sie 0

  • erhöhe sie um eins

  • verringere sie um eins

  • so lange, wie die Liste Elemente hat

Das es momentan funktioniert, hat niemand bezweifelt. Aber es ist nicht sauber in dem Sinn, dass das Objekt, was du manipulierst, gleichzeitig die Abbruchbedingung für die Schleife, in der es manipuliert wird, darstellt. Du baust dir da eine Sprengfalle ein, und wenn sie mal hochgeht, weisst du nicht, wieso. Ich glaube alle, die dich hier darauf hingewiesen haben, haben genau so etwas auch schon mal gemacht und entweder bitter bereut, oder rechtzeitig refaktoriert. Also wir weisen nicht umsonst darauf hin, dass du das ändern solltest 😉.

Folgender Code stammt aus einem Produktivsystem:


foreach(var tmp in someList);

Der Punkt ist, dass der oberschlaue Entwickler den Enumerator manipuliert hat, so dass dieser auf jedem Element der Liste, das durchlaufen wird, etwas tut. Die Schleife selbst ist aber eine leere Anweisung (";"). Kein Schwein kapiert mehr, warum da eine Schleife steht, aber wenn man sie wegnimmt, funktioniert das Programm nicht mehr. "Magischer" Code: und genau so etwas hast du mit deinem "i = i-1" - magischen Code, dessen Sinn nicht sofort klar ist. Und das ist nie gut.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

B
BlackArtC# Themenstarter:in
29 Beiträge seit 2016
vor 7 Jahren

Habe den Code jetzt auf das hier runter reduziert, und das Funktioniert auch super.
Falls es jetzt immernoch "unsauber" ist, muss ich mich wohl noch ne weile mit beschäftigen.


 foreach (var item in breakOutPosition)
            {
                if (ball.Collision(item))
                    ball.Turn(0);
            }
            breakOutPosition.RemoveAll(position => position.Intersects(ball.GetBallRec));

Danke für die Hilfe!

gruß

3.003 Beiträge seit 2006
vor 7 Jahren

Find ich gut. Dank der Bezeichnungen und der lambda-expression wird ziemlich deutlich, was passiert. 👍

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)