amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Wie programmiert man denn am besten folgendes: [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- [ - Beitrag schreiben - ]

06.05.2003, 20:29 Uhr

Reth
Posts: 1858
Nutzer
Hallo zusammen,

ich bräuchte mal ein paar gute Ideen. Ich möchte ein Spiel in C++ programmieren (hatte ich schon mal in C, ging leider verloren) und dazu ein paar Features gestalten (waren in der alten, verlorenen Version nicht).

Es geht darum, wie man am besten animierte Objekte darstellt.

Zur Zeit habe ich nen festen Screenmode für das Spiel eingestellt: 1024x768, soll sich später mal ändern mit SCrolling usw. Aber das ist Zukunftsmusik.

Im Augenblick gehts gerad darum, dass der Spieler Objekte per Mausklick setzen kann (funktioniert schon), diese sollen aber animiert aufgebaut werden (in 3 Phasen) und im weiteren Verlauf des Spieles evtl. weitere Animationen zeigen.

Nun ist das Ganze ja eventgesteuert und ich lasse mir auch IDCMP_INTUITICK Messages geben. Damit will ich so ca. alle 3 Sek. checken, ob ne neue Stufe irgend einer Animation geblittet werden muss.
Nun scheints aber so zu sein, dass wenn der Spieler weiter mit der Maus arbeitet, das Zeitintervall anscheinend nicht eingehalten wird (die Messages der INTUITICKS kommen wohl nicht mehr regelmäßig, wenn inzwischen andere Messages kommen und verarbeitet werden)!?

Meine Frage ist: Wie programmiert man denn am besten solche Animationen? In eigenen Tasks? Habe leider im Umgang mit Taskprogrammierung noch gar keine Erfahrung, gibts da gute Tutorials (die diesbezüglichen Threads hier im Forum hab ich schon gelesen, das langt für mich als Anfänger in Taskprogr. nur bedingt)?

Kann mir da jemand weiterhelfen?

Danke schon mal

Ciao

[ - Antworten - Zitieren - Direktlink - ]

06.05.2003, 20:57 Uhr

Kronos
Posts: 1168
Nutzer
Ein kleiner Trick wäre es wenn du einfach die Timestamps ALLER
Nachrichten überprüfts, egal ob MOUSEMOVE oder INTUITICK.

Da sollten eigentlich immer genug kommen.

MfG
Kronos
--

Only the good die young all the evil seem to live forever

[ - Antworten - Zitieren - Direktlink - ]

06.05.2003, 22:27 Uhr

mrbbc
Posts: 101
Nutzer
Also erstens gäb's es keinen triftigen Grund, C++ zu nehmen, wenn du mit C bestens vertraut bist.

Da du wohl aber von Null anfängst, total wurscht...

Eventsystem... :-/

Bei Spielen kommt das nicht unbedingt zur Geltung, denn ganz generell brauchst du eine Endlosschleife - also eine Schleife, die quasi dein Hauptprogramm ist.

Eine Endlosschleife ist ja auch das Eventsystem. Wenn was passiert, verarbeitet es das Ereignis und generiert ein passendes Event...

In deiner Endlosschleife muss aber auch noch der Bildschirm gezeichnet werden. Das geht nicht mit ereignisorientierter Programmierung; höchstens mit einem Timerevent, der Timer müsste aber mindestens im Dezisekundentakt auslösen und das bremst wieder wie sau...

Tasks bzw. Threads machen nur bei bestimmten CPUs Sinn, z.B. Multiprozessormaschinen. Schwachsinn ist es aber, so viele Threads wie möglich zu machen. Das Optimum sind wohl so 4 Threads für ein Programm.

Das ist aber zu kompliziert und unnötig aufwendig.

Also, Endlosschleife: die könntest du in einen eigenen Thread packen, aber grundsätzlich geht das auch, wenn du sie in eine Funktion packst, die NICHT über ein Event gestartet wird, bzw. nur über das eine Event, das eben nur beim Programmstart einmal ausgelöst wird.

Das Event, das das Programmende auslöst, muss dann eben diesen Thread bzw. eben einfach die Endlosschleife auflösen. Dazu nimmst du am besten eine globale Variabele als Abbruchbedingung, die du dann auf "Cancel" setzt...

---

Die Endlosschleife kümmert sich ums Zeichnen. Dazu musst du jedes Objekt, das gezeichnet wird, speichern. Position + Animationsphase# + Bewegungsrichtung/Vektor pro x Millisekunden. Ausserdem einen Zeitstempel in Millisekunden, damit du eine variabele Framerate erzielen kannst.

Alternativ kannst du auch eine Wartesequenz einfügen, die jeden Frame auf x Millisekunden synchronisiert, d.h. nach z.B. 100 Millisekunden wird immer ein neuer Frame erst sichtbar gemacht[1], egal, ob er 10 oder 80 Millisekunden zum Zeichnen gebraucht hat...

[1] mit flipscreen/swapscreen/doublebuffering oder wie es auch immer genannt wird

So in der Art wird jedes Spiel gemacht, eben u.a. weil es viel schneller geht, als quasi voll objektorientiert jeden Sprite sich selbst zeichnen zu lassen.

--
it obvisiously seems to have been hard to write

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 08:41 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von mrbbc:
Also erstens gäb's es keinen triftigen Grund, C++ zu nehmen, wenn du mit C bestens vertraut bist.


Darum gehts ja: Ich wills gern lernen. Am besten macht man (in dem Fall ich) das so!

Zitat:
Da du wohl aber von Null anfängst, total wurscht...

Wie mans nimmt. In C++ ist genug C enthalten und OO-Programmierung mach ich schon ein paar Jahre.

Zitat:
Eventsystem... :-/

Bei Spielen kommt das nicht unbedingt zur Geltung, denn ganz generell brauchst du eine Endlosschleife - also eine Schleife, die quasi dein Hauptprogramm ist.
Eine Endlosschleife ist ja auch das Eventsystem. Wenn was passiert, verarbeitet es das Ereignis und generiert ein passendes Event...


Das weiss ich. Dieser Teil steht auch schon. Ich habs halt Eventsystem genannt, da das ganze Konzept von Amigas Intuition ereignisorientiert arbeitet.
Ich bekomme die von mir gewünschten Ereignisse (wie schon erwähnt) zugestellt und kann darauf reagieren.

Zitat:
In deiner Endlosschleife muss aber auch noch der Bildschirm gezeichnet werden. Das geht nicht mit ereignisorientierter Programmierung; höchstens mit einem Timerevent, der Timer müsste aber mindestens im Dezisekundentakt auslösen und das bremst wieder wie sau...

Tasks bzw. Threads machen nur bei bestimmten CPUs Sinn, z.B. Multiprozessormaschinen. Schwachsinn ist es aber, so viele Threads wie möglich zu machen. Das Optimum sind wohl so 4 Threads für ein Programm.

Das ist aber zu kompliziert und unnötig aufwendig.

Also, Endlosschleife: die könntest du in einen eigenen Thread packen, aber grundsätzlich geht das auch, wenn du sie in eine Funktion packst, die NICHT über ein Event gestartet wird, bzw. nur über das eine Event, das eben nur beim Programmstart einmal ausgelöst wird.

Das Event, das das Programmende auslöst, muss dann eben diesen Thread bzw. eben einfach die Endlosschleife auflösen. Dazu nimmst du am besten eine globale Variabele als Abbruchbedingung, die du dann auf "Cancel" setzt...


Also wie nun: Tasks sind nicht gut, aber ich soll trotzdem einen/mehrere erzeugen? Das man nicht ewig viele Threads produzieren soll ist ja wohl klar.
Aber was willst Du mir nun damit sagen? Die Schleife, die das wiederholte Darstellen auf dem Bildschirm übernimmt soll in nen eigenen Task (kenne keine Threadbibliothek für AmigaOS, Tasks dürften OK sein) und die ereignisbasierten Teile der Anwendung (Userinteraktionen usw.) in einen anderen?
Zur Zeit ist bei mir alles in einer Hauptklasse, die Endlosschleife (bei Ereignissen wird meine Handlerklasse informiert, welche die Auswertung übernimmt), sowie die Zeichenroutinen.
Wie sorge ich dafür, dass mein Zeichentask kein Busy-Waiting macht? Schicke ich ihm ein Signal, wenn mein Message-Handler eine INTUITICKS-Nachricht bekommt?

Zitat:
---

Die Endlosschleife kümmert sich ums Zeichnen. Dazu musst du jedes Objekt, das gezeichnet wird, speichern. Position + Animationsphase# + Bewegungsrichtung/Vektor pro x Millisekunden. Ausserdem einen Zeitstempel in Millisekunden, damit du eine variabele Framerate erzielen kannst.


Hm, für diese Details fehlt mir noch die Erfahrung. Von den Sachen (also was Animationsberechnungen u. dgl. angeht) hab ich ehrlich gesagt noch keine Ahnung, hab mir bisher die Sachen selbst gebaut, war aber auch alles noch nicht so performancehungrig.
Hier eignen sich Objekte hervorragend! Jedes weiss, in welchem Zustand es sich befindet (soll keine flüssige Animation werden, eher eine Bildfolge) und in welcher Position. Ein Zeitstempel ist ne sehr gute Idee, bekommt auch noch jedes Objekt mit, damit nicht alle Objekte imner gleichzeitig nach genau einer Zeitspanne neu gezeichnet werden, sondern jedes in gleichen Intervallen, abhängig von seiner Startzeit! Damit man sich ungefähr vorstellen kann, wovon ich spreche: Es geht darum, ein Gebäude, wenn es einmal von einem Spieler gesetzt wurde in mehreren Etappen entstehen zu lassen (á la Siedler).
Das ganze funktioniert mit Blitting, wobei die notwendigen Daten trotz mehrfacher Verwendung nur einmal im Speicher liegen. Es gibt innerhalb der Anwendung Objekte, die die graphischen Objekte repräsentieren und mit denen die notwendigen Berechnungen vorgenommen werden. Evtl. ist meine Zuordnung zu den eigentliche Grafiken nicht annähernd optimal (liegt aber auch an der Konstruktion der Spielelemente, diese ist an "Die Siedler von Catan" angelehnt), aber das ist ein ganz anderes Thema, darüber könnnen wir aber gern fachsimpeln, wenns Dich (jemand) interessiert, denn gerade in dem Bereich bin ich für effiziente Ideen sehr empfänglich!

Zitat:
Alternativ kannst du auch eine Wartesequenz einfügen, die jeden Frame auf x Millisekunden synchronisiert, d.h. nach z.B. 100 Millisekunden wird immer ein neuer Frame erst sichtbar gemacht[1], egal, ob er 10 oder 80 Millisekunden zum Zeichnen gebraucht hat...

[1] mit flipscreen/swapscreen/doublebuffering oder wie es auch immer genannt wird

So in der Art wird jedes Spiel gemacht, eben u.a. weil es viel schneller geht, als quasi voll objektorientiert jeden Sprite sich selbst zeichnen zu lassen.

--
it obvisiously seems to have been hard to write


Vielen Dank für Deine Tipps, werde wohl demnächst hier öfters posten mit fortschreitender Entwicklungsdauer (v.a. wenn ich mal Computergegner einführen will)!

Nochmals Dank für all eure Tipps! Bin für weitere Hilfen immer dankbar!

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 10:49 Uhr

Solar
Posts: 3680
Nutzer
Zitat:
Original von mrbbc:
Also erstens gäb's es keinen triftigen Grund, C++ zu nehmen, wenn du mit C bestens vertraut bist.


Erweiterung des Horizonts? Vorteile von C++ bei wachsendem Programmumfang (Modularisierung, Namensräume etc.)? Man muß noch nicht einmal OO, Templates oder Exceptions nutzen, um von C++ zu profitieren... aber das ist bei vielen eher eine Glaubensfrage...

Zitat:
Eine Endlosschleife ist ja auch das Eventsystem. Wenn was passiert, verarbeitet es das Ereignis und generiert ein passendes Event...

?(

Komische Auffassung von einem Eventsystem...

Zitat:
...der Timer müsste aber mindestens im Dezisekundentakt auslösen und das bremst wieder wie sau...

...ein Event alle 0,1 Sekunden? "Bremsen wie Sau"? Oh Gott, ich darf nie wieder meine Maus anfassen... :)

Zitat:
Tasks bzw. Threads machen nur bei bestimmten CPUs Sinn, z.B. Multiprozessormaschinen.

Unfug. I/O- vs. CPU-Phasen, und alleine schon das Round Robin des Exec, machen Mutlithreading / Multitasking auch innerhalb einer einzigen Anwendung durchaus sinnvoll.

Zitat:
Schwachsinn ist es aber, so viele Threads wie möglich zu machen. Das Optimum sind wohl so 4 Threads für ein Programm.

Stimmt auch nicht. Klar bremsen übermäßig viele Threads ein System aus. Die "richtige" Anzahl hängt aber zum ersten von der CPU ab (siehe Hyperthreading), zum zweiten von der OS-Unterstützung, zum dritten von der Anwendung. Was Du hier sagt, mrbbc, ist eine unzulässige Verallgemeinerung.

Zitat:
Original von Reth:
(kenne keine Threadbibliothek für AmigaOS, Tasks dürften OK sein)


Aufgrund seiner Architektur (kein Speicherschutz) kennt AmigaOS prinzipiell keinen Unterschied zwischen Task und Thread. (Ein "Thread" im klassischen Sinne ist ein Kontrollfluß in einem Adreßraum / Prozeß; "Multithreading" meint mehrere Kontrollflüsse in demselben Adreßraum.)

Zitat:
...und die ereignisbasierten Teile der Anwendung (Userinteraktionen usw.) in einen anderen?

Genau. So wird der Kontrollfluß der Grafik-Task nicht unterbrochen, wenn ein User-Input eintrifft. (Natürlich *wird* er unterbrochen, aber automatisch durch das OS statt durch Programmierung deinerseits.)

Zitat:
Wie sorge ich dafür, dass mein Zeichentask kein Busy-Waiting macht? Schicke ich ihm ein Signal, wenn mein Message-Handler eine INTUITICKS-Nachricht bekommt?

Klingt gut.

Zitat:
Original von mrbbc:
Alternativ kannst du auch eine Wartesequenz einfügen, die jeden Frame auf x Millisekunden synchronisiert, d.h. nach z.B. 100 Millisekunden wird immer ein neuer Frame erst sichtbar gemacht[1], egal, ob er 10 oder 80 Millisekunden zum Zeichnen gebraucht hat...
[1] mit flipscreen/swapscreen/doublebuffering oder wie es auch immer genannt wird


Doublebuffering.


[ Dieser Beitrag wurde von Solar am 07.05.2003 editiert. ]

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 11:02 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von Solar:

Zitat:
Eine Endlosschleife ist ja auch das Eventsystem. Wenn was passiert, verarbeitet es das Ereignis und generiert ein passendes Event...

?(

Komische Auffassung von einem Eventsystem...


Wie fasst Du denn Eventsystem auf, bzw. ereignisbasierte Programmierung? Ich habs so kennengelernt (salopp formuliert), dass solange auf ein Ereignis gewartet wird, bis eins ausgelöst wird, danach die Arbeit erledigt und in den Wartezustand zurückkehrt.
Beim Amiga wird das durch div. Wait..()-Anweisungen erledigt, mit denen man z.B. auf eine Intuition-Nachricht warten kann.
Dieser ganze Zyklus wiederholt sich am besten doch in einer Schleife (Endlosschleife), so lange, bis ein Abbruchkriterium erfüllt ist!? Oder nicht? Ich habe jedenfalls schon einige Beispiel-Sourcen für den Amiga (und auch andere ereignisbasierte Systeme, wie z.B. die Java-GUI) gesehen, die das genau so machen. Das muss natürlich nicht heissen, dass das richtig ist. Wie macht man's denn aber sonst?

Zitat:
Zitat:
Wie sorge ich dafür, dass mein Zeichentask kein Busy-Waiting macht? Schicke ich ihm ein Signal, wenn mein Message-Handler eine INTUITICKS-Nachricht bekommt?

Klingt gut.


Danke. Nun muss ich "nur" noch Taskprogrammierung auf dem Amiga lernen!
Danke für Deinen Rat.

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 11:32 Uhr

Solar
Posts: 3680
Nutzer
Statt eine Endlosschleife zu haben, die jeden Durchlauf beim Wait...() blockiert, ist eine andere Implementierung recht verbreitet: Eventhandler / Callbacks. Dabei wird eine Funktion (Handler) beim System "registriert", und dann beim Auftreten des Events vom System aufgerufen (Callback).

Inwieweit das AmigaOS dies unterstützt, weiß ich nicht. Als ich mit "fortgeschrittener" Programmierung anfing, war Amiga schon auf dem absteigenden Ast ;( , so daß ich kaum praktische Erfahrung mit der AmigaOS-API habe. Aber quasi alle Systeme, die ich seither kennengelernt habe, arbeiten mit Callbacks.

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 15:14 Uhr

tokai
Posts: 1071
Nutzer
Zitat:
Original von Solar:
Inwieweit das AmigaOS dies unterstützt, weiß ich nicht. Als ich mit "fortgeschrittener" Programmierung anfing, war Amiga schon auf dem absteigenden Ast ;( , so daß ich kaum praktische Erfahrung mit der AmigaOS-API habe. Aber quasi alle Systeme, die ich seither kennengelernt habe, arbeiten mit Callbacks.


Hooks. :)



--
years flow as water, lake reflects flowers and moon

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 21:09 Uhr

mrbbc
Posts: 101
Nutzer
Zitat:
Original von Reth:
Also wie nun: Tasks sind nicht gut, aber ich soll trotzdem einen/mehrere erzeugen? Das man nicht ewig viele Threads produzieren soll ist ja wohl klar.


So nun: Threads sind je nach Zielplattform schneller, allerdings auch viel komplizierter zu handhaben, vorallem, wenn du z.B. das Zeichnen des Bildschirms auf mehrere Threads verteilst, sodass du zwischen Threads auch noch koordinieren musst.

Zu der "unzulässigen Verallgemeinerung": man müsste sehen, was für eine CPU/wieviele. Moderne CPUs haben mehrere parallele Befehlsinterpreter, beim sog. "Hyperthreading" sind's besonders viele. Im Grunde hat man also virtuell einen Multiprozessorcomputer.

Multithreading kostet ein wenig Performance. Wenn man aber im Gegenzug die Last effektiver verteilen kann, hat man einen kleinen Leistungsschub.

Zwingend notwendig ist es aber nicht. Denn die CPU kann sich ja auch nebenbei noch mit Betriebssystemdingen befassen. Die CPU wird also sicher nicht halb ungenutzt gelassen - wenn das Betriebssystem sie voll unterstützt.

Zitat:
Aber was willst Du mir nun damit sagen? Die Schleife, die das wiederholte Darstellen auf dem Bildschirm übernimmt soll in nen eigenen Task (kenne keine Threadbibliothek für AmigaOS, Tasks dürften OK sein) und die ereignisbasierten Teile der Anwendung (Userinteraktionen usw.) in einen anderen?

Genau.

Zitat:
Zur Zeit ist bei mir alles in einer Hauptklasse

Klingt nach prozeduraler OOP... ;o)

Zitat:
Wie sorge ich dafür, dass mein Zeichentask kein Busy-Waiting macht?

Da gibt es viele Wege. Z.B. kannst du deine Zeichenroutine in bestimmen Zeitabständen aufrufen, du kannst in deiner Synchronisationswarteschleife die Eventhandlerroutine einbauen...

Was natürlich alles sehr prozedural ist. Das ist aber auch nicht gerade die ideale Anwendung von OOP.

Zitat:
Hm, für diese Details fehlt mir noch die Erfahrung. Von den Sachen (also was Animationsberechnungen u. dgl. angeht) hab ich ehrlich gesagt noch keine Ahnung

Es gibt keine "Animationsberechnung". Du musst die Animationsphasen von Hand zeichnen, wie ein Trickkünstler - die Grafik ist aber erst im letzten Drittel der Entwicklung zu vervollständigen.

Wenn du z.B. einen fliessenden Bach machst, zeichnest du den kompletten Bildschirm alle x Millisekunden neu, dabei wechselst du die animierten Felder mit der Grafik von ihrer nächsten Animationsphase aus.

Je nachdem genügt oft schon, alle 500 Millisekunden eine von 3 Phasen durch zu wechseln.

Zitat:
hab mir bisher die Sachen selbst gebaut, war aber auch alles noch nicht so performancehungrig.

Schritt 1: Machbarkeitsstudie.

Wieviele Sprites etc. pro Sekunde kann ich zeichnen ? etc. Je nach dem muss man die Zahl der Sprites nach Möglichkeit reduzieren und andere Optimierungsmöglichkeiten suchen, die Animationsphasen reduzieren und die Auffrischrate reduzieren usw.

Zitat:
Hier eignen sich Objekte hervorragend!

Jein. Nur in Form einer erweiterten struct-Variabele. Nicht aber mit einer Methode show(), also dass es sich quasi selbst in den Bildschirm zeichnet. Denn das frisst Rechenzeit.

Ausserdem schlage ich eine klare Trennung von Sprite und "Objekten" vor. Denn du hast wohl zum einen schlicht Landschaft und zum anderen deine Objekte, die besonderer Abarbeitung bedürfen.

Zitat:
Jedes weiss, in welchem Zustand es sich befindet (soll keine flüssige Animation werden, eher eine Bildfolge) und in welcher Position. Ein Zeitstempel ist ne sehr gute Idee, bekommt auch noch jedes Objekt mit, damit nicht alle Objekte imner gleichzeitig nach genau einer Zeitspanne neu gezeichnet werden, sondern jedes in gleichen Intervallen, abhängig von seiner Startzeit!

Du wirst noch mehr einbauen müssen, schließlich soll nicht jedes Objekt nach der gleichen Zeit fertiggestellt werden ?

Zitat:
Damit man sich ungefähr vorstellen kann, wovon ich spreche: Es geht darum, ein Gebäude, wenn es einmal von einem Spieler gesetzt wurde in mehreren Etappen entstehen zu lassen (á la Siedler).

Für diese "Animation" braucht man natürlich keinen Millisekundentakt... Da tut's jedes noch so ordinäre Timerevent.

Siedler hab' ich jetzt nicht so im Kopf... Aber du meinst wohl so was wie bei Railroad Tycoon auch, wo Gebäude "herbeigerauscht" wurden.

Normal würde man es aber wie bei WarCraft II machen, mit extra Sprites für die jeweilige Bauphase. Dann kannst du natürlich die Animationsphase aber nicht mehr berechnen...

BTW: gegebenenfalls solltest du die Option vorsehen, dass man die Spritepaletten auswechseln kann. Dann könnte man die Gebäude auch z.B. im Winter zeigen, auf palmenbewachsenen Inseln usw. wenn sich Grafiker dafür finden.

--
it obvisiously seems to have been hard to write

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 21:41 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von tokai:
...

Hooks. :)


Hast Du dafür ein gutes Codebeispiel (in C)?

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 22:12 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von mrbbc:

...
Zitat:
Zur Zeit ist bei mir alles in einer Hauptklasse

Klingt nach prozeduraler OOP... ;o)


Nur bedingt. Konnte natürlich nicht alles (den ganzen Source be-)schreiben. In meiner Hauptklasse wird alles initialisiert, Screen, Window, Bitmaps, Masken, Daten für Masken und Bitmaps usw.
Es gibt natürlich für die gnazen Anwendungsobjekte Klassen. Eine für Spielfeldteile (Hexagone), eine für Grafikobjekte, davon abgeleitet eine für Gebäude, eine fürs Eventhandling (ist ein echter EventHandler, wird vom OS gerufen, wenn eine Intuitionnachricht eintrifft, er ist natürllich mittels einer Endlosschleife in seiner Klassenbibliothek (nicht von mir) implementiert, das wohl aufm Amiga nicht anders geht, ist dennoch kein blockierendes Warten in diesen Ednlosschleifen, da man auf ein Signal/eine Nachricht wartet; man kann in dieser Zeit andere Programme nutzen und die CPU steht auch nicht bei 100%, ist nicht mal merkbar langsamer), eine fürs Verwalten der Hexagone, und und und.. (to be continued).

Zitat:
Ausserdem schlage ich eine klare Trennung von Sprite und "Objekten" vor. Denn du hast wohl zum einen schlicht Landschaft und zum anderen deine Objekte, die besonderer Abarbeitung bedürfen.

Genau das hab ich ja eigentlich (denke ich zumindest), ausser dass ich keine Sprites benutze. Meine Objekte sind nur "logisch", keine graphischen Objekte. Sie präsentiern in der Anwendung jedoch teilweise graphische Objekte. Jede Grafik ist nur einmal im Speicher vorhanden, kann aber beliebig oft geblittet werden.Vorgesehen ist, dass ich eine Verwalterklasse für alle Klassen mache, die graphische Objekte mit Animation beherbergt. Diese wird dann regelmässg gerufen, um alle Objekte ggf. neu zu zeichnen (also schon so ähnlich wie Du es mit der Show()-Methode angedeutet hast, aber wie sonst? Nicht-OO muss ich auch alle betroffenen Grafiken aktualisieren).

Zitat:
Du wirst noch mehr einbauen müssen, schließlich soll nicht jedes Objekt nach der gleichen Zeit fertiggestellt werden ?

Hab mich wohl missverständlich ausgedrückt. Der Zeitstempel den jedes Objekt (das eine animierte Grafik repräsentiert) erhält, entscheidet darüber, ob das Objekt aktualisert werden muss. Zusätzlich sind natürlich noch weitere Attribute denkbar, aber z.Zt.soll jedes Objekt nach der gleichen Zeit fertiggestellt sein (natürlich in Abhängigkeit seiner Startzeit, drum der eigene Zeitstempel). Später kann ich ja weitersehen!

Zitat:
...
BTW: gegebenenfalls solltest du die Option vorsehen, dass man die Spritepaletten auswechseln kann. Dann könnte man die Gebäude auch z.B. im Winter zeigen, auf palmenbewachsenen Inseln usw. wenn sich Grafiker dafür finden.


An so was hab ich noch gar nicht gedacht bzw. davon zu träumen gewagt, abgesehen von meinen Möglichkeiten.
Da ich aber nicht mit Sprites arbeite, ist das Palette-Thema vielleicht gar keines. Es wird eine eigene Farbpalette für die darzustellenden Grafiken verwendet. So kann mann evtl. vor dem Bitten andere Farben einstellen, ob das dann aber bei gleichen Objekten die gewünschten Effekte gibt, weiss ich nicht, Bin aber auch kein Grafiker!

So das wars erst mal. Wenn Du Interesse hast, kann ich Dir ja mal Details schicken (Codeausschnitte, Screenshots, ...).

Danke jedenfalls für die Hilfe!

[ - Antworten - Zitieren - Direktlink - ]

07.05.2003, 23:58 Uhr

mrbbc
Posts: 101
Nutzer
Vorweg einmal: für mich ist ein "Sprite" eine Bitmap mit Kontur. Nicht jetzt so was Spezielles wie mit dem Spriteprozessor von Amiga oder C64...

"Kontur" heisst normalerweise Maske. Früher hatte man ein monochromes Bitmuster, das z.B. ein Loch dort hinein geschnitten hat, wo der Sprite dann transparent(OR-Verknüpfung) hineinkopiert wurde. Heute, mit 256 Farben und mehr, kann man meist eine transparente Farbe definieren, die beim Blitten übersprungen wird.

---

Dann noch "Spritepalette" - eine Palette ist eine Sammlung, aus der man auswählt: gemeint ist nicht die Farbpalette der Sprites, sondern die Sprites/Bitmaps selbst.

Mit der Farbpalette kann man ja Fichten nicht in Palmen umwandeln, auch Schneewehen kriegt man auf normale Flächen nicht drauf.

Mir ist eigentlich auch nur so in den Sinn gekommen, dass man als Gag Jahreszeiten einbauen könnte - mit einem ausgeklügelten Konzept kann man die irrsten Erweiterungen in an sich vollendete Programme einbauen...

Mit Farbpalettenrotation kann man unter 256 Farben auch für hübsche Animationen sorgen, u.a. auch rauschende Flüsse, Lavaströme usw. - und für jedes Feld braucht man dennoch bloss je eine Grafik, anstatt diverser Animationen...

Allerdings fällt das mit mehr als 256 Farben weg. Also überhaupt keine Lösung, wenn die Farbtiefe variabel sein soll.

---

Zitat:
Original von Reth:
Jede Grafik ist nur einmal im Speicher vorhanden, kann aber beliebig oft geblittet werden.Vorgesehen ist, dass ich eine Verwalterklasse für alle Klassen mache, die graphische Objekte mit Animation beherbergt. Diese wird dann regelmässg gerufen, um alle Objekte ggf. neu zu zeichnen [...] aber wie sonst?


Über eine "Map", also ein 2D(?)Array, aus dem die Zeichenroutine seine Informationen sequentiell rauslesen kann. Vielleicht schreibst du da einfach hinein, welche Sprites wo hin gehören bzw. inklusive "Animationsphase" (wenn du die Phasen aus einem Grundsprite generierst).

Deine "show()"-Methode sollte den Eintrag in der Map entsprechend ändern.

Zitat:
Hab mich wohl missverständlich ausgedrückt.

Ein äußerst faszinierendes Thema, das überhaupt nicht hier hin gehört: wie kann man sich mit einem Holzhacker-Kommunikationsmedium wie Sprache un-mißverständlich ausdrücken ?

Aber so entstehen immer noch die tollsten Diskussionen, wenn die Leute stundenlang aneinander vorbeireden oder resignieren und sich reflexartig bei allem beipflichten...

Zitat:
Der Zeitstempel den jedes Objekt (das eine animierte Grafik repräsentiert) erhält, entscheidet darüber, ob das Objekt aktualisert werden muss.

Ich halte das für keine gute Idee, Tim. Naja... Ich kann mir vorstellen, dass ein Objekt/Feld ein anderes gegf. bedeckt. Vorallem, wenn du z.B. räumliche Tiefe vortäuscht, wie bei den Siedlern.

Daher zeichnet man den Bildschirm immer wieder einmal komplett - in der richtigen Reihenfolge, hintere Objekte/Sprites zuerst.

--
it obvisiously seems to have been hard to write

[ - Antworten - Zitieren - Direktlink - ]

08.05.2003, 08:52 Uhr

Solar
Posts: 3680
Nutzer
Zitat:
Original von mrbbc:
Zu der "unzulässigen Verallgemeinerung": man müsste sehen, was für eine CPU/wieviele. Moderne CPUs haben mehrere parallele Befehlsinterpreter, beim sog. "Hyperthreading" sind's besonders viele. Im Grunde hat man also virtuell einen Multiprozessorcomputer.


Hyperthreading ist die Abbildung von mehreren, mehr oder minder unabhängigen CPUs auf einem CPU-Core. (Der neue Intel Xeon, für die die nicht wissen worum es geht.)

Die "parallelen Befehlsinterpreter" sind die Ausführungseinheiten bei einer superskalaren CPU. Das gibt's schon seit dem 68060 IIRC.

Das Finden der optimalen Anzahl von Threads ist eine Wissenschaft für sich. Der Server, für den ich gerade programmiere, hat 20 CPUs (Sun E10k) - merkwürdigerweise ist die optimale Anzahl von Verarbeitungsthreads aber näher bei 30 (haben wir per Profiling ermittelt) - und das, obwohl auf der Maschine noch diverser anderer Kram im Hintergrund läuft...

Zitat:
Multithreading kostet ein wenig Performance. Wenn man aber im Gegenzug die Last effektiver verteilen kann, hat man einen kleinen Leistungsschub.

Die Performanceeinbußen hängen auch noch stark vom OS ab (leichtgewichtige Prozesse, Kernel-Level Threads vs. User-Level Threads etc. etc.).

Zitat:
Zwingend notwendig ist es aber nicht.

Letztendlich, und wenn es nicht auf das letzte bißchen Performance ankommt (prof. Serveranwendung, High-End 3D o.ä.), dann sollte das Programmiermodell den Ausschlag geben - keep it as simple as possible, but no simpler.

[ - Antworten - Zitieren - Direktlink - ]

08.05.2003, 19:57 Uhr

mrbbc
Posts: 101
Nutzer
Zitat:
Original von Solar:
Das Finden der optimalen Anzahl von Threads ist eine Wissenschaft für sich. Der Server, für den ich gerade programmiere, hat 20 CPUs (Sun E10k) - merkwürdigerweise ist die optimale Anzahl von Verarbeitungsthreads aber näher bei 30 (haben wir per Profiling ermittelt) - und das, obwohl auf der Maschine noch diverser anderer Kram im Hintergrund läuft...


Ich bin zu faul zum Nachschauen was für CPUs da verbaut sind, das mag aber eben an den mehreren Ausführungseinheiten pro CPU liegen.

Das war zwar jetzt ein wenig off-topic, aber dennoch lehrreich.

Jedenfalls wird ein nicht performancehungriges Spiel wie es hier geplant ist auch sehr gut ohne Multithreading auskommen - abgesehen davon, dass das Betriebssystem es als Thread startet.

--
it obvisiously seems to have been hard to write

[ - Antworten - Zitieren - Direktlink - ]

13.05.2003, 15:34 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von mrbbc:
Zitat:
Der Zeitstempel den jedes Objekt (das eine animierte Grafik repräsentiert) erhält, entscheidet darüber, ob das Objekt aktualisert werden muss.
Ich halte das für keine gute Idee, Tim. Naja... Ich kann mir vorstellen, dass ein Objekt/Feld ein anderes gegf. bedeckt. Vorallem, wenn du z.B. räumliche Tiefe vortäuscht, wie bei den Siedlern.

Daher zeichnet man den Bildschirm immer wieder einmal komplett - in der richtigen Reihenfolge, hintere Objekte/Sprites zuerst.

Das man zur Aktualisierung eines Objektes mitunter auch noch andere und in der richtigen Reihenfolge zeichnen muß, ist vollkommen korrekt. Trotzdem muß man nicht den gesamten Bildschirm neu zeichnen, wenn sich ein kleines Objekt ändert. Clipping basierend auf rechteckigen Bounds ist schon seit Jahrzehnten erfolgreich im Einsatz, u.a. auch im Amiga.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

13.05.2003, 15:38 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Solar:
Die "parallelen Befehlsinterpreter" sind die Ausführungseinheiten bei einer superskalaren CPU. Das gibt's schon seit dem 68060 IIRC.

Das gab's prinzipiell schon vorher, so waren FPU und Integerunit schon immer parallel (wenn FPU vorhanden war). Aber der 68060 war der einzige in der Reihe mit zwei parallelen Integerunits.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

13.05.2003, 15:53 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Solar:
Statt eine Endlosschleife zu haben, die jeden Durchlauf beim Wait...()
blockiert, ist eine andere Implementierung recht verbreitet:
Eventhandler / Callbacks. Dabei wird eine Funktion (Handler) beim
System "registriert", und dann beim Auftreten des Events vom System
aufgerufen (Callback).

Inwieweit das AmigaOS dies unterstützt, weiß ich nicht. Als ich mit
"fortgeschrittener" Programmierung anfing, war Amiga schon auf dem
absteigenden Ast ;( , so daß ich kaum praktische Erfahrung mit der
AmigaOS-API habe. Aber quasi alle Systeme, die ich seither kennengelernt
habe, arbeiten mit Callbacks.


Prinzipiell arbeitet das AmigaOS nicht mit Callbacks in der Ereignisverarbeitung, es sei denn man programmiert BOOPSI-Gadget's, was man aber nur im Ausnahmefall selbst machen sollte.
Deshalb läuft es meist doch darauf hinaus, das man ein solches Callback-System selbst programmiert oder eine Erweiterung (z.B. MUI) benutzt, die so etwas zur Verfügung stellt.
Wenn man kein solches GUI-Toolkit benutzt (typisch für Spiele), sollte man versuchen, die leider notwendige Event-Handling Schleife so einfach und übersichtlich wie möglich halten. Also: Event empfangen, zuständiges Objekt ermitteln, zugehörige Callback-Funktion aufrufen, Event beantworten, schlafen legen/auf nächstes Event warten.

Zitat:
Original von mrbbc:
Jedenfalls wird ein nicht performancehungriges Spiel wie es hier geplant ist auch sehr gut ohne Multithreading auskommen - abgesehen davon, dass das Betriebssystem es als Thread startet.

Aber es schadet nichts, wenn man auch bei einfachen Spielen die entsprechende Vorgehensweise übt. Ein typischer Fall, bei dem man durchaus einiges herausholen kann, ist der Startvorgang. Wenn man das Nachladen der Grafiken/Sounds und das Öffnen von Screen/Window, Intialisieren von Datenstrukturen, etc. parallelisiert, kann man durchaus etwas beschleunigen.

mfg

--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

13.05.2003, 19:47 Uhr

mrbbc
Posts: 101
Nutzer
Zum Clipping: ist eigentlich was, das man nur beim Zeichnen von Fensterinhalten macht. Wenn was den Fensterinhalt verdeckt hat, ermittelt man diesen rechtecktigen Bereich und zeichnet darin alles neu, bzw. ermittelt man, was unverdeckt ist, und somit upgedatet werden soll.

Clipping ist zwar sehr aufwändig, aber oft schneller, als den kompletten Fensterinhalt neu zu zeichnen - so lange nicht fast das komplette Fenster neu gezeichnet werden muss. Dann dreht sich der Spiess wieder um.

Bei Vollbildanwendungen ist Clipping in der Form eher ungewöhnlich. Zum einen gibt es natürlich "Pseudoclipping": wenn die Bitmaps in einem festen Raster liegen, kann man sie auch einzeln neu zeichnen.

Zum anderen ist Clipping aber auch eine Möglichkeit, den Bildschirm auf mehrere Threads verteilt neu zu zeichnen - jeder Thread übernimmt einen rechteckigen Bildschirmausschnitt.

Grundsätzlich ist es auch nur deshalb ungewöhnlich, weil man bei den meisten Spielen praktisch immer damit rechnet, dass sich der gesamte Bildschirminhalt ändert.

---

Zum Eventsystem: auch Callbacks arbeiten über eine Endlosschleife :o)

Die MFC(Windows) tut z.B. sogar so, als wär's ein Callbacksystem, dabei bastelt sie sich die alte API(Microsofts API, nicht allgemein)-Schleife, und biegt sich mit Makros alles zurecht ;-)

Andererseits vielleicht gar nicht so dumm... man braucht nur eine vordefinierte Methode neu definieren, und beim entsprechenden Ereignis wird die dann ausgeführt.

Während Callback und Eventabfrage bei umfassenderer Ereignisbehandlung immer irgendwo endlose Listings verursachen...

--
it obvisiously seems to have been hard to write

[ - Antworten - Zitieren - Direktlink - ]

14.05.2003, 15:17 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von mrbbc:
Zum Clipping: ist eigentlich was, das man nur beim Zeichnen von Fensterinhalten macht.

Auch bei Gadgets und insb. beim Scrolling benutzt man das schon.
Vor allem wenn ohnehin ein ClipRect für meine aktuelle Zeichenoperation definiert ist, spielt es für den Clipping-Algorithmus auch keine Rolle ob dieses nur Aufgrund von Fenstergrenzen oder beliebigen Objektstrukturen erstellt wurde.
Zitat:
Clipping ist zwar sehr aufwändig, aber oft schneller, als den kompletten Fensterinhalt neu zu zeichnen - so lange nicht fast das komplette Fenster neu gezeichnet werden muss. Dann dreht sich der Spiess wieder um.
Da dreht sich eigentlich nichts um. Ein Clipping-Rechteck benötigt man ohnehin, wenn man nicht bei teilweise sichtbaren Objekten außerhalb des Bildschirmspeichers landen will. Und wie gesagt, ob das aktive Rechteck das gesamte Bild oder ein einzelnes Pixel repräsentiert, spielt für die Effizienz von geclippten Zeichenoperationen keine Rolle.
Zitat:
Grundsätzlich ist es auch nur deshalb ungewöhnlich, weil man bei den meisten Spielen praktisch immer damit rechnet, dass sich der gesamte Bildschirminhalt ändert.
Aber gerade in dem hier beschriebenen Fall ist das eben nicht so.
Zitat:
Zum Eventsystem: auch Callbacks arbeiten über eine Endlosschleife :o)
Richtiger wäre: sehr viele Event-Systeme arbeiten intern mit einer solchen Schleife, aber das interessiert den Anwendungsprogrammierer normalerweise nicht.
Es gibt aber auch Interrupt-getriggerte Event-Systeme.
Zitat:
Während Callback und Eventabfrage bei umfassenderer Ereignisbehandlung immer irgendwo endlose Listings verursachen...
Überhaupt nicht. Und wenn man eine saubere MVC-Modellierung vornimmt, ist der Code nicht nur übersichtlicher, sondern auch kompakter (und oft sogar schneller), als die eine Schleife in der Anwendung.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]


-1- [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Wie programmiert man denn am besten folgendes: [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.