Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 18.12.2011, 20:57 Titel: Array bei vielen Objekten der Objekt Menge anpassen? |
|
|
Ich habe da mal eine Frage zu dem Thema mehrere Objekte gleichzeitig darstellen. Wie macht ihr das wenn ihr mehrere Objekte darstellt und sie ihren nutzen verlieren? zb Gegner, Particle usw Explosions Effekte...
Ich habe mir mal folgendes Scenario zusammengecodet und wollte Frage ob ihr bei Objekten die Tot sind auch das Array von dennen Zerstört?
Das Problem ist ja falls in einer (For Each) Schleife es ja noch Objekte gibt die am Leben sind kann man ja nicht einfach das Array verändern. Ja gut in der Grösse ist es ja kein Problem aber wenn man es ja verkleinert sterben ja die anderen Objekte die vielleicht noch am leben sind auch da es keinen Verweiss mehr auf sie gibt.
Oder arbeitet ihr mit 2 Arrays wo ihr die noch lebenden zwischenspeichert und minimiert die Array nach und nach?
Oder legt ihr schon vorher fest wieviele zb Explosionen ihr benötigt und dafür ein Index Objekt Verweiss Array erstellt.
Dies hier ist mein bisheriger Code: Wo Lauter Pixel von den Wänden Abprallen und nach einander sterben. Doch ist es nicht sinnvoller das Array auch zu minimieren um bei der Performance später nicht einzuknicken?
Code: |
Type TBall
As Integer IsAlive
Public:
Declare Sub Draw()
Declare Sub Move()
Declare Sub Collision()
Declare Sub Init(ByVal xx As single,ByVal yy As Single,ByVal ss As Single,ByVal lt As Integer)
Private:
As Single x,y
As Single x_speed
As Single y_speed
As Single lifeTime
As UInteger r, g, b
End Type
Sub TBall.Init(ByVal xx As single,ByVal yy As Single,ByVal ss As Single,ByVal lt As Integer)
x = xx
y = yy
x_speed = ss
y_speed = ss + 0.1
IsAlive = 1
lifeTime = lt
r = Int(Rnd * 255)
g = Int(Rnd * 255)
b = Int(Rnd * 255)
End Sub
Sub TBall.Draw()
If IsAlive = 1 Then
circle (x,y),1,Rgb(r,g,b)
EndIf
End Sub
Sub TBall.Move()
If IsAlive = 1 Then
x += x_speed
y += y_speed
lifeTime -= 0.01
EndIf
If lifeTime <= 0 Then isAlive = 0
End Sub
Sub TBall.Collision()
If x < 0 Or x > 290 Then x_speed = -x_speed
If y < 0 Or y > 290 Then y_speed = -y_speed
End Sub
'##################################################################
ScreenRes 300,300,32
Randomize Timer
Const max = 1500
Dim Ball(max) As TBall
For i As Integer = LBound(Ball) To UBound(Ball)
Ball(i).Init(Int(Rnd * 300)-2,Int(Rnd * 300)-2,Rnd/2,(Rnd * 20) + (Rnd * 20) )
Next
Dim eingabe As String
Dim Alive As Integer
Do
eingabe = ""
eingabe = InKey
For i As Integer = LBound(Ball) To UBound(Ball)
Ball(i).Move
Ball(i).Collision
Next
If eingabe = "n" Then
For i As Integer = LBound(Ball) To UBound(Ball)
Ball(i).Move
Ball(i).Collision
Next
EndIf
ScreenLock
Cls
For i As Integer = LBound(Ball) To UBound(Ball)
Ball(i).Draw
If Ball(i).IsAlive = 1 Then
Alive += 1
EndIf
Next
Draw String (0,0),"Sprites Alive: " +Str(Alive)
Draw String (0,10),"Array Size: " +Str(UBound(Ball))
Alive = 0
ScreenUnLock
If eingabe = "q" Then End
Sleep 1
Loop
|
|
|
Nach oben |
|
 |
Flo aka kleiner_hacker
Anmeldungsdatum: 23.06.2006 Beiträge: 1210
|
Verfasst am: 18.12.2011, 23:46 Titel: |
|
|
ich nehme an dein problem kann man abstrahieren zu "wie kann ich groessere mengen an objekten / daten halten, sodass ich an beliebigen stellen problemlos objekte einfuegen oder entfernen kann? "
die antwort sind einfach oder doppelt verkettete listen, google mal danach
funzt in etwa so : jedes partikelobjekt enthaelt neben den daten auch noch einen zeiger / pointer auf das naechste (bei doppelt vek. listen auch auf den vorgaenger) objekt. wenn es das erate bzw letzte ist, ist der pointer NULL.
"in der mitte entfernen" ist einfach: den "nachfolgerpointer " des vorgängers des zu loeschenden objekts auf den nachfolger des zu loeschenden setzen.
und durchiterieren geht nimmer mut nem zaehler, sondern einen pointer, der immer auf dieserpointer->naechster gesetzt wird
hoffe das hilft
lg
flo _________________ MFG
Flo
Satoru Iwata: Wer Spaß am Spielen hat, fragt nicht nach Grafik.
zum korrekten Verstaendnis meiner Beitraege ist die regelmaessige Wartung des Ironiedetektors unerlaesslich. |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 19.12.2011, 14:02 Titel: |
|
|
Danke euch!
Ich werd mir das mit den verkettenen Listen genauer anschauen.
Also ist es besser wenn man für alle Game Objekte Listen benutzt weil sie besser zu händeln sind?
Gut man könnte ja auch mit einem Array arbeiten nur müsste man es ja immer Sortieren also die unbrauchbaren Objekte nach vorne um sie dann mit einem Redim zu killen.
Ist das auch ne gute möglichkeit? Oder ehr Performance fressend?
Aber ich denke wenn man zb Animierte Objekte die nicht umbedingt mehr oder weniger werden könnte man ja auch ganz normal mit nem Array Index
verwalten.
Ich versuche mir ja nur nen guten Progger Stil anzugewöhnen deshalb hatte ich ja die Fragen gestellt  |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 19.12.2011, 14:16 Titel: |
|
|
es gibt eigentlich 2 einfache varianten die man nutzen kann.
die erste ist eine LinkeList. Es ist eine Liste von Elementen, die chaotisch im speicher liegen, und bei welchen man sich von element zu element hangeln muss.
Es ist schnell wenn sich die liste sehr häufig ändert (hinzufügen / löschen). De zugriff auf ein element ist jedoch etwas langsamer als beim array.
die andere variante ist ein Array. Hier hat man genau die umgekerten vorteile des Linked List. Sie ist schnell beim zugriff auf ein element, und DEUTLICH langsamer beim hinzufügen uzw. löschen eines elementes.
Es gibt eine weitere alternative, welche aus einer kombination eines Arrays und einer Linkedlist besteht.
Hierbei wird das Array beim hinzufügen eines objektes vorvergrösert.
Wird ein element gelöscht, wird das gelöschte element in die Linkedlist seriel eingetragen. Damit schaft man die möglichkeit sehr schnell freie elemente im array zu finden.
Das durchlaufen des arrays wird trotz freier elemente relativ schnell sein. Ein Freies element muss hierbei natürlich als "unbenutzt" markiert werden.
Um direkten zugriff auf lineare elemente zu gestalten kann man eine weitere, nicht einfache technik nutzt.
Hierbei wird ein element array erzeugt, und eine lösch-linkedlist.
wir ein element gelöscht, wird es in die LL eingetragen.
Wird auf ein element zugegriffen (per lineraer indexnummer), kann dies über die löschliste erfolgen. Hierbei wird in das gelöschte element der pointer der linkedlist eingetragen, welcher dieses arrayelement speichert.
beim zugriff wird also nachgesehen ob das element gelöscht ist. ist dies der fall, greift man auf den pointer der ll zu und sieht anschliessend nach, ob das nächste element ebenfalls in der ll eingetragen ist. ist dies der fall, wird das ganze solange wiederholt, bis kein direkt nachfolgender eintrag gefunden wurde.
anschliessend kann der offset auf die indexnummer gerechnet werden, und auf das nächste valide element zugegriffen werden.
aber das ist schon ein sehr hoher aufwand an quellcode und nicht leicht zu schreiben.
Jedoch vereint es bei grösseren listen, die häufig ihren inhalt ändern die zugriffsgeschwindigkeit linear proportionel zur größe.
aber, ich glaube du bist mit einer einfachen linkedlist gut beraten.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 19.12.2011, 14:46 Titel: |
|
|
Thx ThePuppetMaster.
Ich werd mir das mal mit der Normalen List mal anschauen.
Und falls ich es mit einem Array machen würde müsste ich doch so vorgehen.
Erstelle Objekt(Index)
Update Objekt(Index) <= ist jetzt in der hauptschleife zb Animation,Tot oder am Leben
Dann bräuchte ich doch 2 schleifen oder ?
Damit ich das Array zb auf wichtigkeit erstmal überprüfe kann zb (ist am leben oder ist tot)
Falls dann musste ich ja die noch am lebenden objekte nach vorne reihen
also den inhalt eines lebenden objekts + parameter an ein totes übergeben. Dann müsste man doch per Redim das Array so anpassen das nur noch die lebenden dort enthalten sind also die toten abschneiden.
Beim hinzufügen ist es ja einfach dabei gehen ja die alten objekte ja nicht kaputt.
Sorry falls ich euch mit meinen Fragen Quäle
somit ist es wohl doch besser eine Liste zu verwenden oder nicht? |
|
Nach oben |
|
 |
Flo aka kleiner_hacker
Anmeldungsdatum: 23.06.2006 Beiträge: 1210
|
Verfasst am: 19.12.2011, 23:34 Titel: |
|
|
0oFreako0 hat Folgendes geschrieben: | Danke euch!
Ich werd mir das mit den verkettenen Listen genauer anschauen.
Also ist es besser wenn man für alle Game Objekte Listen benutzt weil sie besser zu händeln sind?
Gut man könnte ja auch mit einem Array arbeiten nur müsste man es ja immer Sortieren also die unbrauchbaren Objekte nach vorne um sie dann mit einem Redim zu killen.
Ist das auch ne gute möglichkeit? Oder ehr Performance fressend?
|
letzteres
jedes reallozieren (sprich, redim), erfordert eine volle kopie der objekte, oder wenigstens deren pointer, was bei größeren arrays immer länger dauern wird. (google mal nach komplexität von algorithmen, landausymbolen etc. redim hat O(n))
bei verketteten listen ist es egal wie viele elemente es sind, das geht in O(1)
allerdings kannst du bei listen nicht auf das 42te element einfach zu zugreifen. DAS geht bei arrays in O(1), also schnell, während du bei listen alle einträge durchgehen musst -> dauert
aber das will man meist eh nicht.
Zitat: |
Aber ich denke wenn man zb Animierte Objekte die nicht umbedingt mehr oder weniger werden könnte man ja auch ganz normal mit nem Array Index
verwalten. |
könnte man. kann man aber auch bleiben lassen
ich bin inzwischen eher so der C++-programmierer, dort ist es überhaupt kein problem, listen statt arrays zu nehmen. einfach std::list<foo> statt ein foo-array anlegen, fertig. fb sollte da aber auch fertige bibliotheken für haben...
alternativ können konstrukte wie c++'s (bzw das der STL) vector helfen: die machen das was du tun würdest: ein array immer redim-en. nur dass sie nicht für JEDES element das ding neu anlegen, sondern wenns zu klein wird, immer gleich 100 neue elemente oder so anlegen, quasi sich immer einen gewissen vorsprung schaffen...
aber das ist in aller regel nicht so performant wie listen. ymmv
lg
flo _________________ MFG
Flo
Satoru Iwata: Wer Spaß am Spielen hat, fragt nicht nach Grafik.
zum korrekten Verstaendnis meiner Beitraege ist die regelmaessige Wartung des Ironiedetektors unerlaesslich. |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 20.12.2011, 10:23 Titel: |
|
|
So ich habe mir mal folgendes Listen-Beispiel geschrieben.
Code: |
'Verkette Liste verstehen XD
Type tListe
Inhalt As Integer
_Name As String
Naechstes As tListe Ptr
End Type
Dim Shared Start As tListe Ptr
Dim Shared Neu As tListe ptr
Dim Shared Element As tListe Ptr
Start = Allocate(SizeOf(tListe))
Start->Naechstes = 0
Start->Inhalt = 1
Start->_Name = "Harry"
Neu = Allocate(SizeOf(tListe))
Neu->Inhalt = 2
Neu->Naechstes = Start
Neu->_Name = "Pixel"
Start = Neu
Neu = Allocate(SizeOf(tListe))
Neu->Inhalt = 3
Neu->_Name = "Morpher"
Neu->Naechstes = Start
Start = Neu
Element = Start
Do
Print Element->Inhalt
Print Element->_Name
If Element->Naechstes <> 0 Then
Element = Element->Naechstes
Else
Exit Do
EndIf
Loop
Sleep
End
|
Meine Frage ist jetzt wie lösche ich ein Element muss ich mir die adresse des vorrangigen speichern und dann das elementlöschen und die adresse in dem vorigen eintragen?
Und was ist wenn ich das alles in eine Schleife und particle erzeugen will.
Dann muss ich ja auch aufpassen das ich das erste Listen Element Initalisiere weil es ja eine 0 als Addresse haben muss. |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4699 Wohnort: ~/
|
Verfasst am: 20.12.2011, 12:42 Titel: |
|
|
Du durchläufst die Liste von vorn so weit, bis du das Element gefunden hast, das auf das zu löschende Element zeigt; ich nenne es mal den Vorgänger. Außerdem ermittelst du den Nachfolger des zu löschenden Elements. Der Vorgänger muss jetzt auf diesen Nachfolger verweisen; anschließend kannst du das gewünschte Element mit DEALLOCATE löschen. Vereinfacht ausgedrückt:
Code: | vorgaenger = listenstart
wiederhole bis vorgaenger->naechster->inhalt = zuLoeschen
vorgaenger= vorgaenger->naechster
ende wiederhole
merkedir = vorgaenger->naechster
vorgaenger->naechster = vorgaenger->naechster->naechster
loesche merkedir
|
Da sind Grenzfälle (Element existiert nicht) jetzt noch nicht abgefangen.
Wenn du direkt vom Anfang oder vom Ende der Liste löschen willst, geht es noch ein bisschen einfacher; beim Löschen aus der Mitte musst du aber die Liste so lange abklappern, bis du bei deinem gewünschten Ziel bist. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 20.12.2011, 15:31 Titel: |
|
|
wenn du elemente anhängst und von hinten wieder löscht, reicht eine "einfach verkettete Liste" Sie speichert nur den letzten pointer. alterntiv kann man auch vohrne anhängen und nur von vorne löschen.
möchte man beidseitig löschen oder auch in der mitte, dan braucht man eine "DoppeltVerkettete Liste"
Doppelte Liste mit beschreibung ... http://www.freebasic-portal.de/porticula/doublelinkedlist-1466.html
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 21.12.2011, 20:23 Titel: |
|
|
Hi Leute,
dank eurer Hilfe hab ich das mit den Verkettenen-Listen verstanden.
Aber eine kleine Frage hätte ich noch:
Zitat: | ich bin inzwischen eher so der C++-programmierer, dort ist es überhaupt kein problem, listen statt arrays zu nehmen. einfach std::list<foo> statt ein foo-array anlegen, fertig. fb sollte da aber auch fertige bibliotheken für haben... |
Weiss jemand was darüber ob FB sowas wie für C++ oder C# zur verfügung stellt und einem das mit dem selber coden von Listen-Konstrukten erspart?
Gruss 0oFreako0 |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 25.12.2011, 20:55 Titel: |
|
|
Ich bins nochmal.
Ich bin beim durchstöbern des Forums auf eine Interessante Include für Linkedlist gestossen.
http://www.freebasic-portal.de/porticula/test-linkedlistbas-838.html
Hier ist nun mein code:
Code: |
#Include "linkedlist.bi"
Type MyUDT
zahl As Integer
End Type
Dim TPtr As MyUDT Ptr
Dim List As LinkedList
Dim TItem1 As LinkedList
Print "Add"
For i As UInteger = 1 To 5
Tptr = Callocate(SizeOf(MyUDT))
With *TPtr
.zahl = i
End With
TItem1 = List.ADD(Cast(Any Ptr,TPtr))
Next
Print List.Count
For i As UInteger = 1 To List.Count
TItem1 = List.Item(i)
TItem1.Clear '<==Klappt nicht
Next
Print
Print "Ausgabe"
For i As UInteger = 1 To List.Count
With *Cast(MyUDT Ptr,List.Item(i).AnyData)
Print Str(.zahl)
End with
Next
LL_Destroy(List)
Print List.Count
Sleep
End
|
meine frage ist nun wie lösche ich ein bestimmtes objekt? |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4699 Wohnort: ~/
|
Verfasst am: 25.12.2011, 21:07 Titel: |
|
|
Wenn ich mir den Listentyp so ansehe
Code: | Type LinkedList
LLPtr as LL_INT_LinkedList Ptr
Declare Function Item (V_Index as UInteger) as LinkedList
Declare Function Index () as UInteger
Declare Function DataType () as LL_DataType
Declare Function Count () as UInteger
Declare Property Text () as String
Declare Property Text (as String)
Declare Property UNum () as UInteger
Declare Property UNum (as UInteger)
Declare Property Num () as Integer
Declare Property Num (as Integer)
Declare Property AnyData () as Any Ptr
Declare Property AnyData (as Any Ptr)
Declare Function Add Overload (V_String as String, V_Index as UInteger = 0) as LinkedList
Declare Function Add Overload (V_UInteger as UInteger, V_Index as UInteger = 0) as LinkedList
Declare Function Add Overload (V_Integer as Integer, V_Index as UInteger = 0) as LinkedList
Declare Function Add Overload (V_AnyPtr as Any Ptr, V_Index as UInteger = 0) as LinkedList
Declare Sub Del (V_Index as UInteger)
Declare Sub Clear ()
Declare Function SaveLL (V_PathFile as String, V_WithSubTree as Byte = 1) as Integer
Declare Function LoadLL (V_PathFile as String) as Integer
Declare Function SaveXML (V_PathFile as String, V_WithSubTree as Byte = 1) as Integer
Declare Function LoadXML (V_PathFile as String) as Integer
End Type |
tippe ich auf meineListe.del(index); habe ich aber nicht ausprobiert. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 25.12.2011, 21:13 Titel: |
|
|
Das mit dem Del hab ich schon ausprobiert.
Aber es wurde kein Objekt gelöscht  |
|
Nach oben |
|
 |
ThePuppetMaster

Anmeldungsdatum: 18.02.2007 Beiträge: 1839 Wohnort: [JN58JR]
|
Verfasst am: 25.12.2011, 21:13 Titel: |
|
|
Nun. das liegt einfach daran, weil die funktion "Clear" im Element der falsche weg ist.
Die Liste eine ist Tree-Liste. Sprich. Sie kann Elemente in elemente enthalten.
Code: |
element1 (ebene 1)
element1 in element1 (ebene 2)
element2 in element1 (ebene 2)
element1 in element2 in element1 (ebene 3)
element2 in element2 in element1 (ebene 3)
element3 in element2 in element1 (ebene 3)
element3 in element1 (ebene 2)
element4 in element1 (ebene 2)
element2 (ebene 1)
element1 in element2 (ebene 2)
element2 in element2 (ebene 2)
element3 in element2 (ebene 2)
element4 in element2 (ebene 2)
'...
|
(Baumstruktur wie im windows-explorer)
Was du machst ist folgendes:
1. Neue Liste erzeugen
Code: | Dim List As LinkedList |
2. Dieser Liste einträge hinzufügen. Der wert eiens eintrages ist ein Pointer welcher per callocate erzeugt wurde.
Code: | For i As UInteger = 1 To 5
Tptr = Callocate(SizeOf(MyUDT))
With *TPtr
.zahl = i
End With
TItem1 = List.ADD(Cast(Any Ptr,TPtr))
Next
|
3. Anzahl elemente ind er liste ausgeben
4. Alle elemente der ersten ebene durchgehen
Code: | For i As UInteger = 1 To List.Count
TItem1 = List.Item(i)
TItem1.Clear '<==Klappt nicht
Next
|
Hierbei setzt du das zurückgegebene element in die variable TItem1
dadurch kansnt du mit dieser Variable auf das zurückgegebene element zugreifen.
Dieses Element kann jetzt weitere elemente enthalten. so wie die Festplatte C ordner enthalten kann.
Du willst jetzt mit .Clear diese ordner auf der festplatte C löschen. Da du jedoch keien hinzugefügt hast, gibt es auch nichts zu leeren.
wenn du das .Clear kommandos jedoch auf die liste anwendest (List), dann löscht du damit die gesammte liste udn deren unterelemente
zu deiner frage:
du kannst mit .del ein element löschen.
siehe hierzu: http://www.freebasic-portal.de/porticula/test-linkedlistbas-838.html
bzw.
löscht das 1. element in der ersten ebene
Löscht das 1. element in der 2ten ebene, wenn TItem1 gesetzt wurde.
anders ausgedrückt:
Code: | List.Item(3).Del(1) |
Du greifst auf das 3. element auf ebene 1 zu (item) und löscht in dieser ebene das 1. element
vergleichbar mit
EDIT Wenn du keine Baumstrukturen haben willst, dann nutze einfach nur die List.... und nicht TItem bla ...
List ist immer auf die unterste ebene fixiert.
Alle kommandos .. List.Add / List.Del / List.Clear .. wirken sich immer auf die unterste ebene aus.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
 |
0oFreako0
Anmeldungsdatum: 17.12.2011 Beiträge: 114
|
Verfasst am: 25.12.2011, 21:23 Titel: |
|
|
Ahh ich habs verstanden
Danke TPM für dieses geile Inc file
Das erspart mir viel Tiparbeit  |
|
Nach oben |
|
 |
|