Aktuelle Zeit: 22.06.2018 19:08

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]




Ein neues Thema erstellen Auf das Thema antworten  [ 115 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3, 4, 5, 6 ... 12  Nächste
Autor Nachricht
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 10.03.2018 21:58 
Offline
Benutzeravatar

Registriert: 24.11.2004 13:12
Wohnort: Germany
Code:
Procedure locatePlayer()
   ForEach actor()
      If actor()\type = #monsterActor And actor()\subtype[0] = 0
         *player = @actor()
         ProcedureReturn
      EndIf
   Next
EndProcedure


Achtung! ProcedureReturn ohne Angabe gibt das Register RAX (x64) oder EAX (x86) zurück. Dies ist für ASM-Programmierung gedacht.

Wenn die Variable *player nicht als Global gedacht ist, müsste die Procedure so lauten...
Code:
Procedure locatePlayer()
   Protected *player
   ForEach actor()
      If actor()\type = #monsterActor And actor()\subtype[0] = 0
         *player = @actor()
         ProcedureReturn *player
      EndIf
   Next
 EndProcedure
 
 ; oder
 
 Procedure locatePlayer()
   Protected *player
   ForEach actor()
      If actor()\type = #monsterActor And actor()\subtype[0] = 0
         *player = @actor()
         Break
      EndIf
   Next
   ProcedureReturn *player
EndProcedure

_________________
Alles ist möglich, fragt sich nur wie...
Projekte EventDesigner v1.x / OOP-BaseClass-Modul / OPC-Helper DLL
PB v3.30 / v5.4x - OS Mac Mini OSX 10.xx / Window 10 Pro. (X64) /Window 7 Pro. (X64) / Window XP Pro. (X86) / Ubuntu 14.04
Downloads auf Webspace


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 10.03.2018 23:22 
Offline
Benutzeravatar

Registriert: 06.07.2017 12:24
mk-soft hat geschrieben:
Achtung! ProcedureReturn ohne Angabe gibt das Register RAX (x64) oder EAX (x86) zurück. Dies ist für ASM-Programmierung gedacht.


Whoopsie! :o
Das wußte ich nicht! Habe zwar keine Ahnung was das bedeutet, aber es ist definitiv kein Feature, welches ich für mein Roguelike benötige; also bei vorzeitigem ProcedureReturn immer eine Null zurückgeben, richtig? Daran kann ich mich gewöhnen ... scheint sich ja auszuzahlen, das ich hin und wieder Code-Snippets poste - ihr seid super! :allright:
Der locatePlayer()-Murks ist übrigens wieder draußen, der war tatsächlich unnötig.
Und den *player-Pointer halte ich gerne global, weil ich den eigentlich ständig brauche.

Habe das Handling meiner collisionMap() und bresenMap() noch optimiert - die binaryMap() gibt es nicht mehr! Anstatt vor jeder Pfadsuche die collisionMap() zu updaten, ist diese jetzt permanent gültig! Es reicht, einmal nach Erstellung des Dungeons und Actor-Creation ein Update zu fahren, und dann brauche ich nur noch spezifisch für jeden sich bewegenden Actor einmal auf die entsprechenden Felder des collision()-Array zugreifen und diese zu aktualisieren. Ebenso werden jetzt in der actorFactory() und in der killActor()-Prozedur die entsprechenden Felder im Array sofort aktualisiert.
Ebenso bei Line-of-Sight-Berechnungen: ich habe zwei Arrays, eine bresenRef(), welche permanent mit aktualisierten Daten über LoS-blockierende actor()-Elemente gefüttert wird, aber nicht mehr komplett geupdated werden muß, und eine temporäre bresenMap(), welche nach jedem Schritt neudimensioniert wird und dann in der LoS-Routine anhand der bresenRef()-Daten die aktuelle Line-of-Sight-Matrix liefert.

Morgen gibt's ein Update mit Monstern!

_________________
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 11.03.2018 00:28 
Offline
Benutzeravatar

Registriert: 11.08.2005 19:08
diceman hat geschrieben:
mk-soft hat geschrieben:
Achtung! ProcedureReturn ohne Angabe gibt das Register RAX (x64) oder EAX (x86) zurück. Dies ist für ASM-Programmierung gedacht.
...
also bei vorzeitigem ProcedureReturn immer eine Null zurückgeben, richtig?
Wenn du den Rückgabewert von der Prozedure "locatePlayer" nirgends verwendest, ist es egal, wenn du bei "ProcedureReturn" keinen Wert angibst.
Vereinfacht dargestellt möchte dich mk-soft auf das hinweisen:
Code:
Procedure Beispiel()
  ;a$ = "test" ; Entferne das Semikolon am Anfang und die Procedure liefert ein anderes Ergebnis
  ;b$ = "bla"  ; Wenn du hier das Semikolon ebenfalls entfernst, ändert sich das Ergebnis wieder
  ProcedureReturn
EndProcedure

Debug Beispiel()
Wie du siehst, liefert die Procedure mit ProcedureReturn ohne Wert keinen Null-Wert.

_________________
Bild

PureBasic-CodeArchiv-Rebirth: Git-Repository / Download -- Jede Hilfe ist willkommen!

Manjaro Xfce x64 (Hauptsystem) :: WindowsXP/Xubuntu x86 (VirtualBox) :: PureBasic (Linux: x86/x64, Windows: x86) :: jeweils neueste Version


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 11.03.2018 16:20 
Offline
Benutzeravatar

Registriert: 06.07.2017 12:24
VIDEO:
Roguelike-Diary 03: Monsters, World-Interaction, Alpha-Map-Test

:)
Rapid Prototyping ... Ich habe mir zur Regel gemacht, daß ich fürs erste keine externen Grafiken verwende, und mich nur auf die Purebasic eigenen 2D-Zeichenroutinen verlasse. Damit will ich verhindern, daß ich mich in irgendeiner Art und Weise verklüngele und Zeit verschwende, welcher besser investiert wäre mit der Fertigstellung eines Minimum Viable Products.
Been there, done that.
So geschehen mit meinem Blitzbasic-Projekt, wo ich gut ein halbes Jahr in die Routinen eines prozeduralen Dungeon-Generators gesteckt habe ... gut, von der Arbeit werde ich jetzt im Nachhinein profitieren, wenn ich denn mal soweit bin, daß ich "gute" Level-Generierung haben möchte; der Code ist nicht kaputt oder verloren, den kann ich mit etwas Aufwand problemlos nach PureBasic übersetzen.
Aber das ist momentan einfach nicht notwendig. Ich habe eine quick-and-dirty Generierungs-Routine geschrieben, die weder auf lösbare Level noch interessante Architektur achtet, aber es ist absolut ausreichend. So kann ich mich ganz auf die Entwicklung der Core-Mechaniken konzentrieren; und dann erst kommt Theme, Gameplay & Content.

Eine ganz interessante Kopfnuss waren die Türen ... nicht vom Programmierungsaufwand her, man hätte das in 5 Minuten hardcoden können, aber ich wollte eine maximal elegante, modulare Lösung. Habe mich letztendlich für folgendes entschieden: Offene Türen und geschlossene Türen sind zwei verschiedene actor()-Elemente; geschlossene Türen haben Kollision und blocken Sichtlinie, Offene Türen haben weder noch. Wenn ich jetzt mit der rechten Maustaste (Interaktion) auf eine Tür klicke, wird ein Pointer auf den actor() gelegt, der Status der Tür wird ausgelesen (geschlossen/offen?), anschließend wird an derselben Stelle ein neues actor()-Element vom gegenteiligen Typ in der actorFactory() produziert (welche gleichzeitig alle Parameter bezüglich Kollisions-Map und Sichtlinien-Parameter regelt). Pointer zurück auf ursprüngliches actor()-Element, und freigeben zum löschen in der killActor()-Prozedur (auch hier muß ich mich nicht mehr ums updaten des World-Status kümmern, das passiert alles automatisch). Und nach jeder erfolgreichen Aktion (Schritt/Interaktion) wird die Sichtlinie aktualisiert.

Die Interaktion mit Monstern ging überraschend problemlos über die Bühne; ich brauchte lediglich einen neuen Pointer für den Target-actor(), und ein paar Prozeduren (performMeleeCombat(), moveToAnimation(), damageActor() ), welche den Ablauf maximal abstrahiert regeln, so daß theoretisch auch Monster gegen Monster kämpfen können, so sie denn mal eine KI haben und den Respekt vor der collisionMap() verlieren.

Außerdem neu (nicht im Video zu sehen) ist Auflösungs-unabhängige Darstellung: die Größe des Viewports wird jetzt automatisch, abhängig von der eingestellten Fenstergröße, berechnet. Die maximale Sichtweite bleibt natürlich konstant, die wurde anhand der niedrigstmöglichen Auflösung (800x600) festgelegt, und bleibt auch Benchmark fürs Balancing. Höhere Auflösungen bieten lediglich den Vorteil, daß man weniger scrollen muß um alles zu sehen.

Next in line: rudimentäre Monster-KI und Monster-Interaktion mit der Welt.

_________________
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.


Zuletzt geändert von diceman am 11.03.2018 16:28, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 11.03.2018 16:22 
Offline
Benutzeravatar

Registriert: 01.04.2007 20:18
Klingt ja schon beinahe wie : RogueLike GameCreator ;)

_________________
PureBasic 5.46 LTS / 5.62 (Windows x86/x64) | Windows10 Pro x64 | Z370 Extreme4 | i7 8770k | 32GB RAM | iChill GeForce GTX 980 X4 Ultra | HAF XF Evo​​


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 11.03.2018 17:13 
Offline
Benutzeravatar

Registriert: 25.09.2016 01:42
Sieht gut aus :)

Gibt es Pläne für
- eine Minimap?
- eine Zentralisierung des Spielers?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 11.03.2018 17:25 
Offline
Benutzeravatar

Registriert: 06.07.2017 12:24
Den Spieler zentriert man entweder durch Drücken der SPACE-Taste oder wenn der Mauszeiger länger als 0.5 Sekunden auf dem Spieler-actor() ruht. Das hat den schönen, intuitiven Nebeneffekt, daß wenn du also ein Feld anvisiert hast und da ankommst, die Map automatisch zentrierst, wenn du einen winzigen Augenschlag Geduld hast. Das ist aber ein Quality-of-Life-Feature, bei dem es sich anbietet, es "optional" zu gestalten, also daß man es dem jeweiligen Anbieter überlässt, den gewünschten Intervall für automatische Zentrierung selbst im Optionsmenü festzulegen. :-)
Permanente Zentrierung möchte ich aus dem einfachen Grund nicht, weil ich mit einer von der Spielerposition losgelösten "Kamera" eine größere Sichtweite simulieren kann. Wenn du den Mauszeiger an den Spielfeldrand bewegst, "scrollt" (bzw. springt) die Map in die entsprechende Richtung. Wenn du das Spiel in einer höheren Auflösung startest, hast du zwar keine größere Sichtweite, aber einen weiteren Viewport, mußt also weniger scrollen. :-) Im oben geposteten Video habe ich die Sichtweite absichtlich etwas reduziert, damit man den getesteten Alpha-Map-Effekt ausreichend sehen kann; war mein erstes Mal, daß ich mich mit sowas beschäftigt habe, in Blitzbasic hatte ich diese Möglichkeit nicht, zumindest nicht in der reinen 2D-Programmierung (selber 3D-Applikationen zu schreiben hat mich nie interessiert).
Minimap im klassischen Sinne wohl nicht, aber ich plane ein Map-Item, welches man auf jeder Ebene finden kann, welches einerseits die umliegende, von der Sichtlinie ausgeschossene, bereits entdeckte Architektur als Schattenumriss zeigt, und auf dem man den Dungeon-Umriss mit evtl. eingezeichneten Points of Interest angucken kann. Das ist atmosphärischer, als einfach nur auf den oberen rechten Bildschirm zu starren und blinkenden Punkten hinterher zu laufen. :wink:
Ich würde sehr gerne ein Spiel im Lovecraft-Universum basteln, aber davon bin ich noch weit entfernt; ich habe zwar jede Menge Ideen, will mich aber ungern auf Details festlegen, bevor ich nicht die "Core-Engine" mit den wesentlichen Roguelike-Mechaniken fertiggestellt habe. Das war mein großer Fehler, den ich bei meinem Blitzbasic-Projekt gemacht habe - da habe ich mich total verzettelt und alle möglichen Features gebastelt, die sich cool anfühlten, und als ich dann große Milestones implementieren wollte, wie Nahkampf, etc. hatte ich all diese schlecht optimierten Nebenroutinen, "Features" und Content-Generatoren, welche mir häufig den Blick aufs große Ganze versperrt haben, und das Implementieren von neuen Core-Features unnötig verkompliziert haben.

_________________
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 14.03.2018 15:15 
Offline
Benutzeravatar

Registriert: 06.07.2017 12:24
VIDEO:
Roguelike-Diary 04: Flying Monsters, Ranged Combat, Effect-Actors

Uuuuuund, Update! 8)
Die Fernkampf-Mechaniken sind implementiert! War ganz schön kniffelig, hat aber Spaß gemacht, das auszuknobeln ...
Wie funktionierts?

Zunächst checke ich, ob eine freie Schußbahn existiert, das mache ich mit dem Bresenham-Algorithmus, allerdings füttere ich ihn nicht mit Line-of-Sight-Daten, sondern mit den Informationen aus der collisionMap(). Außerdem habe ich, für schnellere Abfragen, ein interactionMap()-Array initialisiert, in dem gespeichert bleibt, mit welchem sichtbaren Felder man interagieren kann (Türen, Monster, etc.). Dieses wird nach jedem Schritt, genau wie die bresenMap() und die collisionMap(), aktualisiert.
Wird jetzt auf ein weiter entferntes Monster ein Rechtsklick ausgeführt UND die interactionMap(x,y) gibt ihr Okay (Ziel wird nicht durch andere Actors() oder Mauern geblockt), ist die Voraussetzung für erfolgreichen Fernkampf bereits erfüllt und man könnte direkt zur Schadensverteilung übergehen; ohne Schußanimation wär's aber nur halb so schön:
Dabei hilft mir die Geradengleichung: ich stelle die Gleichung auf mit den absoluten Koordinaten (nicht den Tile-Koordinaten!) von der Mitte des Startfeldes zur Mitte des Zielfeldes. Anschließend überprüfe ich die x/y-Achsen des umschließenden Rechteckes und entscheide so, ob ich nach x oder y auflöse (so umgehe ich die gefürchtete Division durch Null, außerdem erhalte ich auch bei sehr steilen Geraden eine durchgängige Linie).
In die fertige Gleichung (Zweipunkteform) setze ich x, bzw. y Koordinaten mit einem Vorschub von 10 Pixeln ein, und speichere die neuen Punkte als Elemente in einer Linked-List (kleinere Werte ergeben eine langsamere Schuß-Animation). Dann überprüfe, ob sich das Startfeld an erster Stelle der LinkedList befindet; falls nicht, initialisiere ich einen Vorschub-Modifikator mit -1. Und dann gehe ich an den Anfang (bzw. Ende) der Liste und arbeite diese nach oben (bzw. unten) ab. :)

Außerdem gibts Fliegende Monster - das Prinzip ist hier sehr einfach: jeder Actor() hat einen bestimmten Kollisionswert: der Spieler, normale Monster, Bäume, Schatztruhen, etc. haben 1, fliegende Monster 2, und geschlossene Türen und Mauern 4. Bei jedem Schritt wird die collisionMap() aktualisiert, und zwar wird der jeweilige Kollisionsfaktor vom alten Feld subtrahiert, und aufs neue Feld aufaddiert. Und da jeder Actor() sich nur auf Felder bewegen darf, welche einen geringeren Kollisionwert haben als sie selbst, können so manche Monster über andere Monster und Objekte hinwegfliegen, aber nicht durch geschlossene Türen. Und weil 1+2 = 3, können maximal 2 Actors() auf ein und demselben Feld verweilen.
Noch eine Anmerkung zur weiter oben beschriebenen "drawPriority": jeder neu erstelle Actor() wird in die LinkedList nach "drawPriority" sortiert eingetragen - fliegende Monster haben eine höhere drawPriority als der Spieler oder Bäume. Die Zeichenroutine klappert die Actorliste von unten nach oben ab, während bei Interaktionen von oben nach unten gesucht wird. Deswegen wird man, wenn man z.B. auf ein Monster in einer offenen Tür klickt, immer zuerst das Monster angreifen! Die Tür kann erst geschlossen werden, wenn sich kein anderer Actor() mehr auf demselben Feld befindet.

Last but not least, Effect-Actors:
Das sind die "Blutspritzer" bei Treffern. Könnten aber genauso gut Teleporter-Animation sein, ein Schutzschild oder Vergiftungseffekt. Auch diese "Effekte" sind Actors, die genauso wie Monster und Objekte über die actorFactory() erstellt werden. Ein Effect-Actor hat keine Kollision und blockiert keine Sichtlinie. Er hat x und y Koordinaten wie jeder andere Actor (und zusätlich frames, timer, frameTimer und killLimits). Und, jetzt wird's spannend: es ist möglich, Effect-Actors an andere Actors() zu koppeln! Das ergibt Sinn bei eben jenen Blutzspritzern, die getimed sind und nach Ablauf ihrer Lebenszeit wieder gelöscht werden - deswegen müssen sie in der Lage sein, ihren Parent-Actors zu folgen, wenn sich diese bewegen bevor der animKillTimer auf Null gezählt hat - auch das wird automatisch in der actorFactory() erledigt:
Es gibt einen globalen actorCounter, der am Anfang immer auf Null steht und den Index des allerersten erstellten Actors festlegt. Wenn jetzt die actorFactory() aufgerufen wird, hat man die Option, einen index-Parameter mitzugeben - für eigenständige Actors ist das immer -1, damit wird der actorFactory() mitgeteilt, daß sie den aktuellen Index vergeben, und anschließend um 1 nach oben zählen soll. Für gekoppelte Effect-Actors() wird stattdessen der Index des Parent-Actors mitgegeben! Und das ist schon das ganze Geheimnis:
In der Routine, in der Monsterbewegungen reguliert werden, gibt es zwei lokale Arrays (newX() und newY()), die bei Bewegug eines Actors mit den jeweiligen neuen Koordinaten aktualisiert werden. So kann ich am Ende, nachdem sich alle Actors einmal bewegt haben, einmal die Actor()-Liste, gefiltert nach actor()\type = #animationActor abklappern und schauen, wo ein newX() Wert mit der jeweiligen Index-Nummer korreliert, und so die x/y-Koordinaten des Effect-Actors anpassen (der Blutspritzer zieht quasi hinterher).

So, das war's erstmal. Uff. :coderselixir:

_________________
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 14.03.2018 15:29 
Offline
Benutzeravatar

Registriert: 25.09.2016 01:42
Gefällt mir :)
weiter so :allright:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Roguelike-Diary (WIP ...)
BeitragVerfasst: 14.03.2018 15:35 
Offline
Moderator
Benutzeravatar

Registriert: 05.10.2006 18:55
Wohnort: Rupture Farms
+1 :allright:

_________________
BildBildBildBild
Bild | EnableExplicit ist kostenlos und vermeidet Fehler | Gib Goto keine Chance | Schneller als die Telekom erlaubt | Avira? Nein Danke
WinAPI forever | Bei Problemen bitte Beispielcode posten | Mit Adblock werbefrei, schneller und sicherer surfen | brain.exe ist der beste Schutz | Userlibrary ohne Source = NoGo


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 115 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3, 4, 5, 6 ... 12  Nächste

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.

Suche nach:
Gehe zu:  

 


Powered by phpBB © 2008 phpBB Group | Deutsche Übersetzung durch phpBB.de
subSilver+ theme by Canver Software, sponsor Sanal Modifiye