| |
VB.NET - Ein- und UmsteigerZufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 15:45 |
| Hallo,
ich habe ein Control, welches mir ein kariertes Feld zeichnet. Die Größe der zu zeichnenden Felder kann ich auch individuell bestimmen. Jetzt habe ich es so gemacht, dass wenn ich auf eines dieser Felder klicke das gesamte Feld ausgefüllt wird, also mit einer anderen Farbe übermalt wird. Entsprechende Funktionen habe ich alles schon fertig. Jetzt möchte ich aber zufällig einige Felder ausmalen lassen, also ohne, dass ich vorher darauf klicken muss.
Hier erstmal der Code, wie ich den habe:
Private Function GetFieldIndex(ByVal x As Integer, ByVal y As Integer) As _
Integer
' Errechnet den Index des Feldes (von links nach rechts)
Return (Me.Width \ FieldSize.Width) * (GetLineFromField(y) - 1) + _
GetColumnFromField(x) - 1
End Function
Private Function GetFieldPosition(ByVal x As Integer, ByVal y As Integer) As _
Point
' Errechnet aus den X- und Y-Koordinaten die Zeilen- und Spaltennummer
Return New Point(GetColumnFromField(x), GetLineFromField(y))
End Function
Private Function GetFieldRectangle(ByVal x As Integer, ByVal y As Integer) _
As Rectangle
' Errechnet aus der X- und Y-Koordinate das entsprechende Rechteck
Dim width As Integer = FieldSize.Width - 1
Dim height As Integer = FieldSize.Height - 1
Return New Rectangle((x \ FieldSize.Width) * FieldSize.Width, (y \ _
FieldSize.Height) * FieldSize.Height, width, height)
End Function
Private Function GetFieldRectangle(ByVal FieldPosition As Point) As Rectangle
' Errechnet aus der Zeilen- und Spaltennummer das entsprechende Rechteck
Dim width As Integer = FieldSize.Width - 1
Dim height As Integer = FieldSize.Height - 1
' X und Y Koordinaten mit 1 subtrahieren, damit das Raster nicht
' überzeichnet wird
Return New Rectangle((FieldPosition.X - 1) * FieldSize.Width, ( _
FieldPosition.Y - 1) * FieldSize.Height, width, height)
End Function
Private Function GetColumnFromField(ByVal x As Integer) As Integer
' Spalte berechnen und mit 1 addieren (verhindert null-basierte Spalte)
Return x \ FieldSize.Width + 1
End Function
Private Function GetLineFromField(ByVal y As Integer) As Integer
' Zeile berechnen und mit 1 addieren (verhindert null-basierte Zeile)
Return y \ FieldSize.Height + 1
End Function
Private Sub Field_Paint(ByVal sender As System.Object, ByVal e As _
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
' Berechne, wie viele vertikalen Linien gezeichnet werden können
For i As Integer = 0 To Me.Width \ FieldSize.Width
' Vertikale Linie zeichnen
e.Graphics.DrawLine(New Pen(pLineColor), i * FieldSize.Width - 1, 0, i _
* FieldSize.Width - 1, Me.Height)
Next
' Berechne, wie viele horizontalen Linien gezeichnet werden können
For i As Integer = 0 To Me.Height \ FieldSize.Height
' Horizontale Linie zeichnen
e.Graphics.DrawLine(New Pen(pLineColor), 0, i * FieldSize.Height - 1, _
Me.Width, i * FieldSize.Height - 1)
Next
' Anzahl der Einheiten (Felder) zeichnen
For i As Integer = 0 To pUnits.Length - 1
' Rechteck zum ausfüllen berechnen und zeichnen
e.Graphics.FillRectangle(New SolidBrush(pUnits(i).Color), _
GetFieldRectangle(pUnits(i).Position))
Next
End Sub
Private Sub Field_MouseClick(ByVal sender As System.Object, ByVal e As _
System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseClick
' Überprüfe, ob jede Einheit (Feld) im Array gezeichnet wurde
If pUnitsSet < pUnits.Length Then
' Wenn nicht, dann die Position für nächste Einheit (Feld) festlegen
pUnits(pUnitsSet).Position = GetFieldPosition(e.X, e.Y)
' Zähler um 1 erhöhen
pUnitsSet += 1
' Zu zeichnendes Rechteck neuzeichnen lassen
Me.Invalidate(New Region(GetFieldRectangle(e.X, e.Y)))
End If
End Sub Dabei ist pUnit ein Array von Objekten vom Typ Unit. Diese beinhalten eine Eigenschaft Position, welches die Zeilen- und Spaltennummer beinhaltet, wo dieses gezeichnet werden soll und eine Eigenschaft Color, die die entsprechende Farbe beinhaltet. Color ist hierbei aber unwichtig.
Wie kann ich also nun nach Zufallsprinzip diese Felder zeichnen lassen? Allerdings soll es nur auf der linken Hälfte des gesamten Controls passieren! Ich brauche also eine Funktion, die die Felder auf der linken Hälfte des Controls nach Zufallsprinzip ausmalt. Dabei kann die Anzahl aber variieren, also die Größe des Arrays pUnits. Vielleicht sollte die Funktion auch überprüfen, ob überhaupt soviele freie Felder dafür vorhanden sind. Bei Bedarf kann ich das Control auch in ein neues Projekt packen und als Archiv irgendwo hochladen (wobei das hier schon fast alle Methoden sind).
Danke schonmal | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: errt | Datum: 20.09.08 16:54 |
| Ich denke, ein sinnvoller Ansatz wäre, alle Felder auf der entsprechenden Seite in einer Schleife durchzugehen (bzw. alle Felder durchgehen und dann jeweils prüfen ob das aktuelle Feld auf der entsprechenden Seite ist) und immer wenn eine Zufallszahl < als ein festgelegter Wert (zwischen 0 und 1) ist, das Feld auszumalen. Der festzulegende Wert ist dann der zu erwartende Anteil ausgemalter Felder. | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 17:08 |
| Also die Indizes der erlaubten Felder in ein Array packen (Funktion zum ermitteln des Index habe ich ja) und das dann durchlaufen. Dazu einen Wert von 0 und 1 und 1 heißt in dem Sinne beispielsweise Feld ausfüllen. Soweit klar. Allerdings fehlt mir der Ansatz, wie ich die erlaubten Felder in ein Array packen kann. Also ich weiß nicht, wie ich die erlaubten Indizes ermittle, ob die auf der richtigen Seite sind... | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: FlyingEagleLW | Datum: 20.09.08 18:40 |
| das hängt doch davon ab wie und ob du zählst und in welcher richtung
*1
[0] [1] [2] [4]
[5] [6] [7] [8]
oder
*2
[0] [2] [4] [6]
[1] [3] [5] [7] bei *1: zwei schleifen, die erste geht waagerecht, die zweite senkrecht. zuerst mal weißt du ja wieviele in einer reihe sind. damit die hälfte ermitteln (das ist alle_waagerecht / 2 danach dann immer nur bis zur hälfte alle waagerechten durchgehen, pack die dann einfach in ein array und zufallsgenerator drüber wie ert schon sagte.
bei *2: wäre es ähnlich wie in 1, nur das du da die beiden schleifen vertauschen müsstest.
Beitrag wurde zuletzt am 20.09.08 um 18:40:52 editiert. | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 19:30 |
| Danke für eure Hilfe. Jetzt habe ich eine Lösung gefunden. Das war sogar ziemlich einfach, wenn man erstmal drauf kommt
Dim leftArray As New List(Of Point)
Dim leftWidth As Integer = CInt(Math.Ceiling(GetColumnFromField(Me.Width _
- 2) / 2))
Dim leftHeight As Integer = GetLineFromField(Me.Height - 2)
For i As Integer = 0 To leftHeight
For j As Integer = 0 To leftWidth
leftArray.Add(New Point(i, j))
Next
Next
For i As Integer = 0 To leftArray.Count - 1
Debug.WriteLine(leftArray(i).ToString)
Next Bei mir ist übrigens 1. der Fall. Meine Indizes sind von links nach rechts angeordnet. Da ich jetzt ein Point-Objekt habe kann ich das in einen Index umrechnen. Ich muss ja meine vorhande Funktion nur noch ein wenig umschreiben, damit es ein Objekt vom Typ Point entgegennimmt. Dann sollte das klappen.
Vielleicht brauch ich den Index auch gar nicht. Ich glaube mit dem Point-Objekt kann ich mehr anfangen. Nochmal kurz drüber nachdenken. Danke jedenfalls für die Denkanstöße. | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 19:44 |
| Habe allerdings noch eine Frage. Wieviele Felder ausgefüllt werden soll ist ja vorgegeben, kann aber auch variieren. Wie kann ich die Zufallswerte nun so vergeben, dass auch wirklich genau diese Anzahl gezeichnet wird, also mit einer 1 gekennzeichnet werden und alle anderen mit einer 0? Es muss im Endeffekt die Anzahl der vergebenen 1 mit der Anzahl der auszufüllenden Felder übereinstimmen. Wie mache ich das? | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: errt | Datum: 20.09.08 20:42 |
| Ich würde den Anteil der zu färbenden so wählen, dass zu erwarten ist, dass die gewünschte Anzahl Felder gefüllt wird. Dann in der Schleife mitzählen wieviele gefüllt wurden. Ist die Zahl erreicht, wieviele gefüllt werden sollen, brichst du die Schleife ab. Ist am Ende der Schleife die Zahl noch nicht erreicht, gehst du die Schleife nochmal durch. Hat nur den Nachteil dass wahrscheinlich mehr ausgefüllte Felder im oberen Bereich gefüllt werden als im unteren. | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 20:45 |
| Das dachte ich mir auch schon, aus dem von dir genannten "Problem" wollte ich das nicht machen. Allerdings habe ich mir überlegt: Wenn ich die Liste mit den erlaubten Feldern irgendwie mische, also so, dass alle Elemente nicht mehr logisch aneinander gereiht sind, dann kann ich einfach in einer Schleife den Wert auf 1 setzen und kann das auch ganz leicht überprüfen, ob die Anzahl schon erreicht wurde. Allerdings finde ich keine Funktion zum mischen der einzelnen Array Elemente Hat vielleicht jemand was dazu? | |
Re: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 22:48 |
| Also.. ich habe das nun soweit, dass zufällig in einem bestimmten Bereich Felder ausgemalt werden. Allerdings variiert die Anzahl, obwohl immer 5 gefüllt werden sollten. Manchmal sind es 5, manchmal auch nur 4 oder gar 3.
[code Public Sub SetRandom()
' Array erstellen
Dim leftSideArray As List(Of Point) = LeftSide()
' Array mischen
ShuffleArray(leftSideArray, 7)
' Anzahl der Einheiten durchlaufen
For i As Integer = 0 To pUnits.Length - 1
' Eigenschaft der Einheit setzen
pUnits(i).Position = leftSideArray(i)
' Anzahl gesetzter Einheiten erhöhen
pUnitsSet += 1
' Entsprechenden Bereich neu zeichnen
Me.Invalidate(New Region(GetFieldRectangle(pUnits(i).Position)))
Debug.WriteLine(leftSideArray(i))
Next
End Sub
Private Function LeftSide() As List(Of Point)
' Array deklarieren
Dim leftArray As New List(Of Point)
' Hälfte der Felder der Breite ermitteln
Dim leftWidth As Integer = CInt(Math.Ceiling(GetColumnFromField(Me.Width - 2) / 3))
' Höhe ermitteln
Dim leftHeight As Integer = GetLineFromField(Me.Height - 2)
' Alle verfügbaren Felder in die Liste aufnehmen
For i As Integer = 0 To leftHeight
For j As Integer = 0 To leftWidth
leftArray.Add(New Point(i, j))
Next
Next
Return leftArray
End Function
Private Sub ShuffleArray(ByRef arrayToBeShuffled As List(Of Point), ByVal numberOfTimesToShuffle As Integer)
Dim rndPosition As New Random(DateTime.Now.Millisecond)
For i As Integer = 1 To numberOfTimesToShuffle
For i2 As Integer = 1 To arrayToBeShuffled.Count
swap(arrayToBeShuffled(rndPosition.Next(0, arrayToBeShuffled.Count)), arrayToBeShuffled(rndPosition.Next(0, arrayToBeShuffled.Count)))
Next i2
Next i
End Sub
Private Sub swap(ByRef arg1 As Point, ByRef arg2 As Point)
Dim strTemp As Point = arg1
arg1 = arg2
arg2 = strTemp
End Sub]Damit habe ich das versucht, aber irgendwie scheint das nicht ganz zu funktionieren. Ich bin mal mit dem Debugger durchgegangen und jede Einheit bekommt eine Position zugewiesen und sollte auch angezeigt werden, aber irgendwie gehts nicht. Hoffe jemand findet den Fehler. | |
Lösung: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 20.09.08 23:22 |
| Ich hatte einen kleinen Fehler beim erstellen meiner Liste für die linke Seite erlaubter Zeichen. Da gibts Positionen mit einer 0, was in dem Control außerhalb des sichtbaren Bereiches ist. Habe also dafür gesorgt, dass das nicht mehr passiert. Ergo meine ganzen Probleme sind gelöst. Danke für die Hilfen | |
Re: Lösung: Zufällige Rechtecke im Control ausmalen | | | Autor: FlyingEagleLW | Datum: 21.09.08 02:07 |
| bitte schön, gern geschehen.
Tip: quellcode in die code-blöcke packen
aber ich hätte da noch ne idee ohne das array "zu mischen" ...
du gehst durch die von mir beschriebenen schleifen und sammelst alle felder als feld(+index o.ä.) in einem array (alle die meinetwegen links sind) und nimmst danach x-zufallszahlen, die als untergrenze die untergrenze und als obergrenze die obergrenze des array haben. dann sollte es auch eine ausgewogene verteilung geben (insofern der randomizer mitspielt . wenn du die felder als elemente/objekte in deinem array hast und diese z.b. als klassen/objekte ansprechbar sind sollte das relativ simpel sein. wobei mit array eine collection gemeint ist.
würde mich aber mal interessieren was genau du da eigentlich proggst, falls du uns das verraten kannst/darfst/willst. | |
Re: Lösung: Zufällige Rechtecke im Control ausmalen | | | Autor: keco | Datum: 21.09.08 13:31 |
| Das mit dem Code war ein Unfall... habe mich beim reinkopieren irgendwie verklickt :x
Danke noch für deinen Ansatz, aber ich hatte mit dem Randomizer schonmal das Problem, dass der ständig gleiche Zahlen ausgespruckt hatte, weil das irgendwie viel zu schnell ging, mit einem Sleep dazwischen wars wenigstens durcheinander, aber naja. Möchte das nicht riskieren. Und jetzt, wo ich schon die FUnktion habe zum mischen und auch mit dem Ergebnis zufrieden bin, möchte ich nicht weiter drin rumrühren.
An sich sind eigentlich nicht alle Felder ansprechbar, also möglich ist es schon, aber die brauche ich nicht ansprechen, sondern nur die ausgefüllten. Im Endeffekt soll das eigentlich eine Art Spielfeld darstellen, wobei die ausgefüllten Felder die Spielfiguren sind. Deswegen brauche ich auch nur die Spielfiguren auswählen und nicht die einzelnen Felder. Deswegen gibt es nur ein Array mit den Spielsteinen. Wird auf das Spielfeld geklickt werden die Pixel-Koordinaten in meine Feld-Koordinaten umgerechnet und mit der Position-Eigenschaft der einzelnen Spielsteine verglichen. Ist eine Übereinstimmung dabei wird die Eigenschaft SelectedUnit eben mit dem ausgewählten Stein gesetzt. | |
Re: Lösung: Zufällige Rechtecke im Control ausmalen | | | Autor: FlyingEagleLW | Datum: 21.09.08 14:32 |
| den randomizer kann man imho auch mit parametern starten, wo man dann z.b. die aktuelle zeit übergibt und man dann dadurch etwas "zufälligere" zahlen erhält.
aber wenn es so funktioniert wie du dir das vorstellst ist ja alles prima.
am ende entscheidet ja ohnehin meistens das ergebnis und nicht nur der weg. letzterer ist nur bei zeitkritischen geschichten interessant(er). musst halt mal gucken ob mein ansatz oder dein ansatz am ende in diesem punkt schneller wäre. | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
vb@rchiv CD Vol.6 vb@rchiv Vol.6
Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
Online-Update-Funktion Entwickler-Vollversionen u.v.m.Jetzt zugreifen Tipp des Monats sevAniGif (VB/VBA)
Anzeigen von animierten GIF-Dateien
Ab sofort lassen sich auch unter VB6 und VBA (Access ab Version 2000) animierte GIF-Grafiken anzeigen und abspielen, die entweder lokal auf dem System oder auf einem Webserver gespeichert sind. Weitere Infos
|