Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Tician

Frischling

  • »Tician« ist der Autor dieses Themas

Beiträge: 32

Wohnort: Bad Friedrichshall

Beruf: FISI

  • Private Nachricht senden

1

16.08.2016, 12:27

C# 2D Labyrinth - Kollission und Scrolling

Hallöööchen mit 3 öchen,

nachdem ich ja mein erstes kleines Spiel fertig hatte bei dem man einen Kreis bewegen konnte der schneller wird sobald man etwas einsammelt, möchte ich nun eine Stufe weiter.

Vorneweg: Ich benutze VS ohne irgendwelche Zusätze.

Mein Beispiel-Ziel: ein 5000*5000 pixel Labyrinth bestehend aus VS-gezeichneten Linien (wer hätte es gedacht) und einem Spieler (kreis) der sich mit Pfeiltasten durch das Labyrinth bewegt.
Das alleine würde ich wahrscheinlich mit gefühlten tausend Zeilen Code und einem entsprechend großen Bildschirm hinbekommen. Der Gedanke war den Rand jeder Linie des Labyrinths (jeden Pixel?)als No-Go zu definieren. Problem Nummer 1: Heißt ich mit null wissen würde mit jedem Pixel den sich der SPieler bewegt überprüfen ob sich da was berührt - und wenn ja dann die entsprechend Richtung zu "blockieren". So wie ich mir das vorstelle wären das mehrere tausend Zeilen Abfragen. Wie bekomme ich es in weniger Zeilen hin diese Berührung von Kreis-Rand und den hunderten von Linien zu überprüfen?

Jetzt ist meine Absicht aber kein 5000*5000 Pixel Fenster sondern der Spieler soll nur z.B. einen 500*500 Pixel AUsschnitt des Labyrinth-Bereiches sehen in dem er sich befindet. Heißt der Focus soll auf dem Kreis sein - und dieser immer in der Mitte des Bildes. Im Prinzip ist das Problem ähnlich dem anderen, wie bekomme ich dann die vielen Linien bewegt sobald sich der Spieler bewegt?

Ich finde nichts was nicht XNA oder anderes benutzt und mir fehlt die Idee bzw die Erfahrung wie ich diese 2 Herausforderungen meistere, könnte mir da jemand auf die Sprünge helfen?

LInsoDeTeh

Treue Seele

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

2

16.08.2016, 13:34

Ich würde überlegen, ob ich als Datenstruktur für das Labyrinth wirklich die Linien speichern will, oder nicht die Pixel selbst, z.B. in einem 2-dimensionallen Array. Dann kannst du pro Pixel festlegen, ob ein Feld frei oder blockiert ist.
Zur Prüfung auf Kollision bräuchtest du dann nur die jeweils vier benachbarten Pixel auswerten (-1 und +1 in X-Richtung, und -1 und +1 in Y-Richtung). Ähnlich effektiv verhält es sich dann beim Rendern, wo du praktisch nur von -250 bis 250 in X-Richtung und -250 bis 250 in Y-Richtung zeichnen musst. Eine Unter-/Obergrenze für die Position, sodass das Labyrinth halb nicht aus dem Bildschirm rausguckt, wenn du dich an dessen Rand befindest, kannst du mit einfachen ifs lösen.

Tician

Frischling

  • »Tician« ist der Autor dieses Themas

Beiträge: 32

Wohnort: Bad Friedrichshall

Beruf: FISI

  • Private Nachricht senden

3

16.08.2016, 15:16

Ich denke ich verstehe was du meinst was das 2D-Array betrifft und die Abfrage der Pixel um den Spieler herum... ich melde mich nochmal wenn ich es gemeistert habe ein 2-dimensionales Array aus Vierecken zu machen... .

C#-Quelltext

1
2
3
4
5
6
7
8
9
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            int pixelCount = 7;
            int pixelSize = 10;

            SolidBrush playerBrush = new SolidBrush(Color.Black);
            Graphics grafik = this.CreateGraphics();
            Rectangle[,] recArray = new Rectangle[pixelCount, pixelCount];
        }


Irgendwie so und dann noch 2 verschachtelte Schleifen... ich kriegs noch raus und melde mich dann wie gesagt nochmal


Edit:

Quellcode

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
private void Form1_Paint(object sender, PaintEventArgs e)
        {
            int pixelCount = 7;
            int pixelSize = 10;
            //int space = 2; //temporary for visibility;

            Pen black = new Pen(Color.Black);
            Graphics grafik = this.CreateGraphics();
            Rectangle[,] recArray = new Rectangle[pixelCount, pixelCount];

            for (int x = 0; x < pixelCount; x++)
            {
                for (int y = 0; y < pixelCount; y++)
                {
                    recArray[x, y] = new Rectangle((x * pixelSize),(y * pixelSize), pixelSize, pixelSize);
                }
            }
            for (int x = 0; x < pixelCount; x++)
            {
                for (int y = 0; y < pixelCount; y++)
                {
                    grafik.DrawRectangle(black, recArray[x, y]);
                }
            }
        }


Das ging ja dank StackOverflow recht schnell, ich mach mal weiter bis ich auf Probleme stoße, vielen Dank soweit mal LInsoDeTeh das war der Anstoß den ich gebrauchen konnte!

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Tician« (16.08.2016, 15:46)


Tician

Frischling

  • »Tician« ist der Autor dieses Themas

Beiträge: 32

Wohnort: Bad Friedrichshall

Beruf: FISI

  • Private Nachricht senden

4

16.08.2016, 16:51

Gibt es in C# eine Möglichkeit Boolean einem Objekt zuzuordnen? Mein Gedanke war im Prinzip das hier:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool b = true;
            recArray[3, 3] = b;

            for (int x = 0; x < pixelCount; x++)
            {
                for (int y = 0; y < pixelCount; y++)
                {
                    if (recArray[x,y] == true)
                    {
                        grafik.FillRectangle(black, recArray[x, y]);
                    }
                    else
                    {
                        grafik.DrawRectangle(transparent, recArray[x, y]);
                    }
                }
            }


Funktioniert nicht und ist auch nur symbolisch gemeint um zu veranschaulichen worauf ich hinaus möchte.
Aber außer Boxing (oder ist es das was ich suche?) kann ich nichts finden.

LInsoDeTeh

Treue Seele

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

5

16.08.2016, 17:46

Da Rectangle ein struct ist, kannst du davon leider keine Ableitung machen. Aber du kannst ja eine eigene Klasse bauen, z.B.

C#-Quelltext

1
2
3
4
class LabyrinthTile {
  public Rectangle { get; set;}
  public bool IsFree { get; set; }
}


Dann hast du eben

C#-Quelltext

1
var recArray = new LabyrinthTile[pixelCount, pixelCount];

statt einem Array von Rechtecken und verwendest dann

C#-Quelltext

1
if (recArray[x,y].IsFree)

und

C#-Quelltext

1
grafik.FillRectangle(recArray[x,y].Rectangle);


Bei der Gelegenheit kannst du z.B. auch die Logik, welche Farbe dein Pixel/Rechteck haben soll (was ja von IsFree abhängen wird), direkt in die Klasse packen und deine Schleife damit aufräumen.

Tician

Frischling

  • »Tician« ist der Autor dieses Themas

Beiträge: 32

Wohnort: Bad Friedrichshall

Beruf: FISI

  • Private Nachricht senden

6

18.08.2016, 12:02

Ich habe noch nie von einem struct gehört, bist du dir sicher das es sich so benutzen lässt?
Ich probiere seit ner ganzen Weile rum, aber außer das ich gleich sowas hier baue (und keine Ahnung habe wie ich es dann benutze) bekomme ich nichts hin.

Quellcode

1
2
3
4
5
6
7
8
class MazeTile
    {
        public bool Wall { get; set; }
        struct Rectangle
        {
            int pixelsize { get; set; }
        }
    }


Es gibt für

Quellcode

1
public Rectangle { get; set;}

kein get/set - oder fehlt mir da etwas?

LInsoDeTeh

Treue Seele

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

7

18.08.2016, 13:01

Mir ist da ein kleiner Syntaxfehler unterlaufen (der Bezeichner fehlt)... Es sollte eigtl. so aussehen:

C#-Quelltext

1
2
3
4
class LabyrinthTile {
  public Rectangle Rectangle { get; set;}
  public bool IsFree { get; set; }
}


Du sollst auf jeden Fall nicht in der Klasse selber ein struct Rectangle definieren, sondern den Rectangle-Typ aus System.Drawing verwenden, den du ja auch schon vorher in deinem Array verwendet hast.

Tician

Frischling

  • »Tician« ist der Autor dieses Themas

Beiträge: 32

Wohnort: Bad Friedrichshall

Beruf: FISI

  • Private Nachricht senden

8

18.08.2016, 16:10

Nachdem ich jetzt das große rote Kreuz (hab erstmal ganz schön blöd gekuckt) (Event Exception) von meiner Form losgeworden bin und verstanden habe wie ich die NullReferenceException beheben kann stehe ich vor dem nächsten Schritt - und kurz vor dem Ziel.
Ich weiß nicht inwieweit ich jetzt von dem Weg den du vorgeschlagen hast weg bin, aber ich habe gerade eine Blockade und weiß nicht wo ich mein "IsFree" (="Wall", ich glaube das habe ich umgedreht) setzen kann da ich ja vorher das Objekt erstellen muss. Du hattest gemeint das irgendwie in die Klasse zu packen, was meintest du genau?

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            try
            { 
                int pixelCount = 7;
                int pixelSize = 10;

                SolidBrush black = new SolidBrush(Color.Black);
                Graphics grafik = this.CreateGraphics();
                var recArray = new MazeTile[pixelCount, pixelCount];

                //declare
                //recArray[3, 3].Wall = true; //SystemNullException
                //recArray[1, 1].Wall = true;

                for (int x = 0; x < pixelCount; x++)
                {
                    for (int y = 0; y < pixelCount; y++)
                    {
                        //recArray[x, y].Rectangle.X = x * pixelSize;
                        Rectangle rec = new Rectangle((x * pixelSize), (y * pixelSize), pixelSize, pixelSize);
                        recArray[x, y] = new MazeTile();
                        recArray[x, y].Rectangle = rec;

                        if (recArray[x, y].Wall == true)
                        {
                            grafik.FillRectangle(black, recArray[x, y].Rectangle);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

    class MazeTile
    {
        public bool Wall { get; set; }
        public Rectangle Rectangle { get; set; }       
    }

9

18.08.2016, 17:47

Ich hoffe ich mische mich jetzt hier nicht ein aber es sind nur ein paar Kleinigkeiten und dann hast du zumindest schon mal ein kleines Erfolgserlebnis:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                //declare
                recArray[3, 3] = new MazeTile();
                recArray[3, 3].Wall = true; //SystemNullException
                //recArray[1, 1].Wall = true;

                for (int x = 0; x < pixelCount; x++)
                {
                    for (int y = 0; y < pixelCount; y++)
                    {
                        Rectangle rec = new Rectangle((x * pixelSize), (y * pixelSize), pixelSize, pixelSize);
                        var tile = (recArray[x, y]);
                        if (tile != null && tile.Wall)
                            grafik.FillRectangle(black, rec);
                        else
                            grafik.DrawRectangle(Pens.Black, rec);
                    }
                }

LInsoDeTeh

Treue Seele

Beiträge: 372

Wohnort: Essen, Deutschland

Beruf: Team Lead Inhouse-Entwicklung

  • Private Nachricht senden

10

19.08.2016, 08:24

weiß nicht wo ich mein "IsFree" (="Wall", ich glaube das habe ich umgedreht) setzen kann da ich ja vorher das Objekt erstellen muss. Du hattest gemeint das irgendwie in die Klasse zu packen, was meintest du genau?


Also das erste Problem in deinem Code ist, dass du die Rechtecke bei jedem Zeichenvorgang neu erzeugst. Das war in deiner vorigen Implementierung besser. Du müsstest also schon im Form_Load so etwas bauen wie:

C#-Quelltext

1
2
3
for (var x = 0; x < pixelCount; x++)
    for(var y = 0; y < pixelCount; y++)
        recArray[x,y] = new MazeTile() { Rectangle = new Rectangle(...), Wall = true };


Oder -was noch besser ist-, du verpasst deiner MazeTile-Klasse einen Konstruktor:

C#-Quelltext

1
2
3
4
5
6
7
8
9
class MazeTile {
  public Rectangle Rectangle { get; private set; }
  public bool Wall { get; private set; }

  public MazeTile(Rectangle rect, bool wall) {
    Rectangle = rect;
    Wall = wall;
  }
}


Und dann instantiierst du die direkt mit:

C#-Quelltext

1
recArray[x,y] = new MazeTile(new Rectangle(...), true);


Zu deiner Rückfrage mit der Klasse. Nun es ist ja so, dass man in der objektorientierten Entwicklung sich immer Gedanken darüber macht, welche Funktionen gehören zu einem Objekt und welche zu anderen Objekten. Und die Funktionen (Methoden) packt man dann in die Klassen, zu denen sie gehören. Die Logik, ein MazeTile zu zeichnen, noch dazu abhängig von der Eigenschaft des MazeTiles selbst (Wall == true??) gehört also in die MazeTile Klasse und nicht in die Schleife außen drum. Die sollte im Idealfall gar nichts von der Logik wissen müssen, sondern nur wissen, dass sie das MazeTile zeichnen muss.

Das machst du dann so, dass du deine Klasse um eine Draw-Funktion erweiterst, die die Logik enthält:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MazeTile {
  public Rectangle Rectangle { get; private set; }
  public bool Wall { get; private set; }

  private SolidBrush blackBrush;

  public MazeTile(Rectangle rect, bool wall) {
    Rectangle = rect;
    Wall = wall;
    blackBrush = new SolidBrush(Color.Black);
  }

  public void Draw(Graphics grafik) {
    if (this.Wall)
      grafik.FillRectangle(blackBrush , rec);
    else
      grafik.DrawRectangle(Pens.Black, rec);
  }
}


Und deine Schleife im Form_Paint braucht dann nur noch:

C#-Quelltext

1
2
3
for (var x = 0; x < pixelCount; x++)
    for(var y = 0; y < pixelCount; y++)
        recArray[x,y].Draw(grafik)

Werbeanzeige