Struktur/Aufbau eines Spiels

Übersicht Sonstiges Gamedesign

Neue Antwort erstellen

 

Tritium

Betreff: Struktur/Aufbau eines Spiels

BeitragFr, Apr 25, 2014 11:50
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin,

vorab: Ist eigentlich keine Design-Frage, wusste aber nicht, wo ich sonst fragen soll. Falls nötig also bitte verschieben.

Nun zur Frage: Ich mache mir momentan Gedanken darüber, ob es "allgemeingültige" Strukturen für den funktionellen Teil eines Spiels (Code) gibt, die sich in allen Genres anwenden lassen. Also quasi ein Code-Grundgerüst, das erstmal vollkommen unabhängig vom eigentlichen Spielinhalt ist, und auf dem man aufbauend (durch das Gerüst dann strukturierter und effektiver/effizienter) dann das eigentliche Spiel implementiert.

Wie macht Ihr das? Kennt Ihr Links, die mit der Thematik zu tun haben? Bin um jede Anregung dankbar Smile

(Es geht hier nicht um ein konkretes Projekt, es ist eine allgemeine und eher theoretische Frage)

BladeRunner

Moderator

BeitragFr, Apr 25, 2014 11:57
Antworten mit Zitat
Benutzer-Profile anzeigen
100% allgemeingültig lässt sich das nicht beantworten - ein Textadventure hat ja zB ein komplett anderes Interface als ein Egoshooter. Auch die Logik im Hintergrund ist komplett anders.
Ein 2d JnR wird auch komplett andere Mechaniken brauchen als zB ein Schach.
Dennoch gibt es weitreichende Gemeinsamkeiten: Jedes Spiel was auch nur im Ansatz grafikbasierte Ausgabe besitzt wird eine Zeichenlogik brauchen, die man dann überladen kann. Auch ein UI muss bei jedem Game vorhanden sein. Allerdings beschränkt sich dann die Anzahl wiederverwendbarer Zeilen enorm.

Pseudo-Code: [AUSKLAPPEN]

Init()
Mainloop(
    UserInput()
    Evaluate()
    Draw()
)
CleanUp()


Sollte wohl das Minium darstellen.
Ich verwende gern Gamestates um die Schaltlogik in der Evaluation zu beeinflussen, sowas lässt sich auch als schön als eigene Singleton implementieren.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Jolinah

BeitragFr, Apr 25, 2014 12:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Was für jede Spiellogik sehr nützlich sein kann sind - wie bereits erwähnt - Gamestates. Etwas weiter geführt könnte man z.B. eine Statemachine oder einen Behavior Tree umsetzen, mit dem sich dann die Logik von einzelnen Objekten oder vom ganzen Spiel abbilden lässt.

Im wesentlichen gibt es immer einen Zustand in dem sich das Spiel oder ein Objekt gerade befindet. In diesem Zustand werden bestimmte Aktionen ausgeführt. Entweder werden diese Aktionen immer wieder ausgeführt (so lange der Zustand aktiv bleibt) oder die Aktionen werden nur einmal ausgeführt und danach wird ein anderer Zustand aktiviert. Eine Aktion könnte auch direkt veranlassen, dass ein anderer Zustand aktiviert wird usw...

Wenn man das objektorientiert umsetzt, könnte man die Aktionen jeweils als Types/Klassen definieren. Dadurch können Aktionen in mehreren Zuständen wiederverwendet werden. Wenn man die Aktionen abstrakt hält, könnte man diese auslagern und sogar in mehreren Spielen verwenden. Die Aktionen haben Eigenschaften, mit denen sich die Aktion beeinflussen lässt und evtl. auch Eigenschaften und Methoden die von aussen wieder ausgelesen werden können. Sie können Events auslösen auf die der Zustand reagieren kann um zum nächsten Zustand zu wechseln.

Das soweit nur als Idee. Es gibt sicher noch viele andere Ansätze. Aber allgemein könnte man sagen, es muss wahrscheinlich etwas sein, das selbst keine Logik vorgibt, aber es zulässt jegliche Logik damit strukturiert zu modellieren.
 

PhillipK

BeitragFr, Apr 25, 2014 12:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe bereits vor guten 2-3 jahren "GameStates" für mich entdeckt.

Diese enthalten ein grundlegendes gerüst, OOP basiert, wovon ich diverse objekte spiel/programmlogiken extenden kann.

ACHTUNG: Mir fällt keine NICHT OOP basierte möglichkeit für das folgende ein. Hör einfach auf zu lesen, wenn du kein oop hast D: Du sparst einfach deine nerven.

Ein Gamestate bildet in sofern also ein Interface, allerdings ist das für meine abstraktion nichtmehr möglich.

Grundlegend sieht es so aus:

- Class GameState. Enthält diverse globale funktionen wie "MakeActive" "CloseActive" "Render" "Update".
MakeActive verwaltet einen stack mit aktiven Gameobjekten. Es gibt immer ein Aktives GameState, welches render und update aufrufe erhält. CloseActive schließt eben dieses aktive und holt das letzte GameState vom stack. Keins mehr vorhanden? Programm ende.

Render leitet eine reihe von aufrufen an diverse methoden an das aktive GameState-objekt weiter.
Ein beispiel könnte sein:
Draw()
DrawOverlay()

Dabei wird vor Draw() die Matrix gesichert, und nach Draw() wieder zurückgesetzt. Ebenso vor DrawOverlay() und danach. So kann man zb im Draw() die eigentliche Zeichensachen regeln, in DrawOverlay() so dinge wie eine HUD oder andere Gui Elemente.

Update() leitet lediglich ans Aktive GameState den update-methoden aufruf weiter.


Mein " Hauptprogramm" ist dahingehend extrem klein:

1) Diverse globale ressourcen laden (fonts zb)
2) Ein GameState starten (beispiel: GameState.MakeActive( new MainMenu())
3) Loop: GameState.Render(), GameSTate.Update()

Alles weitere wird in den GameState objekten durch überladung der Draw(), DrawOverlay() und Update() methoden geregelt.

Hier mal mein Monkey-Gamestate. Sollte einigermaßen leserlich sein Smile

BlitzMax: [AUSKLAPPEN]
#GAMESTATE_DRAW_GUI_KEEPER=1

Strict

Import mojo


#If GAMESTATE_DRAW_GUI_KEEPER=1
Import lss.ax.swapper.guiswapper
#End


Class GameState

'summary: The current GameState that is active. Note that you shouldn't change this! Use the Functions 'MakeActive' and 'CloseActive' instead!
Global active:GameState

'summary: The stack of GameStates that was active.
Global stack:List<GameState> = New List<GameState>

#If GAMESTATE_DRAW_GUI_KEEPER=1
Global doGuiHover:Bool = True
#End

#Rem
summary: MakeActive activates a New Gamestate And place the Current active gamestate on the stack.

The New created gamestate will get the 'OnActivation' method fired.

[i]parameters:[/i]
toActivate:GameState - your gamestate extend that you want To activate.
whipeOld:Bool - True, If you want To close the old one (you dont need a levelmenu on the stack, Right? Wink )
#End
Function MakeActive:Int(toActivate:GameState, whipeOld:Bool = False)
If (active <> Null) Then
If (stack.Contains(active)) Then
stack.Remove(active)
EndIf

If whipeOld = False Then stack.AddLast(active)

If whipeOld = False Then active.OnPause()


EndIf

Local tmp:GameState = active

active = toActivate

active.OnActivation(tmp)

If whipeOld Then tmp.OnClose()


Return True;

End

#Rem
summary: Closes that Current active gamestate.

The gamestack that was closed will get the 'OnClose' method fired.
It also pop's the last gamestate of the stack and fire the 'OnResume' method for it.

Returns True, If it was possible To close the Current active gamestate, False otherwise (no more gamestates Left!)
#End
Function CloseActive:Int()
Local ret:Int = 0

If (active <> Null) Then
active.OnClose()
active = Null
ret = True
EndIf

If (stack.Count() > 0)
active = stack.RemoveLast()

active.OnResume()

EndIf

Return ret
End

#Rem
summary: Render() should get called in the App's onRender method. It overtake the rendering!

Returns False, If it was Not possible To call an active gamestate.
#End
Function Render:Int(doCls:Int = True)
If (active <> Null)

If (doCls > 0) Then Cls

PushMatrix()
active.OnRender()
PopMatrix()

#If GAMESTATE_DRAW_GUI_KEEPER=1
PushMatrix()
' debugAlpha = True
' Print("Rendere GuiKeeper")
GuiKeeper.Draw(doGuiHover)
' Print("---------------")
' debugAlpha = False
PopMatrix()
#End

PushMatrix()
active.OnGuiRender()
PopMatrix()
Else
Return 0;

EndIf
Return 1;
End
#Rem
summary: Minib3dRender() should get called in the App's onRender method. It overtake the rendering! Note: Its a slightly different version of render, designed to work with Minib3d propebly (Minib3d hates PopMatrix() !)

Returns False, If it was Not possible To call an active gamestate.
#End
Function Minib3dRender:Int()
If (active <> Null)


active.OnRender()

#If GAMESTATE_DRAW_GUI_KEEPER=1

GuiKeeper.Draw(doGuiHover)

#End

active.OnGuiRender()

Else
Return 0;

EndIf
Return 1;
End

#Rem
summary: Update() should get called in the App's onUpdate method.

Returns False, If it was Not possible To call an active gamestate.
#End
Function Update:Int()
If (active <> Null)

active.OnUpdate()
Else
Return 0;

EndIf
Return 1;
End

#Rem
summary: Provides a simple shortcut To call "active.OnFoucsLost" If app.OnSuspend() is called.
So, simply Call this in your entry app And process some logics in the active gamestates!
#End
Function FocusLost:Int()
If active Then active.OnFocusLost()
Return 1
End
#Rem
summary: Provides a simple shortcut To call "active.OnFoucsGain" If app.OnResume() is called.
So, simply Call this in your entry app And process some logics in the active gamestates!
#End
Function FocusGain:Int()
If active Then active.OnFocusGain()
Return 1
End
#Rem
summary: Provides a simple shortcut To call "OnBack" For every gamestate, If app.OnBack() is callde.
So, simply Call this in your entry app And process some logics in the gamestates!
#End
Function Back:Int()
For Local g:GameState = EachIn GameState.stack
g.OnBack(active)
Next
Return 1
End


Function Loading:Int()
If active Then active.OnLoading()

Return 1
End
'summary: The default new() method calls OnCreate.
Method New()
'Print "BASE NEW CALLED!"
Self.OnCreate();
End

'summary: OnCreate is called if you make an instance of a gamestate (-extend). Use this to load some Ressources or fill the field.
Method OnCreate:Int()
Return True
End

'summary: OnLoading is called when the App is "OnLoading"
Method OnLoading:Int()

Return True
End

'summary: OnActivation is called if you use the GameState.MakeActive() method.
Method OnActivation:Int(oldGamestate:GameState)
Return True
End

'summary: OnClose is called if you use the GameState.CloseActive() method. Use this to unload ressources.
Method OnClose:Int()
Return True
End

'summary: OnRender is called before the OnGuiRender method. General drawings should be done here (player, map...)
Method OnRender:Int()
Return True
End

'summary: OnGuirender is called after the OnRender method. Draw stuff like the gui here, it will overlay the normal rendered stuff.
Method OnGuiRender:Int()
Return True
End

'summary: OnUpdate is called out of the GameState.Update() method. Its called before the Render methods. Place general gamelogic in here.
Method OnUpdate:Int()
Return True
End

'summary: It will get called on a focus change.
Method OnFocusGain:Int()
Return True
End

'summary: It will get called on a focus change.
Method OnFocusLost:Int()
Return True
End

'summary: OnPause is called, if a current active gamestate is pushed on the stack. It will "pause" its working, until it its popped out again.
Method OnPause:Int()
Return True
End

'summary: OnResume is called, if a gamestate is popped out of the stack. It will be the new active gamestate.
Method OnResume:Int()
Return True
End

#Rem
summary: OnBack is called For EVERY gamestate (Not only the active one!) when the App.OnBack() Method is fired.
The "active" parameter lets you check with "if active = self", If its called For the active gamestate.
#End
Method OnBack:Int(active:GameState)
Return True
End


End


(GuiKeeper ist ein Verwalter für GuiObjekte, ebenfalls aus einem privaten modul)

Dieses System findet auch verwendung in meinem ersten spiel.

Hier sind alle möglichen "Menus" sowie die spielsache eigene GameStates.

Hauptmenu -> klick auf neues spiel -> Levelselection gamestate starten.
Von dort kann man zu "ingame" gelangen (Levelselection kommt NICHT auf den stack.)
Ingame kann man gewinnnen ( WinningScreen Gamestate) oder verlieren ( LooseScreen GameState). Ingame kommt NICHT auf den stack.
Beendet man den win / loss screen, wird MainMenu wieder vom stack geholt. Man hat eine voll funktionsfähige und logische verkettung von diversen Fenstern / Ingame sachen.

Neue Antwort erstellen


Übersicht Sonstiges Gamedesign

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group