Last active
August 29, 2015 14:12
-
-
Save dom96/3c5505f28260c4f20b71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import strutils | |
import lib | |
type | |
UpperScene = object of Scene | |
LowerScene = object of Scene | |
proc newUpperScene(): ref UpperScene = | |
result = new UpperScene | |
result.prompt = "U:" | |
proc newLowerScene(): ref LowerScene = | |
result = new LowerScene | |
result.prompt = "l:" | |
method enter(self: ref UpperScene) = | |
echo("UpperScene needed initialization!") | |
method leave(self: ref LowerScene) = | |
echo("LowerScene needed cleanup!") | |
method update(self: ref UpperScene, input: string): ref Scene = | |
if input == "": | |
return newLowerScene() | |
echo("UPPER: " & input.toUpper) | |
method update(self: ref LowerScene, input: string): ref Scene = | |
if input == "": | |
return newUpperScene() | |
echo("lower: " & input.toLower) | |
# initialize a scene | |
var lowerScene = newLowerScene() | |
# initialize app with scene | |
var app = newApp(lowerScene) | |
# fall into app main loop | |
app.run() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this module implements a simple "framework". | |
# In this example, the framework supports the implementation of | |
# user programs that implement a basic input-output loop | |
# However, the system is implemented as a State Machine | |
# On each loop, the user input is passed to the *current* | |
# "Scene" object. There can only be one active Scene. Scene's have | |
# the capability to set the system to a different Scene thereby | |
# changing the behavior of the program. | |
# The base Scene class implements a simple interface of 4 methods: | |
# `enter` for initialization upon entering the Scene | |
# `update` for Scene specific behavior | |
# `leave` for cleanup upon leaving the Scene | |
# While the example usecase is odd, the metaphor is really for | |
# game engines. Each Scene might implement some "screen" in a | |
# game such as the main menu, the game play, a pause screen, | |
# an options menu, the highscore listing. | |
# Each Scene is essentially a completely different "program" | |
# that the overall application switches between. A menu screen | |
# might be implemented very differently than the gameplay screen. | |
# It would probably do different things during the frame update | |
# and draw differently too. | |
# The main reasoning behind the inheritance based implementation | |
# of this system is so that user's of this library can implement | |
# their Scene's by inheriting the base and implementing just the | |
# parts of the Scene lifetime that they need to overload. | |
# If the framework instead expected the user to provide types | |
# that simply implemented a "Scene interface" to adhere to some | |
# expected typeclass, then the user utilizing the library would | |
# be required to implement every proc prescribed by the interface | |
# whether any particular Scene actually needed to overload every | |
# method in the interface or not. | |
# In the example below, there are two "Scenes". One that converts | |
# all user input to UPPERCASE and the other to lowercase. You can | |
# see that each Scene has its own state (prompt) and they both | |
# implement `update` differently. | |
# Lastly, the UpperCase Scene implements `enter` to simulate the | |
# need for initialization and vice versa for LowerCase. But | |
# neither do, or are required, to implement all Scene methods. | |
import rdstdin | |
type | |
Scene* = object of RootObj | |
app*: ref App | |
prompt*: string | |
App* = object | |
scene*: ref Scene | |
closing*: bool | |
method enter*(self: ref Scene) = | |
discard | |
method leave*(self: ref Scene) = | |
discard | |
method update*(self: ref Scene, input: string): ref Scene = | |
discard | |
method set_scene*(self: ref App, scene: ref Scene) = | |
# leave old scene | |
self.scene.leave() | |
# enter new scene | |
self.scene = scene | |
self.scene.app = self | |
self.scene.enter() | |
proc newApp*(first_scene: ref Scene): ref App = | |
result = new App | |
result.closing = false | |
result.set_scene(first_scene) | |
proc run*(self: ref App) = | |
while not self.closing: | |
let str = readLineFromStdin(self.scene.prompt) | |
var new_scene = self.scene.update(str) | |
if new_scene != nil: | |
self.set_scene(new_scene) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment