Roguelike-Diary (WIP ...)

Spiele, Demos, Grafikzeug und anderes unterhaltendes.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Roguelike-Diary (WIP ...)

Beitrag von diceman »

Hallöchen,
Ich habe heute den ersten Schrit zu meinem großen PureBasic-Projekt getan ... wie einige vielleicht mitbekommen haben, hatte ich bereits in Blitzbasic begonnen, ein Roguelike-RPG-Adventure zu programmieren, bin auch recht weit gekommen, bevor ich mich verzettelt habe und der Umstieg auf Windows-10 mir den Spaß an der Sprache endgültig verhagelt hat (Bugs/Glitches/keine Aussicht auf Besserung da OpenSource und kein offizieller Support mehr). Allerdings bin ich recht stolz auf einen umfangreichen Zufalls-Dungeon-Creator, in den mindestens ein halbes Jahr Gehirnschmalz und Finetuning geflossen ist, und den ich jetzt demnächst nach Pure-Basic übersetzen werde.

Auf ein Neues!
Bin voll motiviert!

Ich habe mir vorgenommen, diesen Thread als eine Art Entwickler-Tagebuch zu führen, einerseits um mich selbst zu motiveren, andererseits auch um gelegentliches Feedback zu erhalten und Projekt-spezifische Fragen zu stellen. Ich versuche regelmäßig Updates zu posten, mal Code-Snippets, mal kleine Youtube-Demos, mal Bilder, mal Notizen zu Gameplay-Konzepten; wenn mal längere Zeit nix kommt, dann dürft ihr gerne Publisher spielen und auf die Füße treten. <) Ich hoffe das geht so in Ordnung?

Der erste Schrit ist getan, mein Prototyp-Spielplatz steht (mit weniger als 300 Zeilen Code):
Viewport, Keyboard-Input, scrollende Map, rudimentäre Kollision, Line-of-Sight mit dem Bresenham-Algorithmus. Maus-Steuerung ist geplant, wird zu einem späteren Zeitpunkt implementiert. Was ich aus meiner Erfahrung in Blitzbasic mitgenommen habe, ist, daß es eine schlechte Idee ist, sich zu früh mit grafischen Spielereien und Details aufzuhalten. Werde stattdessen möglichst rasch versuchen, das so gerne zitierte "Minimum Viable Product" auf die Beine zu stellen - das muß nicht schön aussehen, aber es ist das essentielle Fundament, auf dem Gameplay-Mechaniken, Content, etc. erst so richtig gedeihen können.

Bild
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von RSBasic »

Ich finde deine Idee gut.
Ich bin auf deine weiteren, zukünftigen Ergebnisse und Fortschritte sehr gespannt.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von diceman »

Danke für die positiven Vibes. :)

Mouse-Input is now a thing ...
War fast erschrocken, wie problemlos ich das implementiert bekommen habe! Da muß doch irgendwo noch ein Bug sein, oder überflüssiger Code?
Nee, läuft wie geschmiert! <)
War außerdem meine erste positive Erfahrung mit Static-Variablen ... sowas Tolles habe ich mir in Blitzbasic öfters gewünscht! Richtig elegante Sache; bin begeistert!
Endlich kein endloses Durchschleifen von Hilfsvariablen mehr, bzw. wieder eine Global gespart, yay!

Und so funktionierts:
Wenn man auf ein freies Feld klickt, berechnet meine A*-Suchroutine einen Pfad zum Zielfeld und speichert die entsprechenden Nodes in einer LinkedList (aStarPath()). Das erste Element wird direkt aufgerufen (identisch mit dem Spielerfeld). Solange man jetzt die Maustaste gedrückt hält, wird nach einem kurzen Timer-Delay die nächste Node in der Link aufgerufen und die Spielerposition aktualisiert. Währenddessen bleibt die Maus für weiteren Input "gesperrt", da die Map mitscrollt (also den Spieler immer in der Mitte des Viewports hält) und ansonsten nach jedem Schritt ein neuer Pfad berechnet werden würde, was ja nicht der Sinn der Sache ist. Sobald die Maustaste losgelassen wird, bleibt der Spieler stehen, die Maus wird wieder freigegeben man kann ein neues Feld anklicken und dorthin gehen.

//EDIT:
Ich sollte vielleicht noch festlegen, daß man nicht auf verdeckte Felder im Fog of War klicken kann.

Code: Alles auswählen

Procedure processInput()
	#centerCamera_LIMIT = 500
	Define leftClick = MouseButton(#PB_MouseButton_Left)
	Define rightClick = MouseButton(#PB_MouseButton_Right)
	Static holdLeft
	Static centerCamera_TIMER

	If holdLeft And Not leftClick ;sobald die Maustaste losgelassen wird, MouseInput wieder freigeben
		holdLeft = 0
	EndIf
	
	xMouse = limit((MouseX()/#tileSize)+(xViewCenter-#xMaxView),0,#xMax)
	yMouse = limit((MouseY()/#tileSize)+(yViewCenter-#yMaxView),0,#yMax)
	
	If leftClick And Not holdLeft
		holdLeft = 1 ;während die Maustaste gehalten wird, MouseInput sperren, damit Pfad nach dem ersten Schritt nicht erneut aktualisiert wird
		If worldMap(xMouse,yMouse) = 1 And bresenMap(xMouse,yMouse) > 0
			translateWorld() ;worldMap() in binaryMap() "übersetzen"
			If getPath(xPlayer,yPlayer,xMouse,yMouse,#xMax,#yMax) > 0
				FirstElement(aStarPath())
			EndIf
		EndIf
	EndIf

	If leftClick And holdLeft ;solange die Maustaste gedrückt bleibt, die nächste PathNode im gefundenen Weg aufrufen
		If NextElement(aStarPath()) <> #Null
			xPlayer + ((xPlayer-aStarPath()\x)*-1)
			yPlayer + ((yPlayer-aStarPath()\y)*-1)
			calculateLOS() ;Line-of-Sight aktualisieren	
			ProcedureReturn
		EndIf
	EndIf

	If xMouse = xPlayer And yMouse = yPlayer
		If centerCamera_TIMER = 0
			centerCamera_TIMER = ElapsedMilliseconds()
		EndIf
		If ElapsedMilliseconds() - centerCamera_TIMER > #centerCamera_LIMIT
			;wenn Mauszeiger 0.5 Sekunden auf Spielerfeld ruht, Viewport zentrieren
			centerCamera_TIMER = 0
			xViewCenter = xPlayer
			yViewCenter = yPlayer
			calculateLOS()
			MouseLocate(#xRes/2,#yRes/2)
			ProcedureReturn
		EndIf
	Else
		centerCamera_TIMER = 0
	EndIf
		
	If Not (leftClick+rightClick)	;Wenn Mauszeiger an den Rand bewegt wird, Ansicht aktualisieren
		If MouseX() = 0
			xViewCenter = xPlayer - (#xMaxView-2)
			calculateLOS()
			ProcedureReturn
		EndIf
		If MouseX() = #xRes-1
			xViewCenter = xPlayer + (#xMaxView-2)
			calculateLOS()
			ProcedureReturn
		EndIf
		If MouseY() = 0
			yViewCenter = yPlayer - (#yMaxView-2)
			calculateLOS()
			ProcedureReturn
		EndIf
		If MouseY() = #yRes-1
			yViewCenter = yPlayer + (#yMaxView-2)
			calculateLOS()
			ProcedureReturn
		EndIf
	EndIf
EndProcedure
Zuletzt geändert von diceman am 08.03.2018 20:43, insgesamt 1-mal geändert.
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Jan125
Beiträge: 31
Registriert: 23.06.2013 06:26
Computerausstattung: Nicht lachen. Atom Z3775, 2GiB RAM, Win8.1.

Re: Roguelike-Diary (WIP ...)

Beitrag von Jan125 »

Kleine Anmerkung zur Mouse-Library:
Clicks etc. funktionieren zwar ganz gut, aber bei zu schnellen Bewegungen haken MouseX und Konsorten gerne mal.
Wenn das Problem bei dir auftauchen sollte, schau dir mal WindowMouseX/Y (grad am Telefon, keine Ahnung ob korrekt) an.
Wer braucht schon Unicode? PB5.24LTS
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von diceman »

Dankeschön für den Hinweis. :-)
Gut zu wissen, auch wenn ich glaube, daß das momentan nur sekundäre Relevanz für mich hat ... ich plane kein schnelles Reaktions-Spiel, sondern ein rundenbasiertes Roguelike, und bis jetzt funktioniert das super-fluffig; konnte auch den Code mit der Abfrage, welches Feld gerade geklickt wurde, noch wesentlich optimieren: ich muß gar nicht das komplette World-Array durchlaufen - wenn ich die aktuelle Mausposition durch #tileSize teile und mit den Parametern für Kamera-Position und viewPort-Ausdehnung verrechne, habe ich direkt die entsprechenden Feld-Koordinaten.
Und, wie gesagt, Probleme mit hängenden Mauskoordinaten habe ich momentan keine; ich hoffe, das bleibt so. :)
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von diceman »

Demo-Video:
Roguelike Diaries 01: Viewport, Navigation, Line-of-Sight

Bin jetzt ganz zufrieden mit meinem Fundament, denn eine intuitive, reibungslose Steuerung ist das A und O:

• Linksklick auf den Boden bewegt den Spielercharakter zum Zielfeld, solange man die Maustaste gedrückt hält.
• Man kann die Ansicht anpassen, in dem man den Mauszeiger an den Bildschirmrand bewegt.
• Lässt man den Mauszeiger für 0.5 Sekunden auf den Spieler-Koordinaten "hängen", wird der Viewport automatisch zentriert.
Zuletzt geändert von diceman am 08.03.2018 20:44, insgesamt 3-mal geändert.
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von RSBasic »

Danke für das Video, sieht gut aus. :allright:
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von diceman »

Fullscreen/TaskSwitch/FullScreen funktioniert jetzt auch. 8)
Das war etwas kompliziert, hab's auch nur dank einem Code-Snippet gelöst, welches ich mit der Google-Suche im englischen Forum gefunden habe.
Anscheinend muß man sich das StandBy-Fenster in der Taskleiste selbst kreieren ... :?
Kann mir jemand erklären, was genau hier callFunctionFast(*standBy) leistet? :)
Ohne funktioniert's nämlich auch ...

Code: Alles auswählen

;Abfrage in der Hauptschleife:
[...]
If Not IsScreenActive()
	fullScreenResume()
EndIf
[...]

Procedure fullScreenResume(*standBy = 0)
	CloseScreen()
	screen = OpenWindow(#PB_Any,0,0,0,0,"Roguelike-Project",#PB_Window_BorderLess | #PB_Window_NoActivate)
	Repeat
		Delay(16)
		If *standBy
			callFunctionFast(*standBy)
		EndIf
	Until WindowEvent() = #PB_Event_ActivateWindow
	CloseWindow(screen)
	screen = createScreen(#xRes,#yRes,32,"Roguelike-Project")
EndProcedure
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Roguelike-Diary (WIP ...)

Beitrag von Sicro »

diceman hat geschrieben:

Code: Alles auswählen

Procedure fullScreenResume(*standBy = 0)
   ...
   Repeat
      Delay(16)
      If *standBy
         callFunctionFast(*standBy)
      EndIf
   Until WindowEvent() = #PB_Event_ActivateWindow
   ...
EndProcedure
Kann mir jemand erklären, was genau hier callFunctionFast(*standBy) leistet? :)
Ohne funktioniert's nämlich auch ...
Der If-Block wird nicht ausgeführt, wenn du kein Parameter bei der Procedure angibst, daher kannst du den gesamten If-Block weglassen.
CallFunctionFast() erwartet als Parameter eine Adresse zu einer Procedure, die ausgeführt werden soll. Du könntest also so etwas machen:

Code: Alles auswählen

Procedure StandbyCallback()
  ; Diese Procedure wird alle 16 Sekunden ausgeführt (siehe "Delay(16)" im obigem Code),
  ; solange du im Standby (nicht im FullScreen) bist
EndProcedure
...
fullScreenResume(@StandbyCallback())
...
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Antworten