Override headache

BlitzMax Forums/BlitzMax Programming/Override headache

Imphenzia(Posted 2010) [#1]
I'm using the game state code found in the code archive and I've modified to use methods instead of functions as I want to encapsulate it.

I also need to pass a value from the original instance but here is where I have my problems.

Local state:GameState = New GameState
state.value = New MyType
state.value.name = "A name"

state.switch( New MyState )

Type MyType
	Field name:String
End Type

' make a new type that extends this one. Overload the methods.
Type MyState Extends GenericState

	' Overload this one and put startup code here (loading images, sounds, etc)
	Method startup()
		' -------------------------------------------------------------
		DebugLog Self.value.name
		' -------------------------------------------------------------
	EndMethod
	
	
	' No drawing here! Only user input and other behind-the-scene stuff
	Method update()
	EndMethod
		
	
	' Draw things in this one. But no user input or logic code!
	Method draw()
	EndMethod
		
	
	' Save highscore/nullify variables/scream like a banshee
	Method shutdown()
	EndMethod


	' Called when the engine switches to a new state.
	Method on_hold()
	EndMethod
	
	
	' Called when the engine is done with the other state and switches back t this one
	Method resume()
	EndMethod

EndType




' make a new type that extends this one. Overload the methods.
Type GenericState
	' -------------------------------------------------------------
	Field value:MyType
	' -------------------------------------------------------------

	' Overload this one and put startup code here (loading images, sounds, etc)
	Method startup()
	EndMethod
	
	
	' No drawing here! Only user input and other behind-the-scene stuff
	Method update()
	EndMethod
		
	
	' Draw things in this one. But no user input or logic code!
	Method draw()
	EndMethod
		
	
	' Save highscore/nullify variables/scream like a banshee
	Method shutdown()
	EndMethod


	' Called when the engine switches to a new state.
	Method on_hold()
	EndMethod
	
	
	' Called when the engine is done with the other state and switches back t this one
	Method resume()
	EndMethod

EndType



Type GameState
	Field state_list:TList
	Field current_state:GenericState
	' -------------------------------------------------------------
	Field value:MyType
	' -------------------------------------------------------------

	Method Switch( new_state:GenericState )
		If Not Self.state_list Then Self.state_list = CreateList()
		Self.state_list.addlast( new_state )
		If current_state Then current_state.on_hold()
		new_state.startup()
		' -------------------------------------------------------------
		new_state.value = Self.value
		' -------------------------------------------------------------	
		Self.current_state = new_state
	EndMethod
	
	' Called by the running state when it doesn't want to play anymore
	Method ExitState()
		If Not state_list Then RuntimeError("ExitState should only be called by running states!")
		Self.current_state.shutdown()
		Self.state_list.remove( Self.current_state )
		If Self.state_list.Count() > 0 Then
			Self.current_state = GenericState( Self.state_list.last() )
			Self.current_state.resume()		
		EndIf
	
	EndMethod
	
	Method Run()
		If Not Self.state_list Then RuntimeError("Switch to a new game state before calling GameState.Run()")
		While Self.state_list.Count() > 0
			Self.current_state.update()
			Self.current_state.draw()
		Wend
	EndMethod

EndType


see where i've marked the code with ------------------------ (multiple places). This is where I try to pass a object so I can reference it from my newly created gamestate.

Try to run the code and you'll see how it fails and it's beyond me how to solve it....


therevills(Posted 2010) [#2]
Just quickly looked over the code.

Two things pop out for me:

1. Superstrict missing
2. Type GenericState looks like it should be Abstract

Ill have a look at the code more in-depth later...


therevills(Posted 2010) [#3]
Try this code... it doesnt crash at least (you needed to create a new MyType):




Imphenzia(Posted 2010) [#4]
Thanks for looking at this, much appreciated. Yes, I definitely use SuperStrict but I missed it in the example.

Your code works now as you said but it defeats what I'm trying to achieve. The MyType object is already created with the "New MyType" command before the switch is made. See MyType as the game object that should own everything else. It's important that I can pass in the already existing object so I can reference values in the MyType object such as game settings and lists etc.

Or maybe this is a bad design idea? I want to avoid any globals so I can truly encapsulate my game - it will help when creating the network code so I can create two instances in one compile.

Any additional thoughts are most welcome =)


matibee(Posted 2010) [#5]
Try using create and init methods. The base type has an init method that ensures the arguments you pass it are worked on, and the derived type has a create function to wrap all the creation code.



I renamed your GameState to a GameStateManager and if you don't need more than one manager there's nothing wrong with ..



Then you don't have to remember to create one each time. You can even provide a nice simple API to keep the typing down..
Function SwitchGameState( new_state:GenericState )
	GameStateManager.Switch( new_state )
End Function 

And so on.

Finally, I think ExitState should take a GenericState parameter to ensure it is only ever trying to remove itself.

HTH


Imphenzia(Posted 2010) [#6]
Finally got around to test it, my wife just delivered a son earlier than expected :)

Thanks matibee - the revised code works just they way I need it to!


matibee(Posted 2010) [#7]
Finally got around to test it, my wife just delivered a son earlier than expected :)


A big congratulations! Hope they're all doing fine. Happy times :)