Entwickler-Ecke

WinForms - Kollision von zwei Rechtecken


YK18415 - Do 05.01.17 15:53
Titel: Kollision von zwei Rechtecken
Hallo,

ich bin dabei ein Asteroids-Spiel zu entwickeln. Es klappt ganz gut (Raumschiff bewegen, schießen etc.), allerdings habe ich ein Problem bei der Kollisionsabfrage des Raumschiffes (Rechteck) mit einem Asteroiden (Kreis).
Ich zeichne alles auf einer pictureBox und speichere dabei die Asteroiden in einer Liste (s. Code):

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
// grap all astroids
List<GeometricObject> astroids = new List<GeometricObject>();
foreach (var item in listBox1.Items)
{
    if (item is Asteroid)
    {
        astroids.Add((Asteroid)item);
    }
}

Diese Objekte in der Liste (Asteroiden) vergleiche ich mit dem Raumschiff mit Hilfe der Methode "CheckCollision".
In meiner Basisklasse (GeometricObject) habe ich eine Methode, die um alle gezeichnete Objekte (also um Kreis, Rechteck, Dreieck usw.) ein Rechteck zeichnet, um die Kollisionsabfrage fürs Erste einfacher zu gestalten. Die Kollisionsabfrage habe ich auch in meiner Basisklasse geschrieben.

Mein Code in der Basisklasse:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
        public virtual void Boundaries(Graphics g)
        {
            g.DrawRectangle(Pens.White, (float)X, (float)Y, (float)Width, (float)Height);
        }
        public Collision CheckCollison(List<GeometricObject> otherObjects)
        {
            foreach (var item in otherObjects)
            {
                var collison = CheckCollison(item);
                if (collison != nullreturn (collison);
            }
            return null;
        }
        public Collision CheckCollison(GeometricObject otherObject)
        {
            asteroid = new Asteroid();
            rectangle = new Rectangle();
          
      1.      if ((asteroid.X > rectangle.X && asteroid.X < rectangle.X + rectangle.Width) && (asteroid.Y > rectangle.Y && asteroid.Y < rectangle.Y + rectangle.Height))
            {
                return new Collision() { Object1 = this, Object2 = otherObject };
            }
      2.      if ((asteroid.x > this.X && asteroid.X < this.X + Width) && (asteroid.Y > this.Y && asteroid.Y < this.Y + Height))
            {
                return new Collision() { Object1 = this, Object2 = otherObject };
            }
   
            return null;
        }

Wie man in der unteren CheckCollision-Methode sieht, habe ich schon einiges ausprobiert.

Mein Problem:

In 1. werden die Werte der einzelnen Objekte irgendwie nicht erfasst, wodurch die Position von den Objekten (x und y) immer auf 0 stehen...
In 2. bekomme ich zwar mit "this.X" die Koordinaten des Rechteckes vom Raumschiff (klar, weil ich ja auch in dieser Klasse das umschließende Rechteck zeichne), aber bei "asteroid.X" und bei "asteroid.Y" steht immer noch 0...

Wie kann ich diesen Wert (also den Wert von dem oberen linken Punkt des Rechteckes, das den Asteroiden umschließt) bekommen?

Danke schon mal! :)

Moderiert von user profile iconTh69: C#-Tags hinzugefügt


YK18415 - Do 05.01.17 15:59

Ach so,

die Auswertung habe ich in Form1.cs in meiner Methode, die alles zeichnet wie folgt geschrieben:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
if (item is Spaceship)
{
    var collison = ((Spaceship)item).CheckCollison(astroids);
    if (collison != null)
    {
        MessageBox.Show("Bum: " + collison.Object2.ToString());
    }
}


Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Ralf Jansen - Do 05.01.17 16:00

Zitat:

C#-Quelltext
1:
2:
            asteroid = new Asteroid();
            rectangle = new Rectangle();


Du erzeugst einfach zwei neue Objekte, initialisierst die nicht, vergleichst die aber. Warum sollte da was vernünftiges rauskommen?


Th69 - Do 05.01.17 16:01

Du erstellst ja auch in der Zeile über 1. sowohl einen neuen Asteroiden als auch ein neues leeres Rechteck (alle Werte werden dabei auf 0 gesetzt), welche du dann vergleichst - dies macht wohl keinen Sinn. Überlege dir genau was du miteinander vergleichen willst.

PS: Und bitte füge selbständig die C#-Tags hinzu...


jfheins - Do 05.01.17 16:02

Soweit logisch 8)


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
public Collision CheckCollison(GeometricObject otherObject) 

  asteroid = new Asteroid(); 
  rectangle = new Rectangle(); 

  // 1
  if ((asteroid.X > rectangle.X && asteroid.X < rectangle.X + rectangle.Width) && (asteroid.Y > rectangle.Y && asteroid.Y < rectangle.Y + rectangle.Height)) 
  { 
    return new Collision() { Object1 = this, Object2 = otherObject }; 
  } 
  // 2
  if ((asteroid.x > this.X && asteroid.X < this.X + Width) && (asteroid.Y > this.Y && asteroid.Y < this.Y + Height)) 
  { 
    return new Collision() { Object1 = this, Object2 = otherObject }; 
  }
  return null
}


Bei 1 vergleichst du ja asteroid mit rectangle, die du beide erst direkt darüber erzeugt hast.
Bei 2 vergleichst du this mit asteroid. this hat dann wohl schon von 0 verschiedene Werte, aber die Variable asteroid wird ja immer noch direkt oberhalb erzeugt und initialisiert.

In keiner Variante benutzt du den Parameter otherObject.


YK18415 - Do 05.01.17 16:11

Naja, initialisiert habe ich die schon, allerdings direkt am Anfang der Basisklasse mit "Rectangle rectangle;" und mit "Asteroid asteroid;".

Ja stimmt @jfheins :D :roll:
Wenn ich diesen Parameter benutze, dann klappt es auch.

Vielen Dank für eure Zeitinvestition! :D


PS: Man merkt ich bin ein Anfänger...