Created
June 1, 2017 07:40
-
-
Save rezich/d8149f22eb0a776384485a6a62df1d5f to your computer and use it in GitHub Desktop.
This file contains 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
# nch -- nim-based crappy hellhole | |
import sdl2, sdl2/gfx, sdl2.image, sdl2.ttf, basic2d, random, math | |
type | |
Input {.pure.} = enum none, quit, action | |
InputState {.pure.} = enum up, pressed, down, released | |
Game = ref object | |
input: array[Input, bool] | |
inputLast: array[Input, bool] | |
states: seq[State] | |
ren: RendererPtr | |
exiting: bool | |
fpsman: FpsManager | |
State = ref object | |
name: string | |
init: proc (state: State) | |
step: proc (state: State, dt: float) | |
draw: proc (state: State) | |
exit: proc (state: State) | |
stepping: bool | |
drawing: bool | |
exiting: bool | |
game: Game | |
SDLException = object of Exception | |
# TODO: stop using this lol | |
let nullState = State( | |
name: "INVALID STATE" | |
) | |
# | |
## GAME ## | |
# | |
proc newGame(ren: RendererPtr): Game = | |
new result | |
result.ren = ren | |
result.exiting = false | |
result.states = @[] | |
result.fpsman.init() | |
result.fpsman.setFramerate(60) | |
return result | |
proc hasState(game: Game): bool = | |
return game.states.len > 0 | |
proc curState(game: Game): State = | |
if game.hasState: | |
var i = 0; | |
while (i < game.states.len): | |
if game.states[game.states.high() - i].stepping: | |
return game.states[game.states.high() - i] | |
i += 1 | |
echo "tried to get current State when there were none" | |
return nullState | |
proc pushState(game: Game, state: State) = | |
var newState: State | |
deepCopy(newState, state) | |
newState.stepping = true | |
newState.drawing = true | |
newState.exiting = false | |
newState.game = game | |
game.states.add(newState) | |
proc setState(game: Game, state: State) = | |
if game.hasState: | |
game.curState.stepping = false | |
game.pushState(state) | |
game.curState.stepping = true | |
proc exit(state: State) = | |
state.exiting = true | |
proc cleanupStates(game: Game) = | |
var i = 0 | |
while i < game.states.len: | |
if game.states[i].exiting: | |
if (i > 0): | |
game.states[i - 1].stepping = true | |
game.states.delete(i) | |
else: | |
i += 1 | |
proc toInput(key: Scancode): Input = | |
case key | |
of SDL_SCANCODE_SPACE: Input.action | |
of SDL_SCANCODE_ESCAPE: Input.quit | |
else: Input.none | |
proc handleInput(game: Game) = | |
shallowCopy(game.inputLast, game.input) | |
var event = defaultEvent | |
while pollEvent(event): | |
case event.kind | |
of QuitEvent: | |
game.exiting = true | |
of KeyDown: | |
game.input[event.key.keysym.scancode.toInput] = true | |
of KeyUp: | |
game.input[event.key.keysym.scancode.toInput] = false | |
else: | |
discard | |
proc getInput(game: Game, input: Input): InputState = | |
if not game.input[input] and not game.inputLast[input]: return InputState.up | |
if game.input[input] and not game.inputLast[input]: return InputState.pressed | |
if game.input[input] and game.inputLast[input]: return InputState.down | |
return InputState.released | |
proc step(game: Game) = | |
# quit | |
if game.getInput(Input.quit) == InputState.pressed: | |
game.exiting = true | |
let dt = game.fpsman.getFramerate() / 1000 | |
# state step | |
for state in game.states: | |
if state.stepping and not state.step.isNil: | |
state.step(state, dt) | |
proc draw(game: Game) = | |
# state draw | |
for state in game.states: | |
if state.drawing and not state.draw.isNil: | |
state.draw(state) | |
game.ren.present() | |
template sdlFailIf(cond: typed, reason: string) = | |
if cond: raise SDLException.newException( | |
reason & ", SDL error: " & $getError()) | |
# | |
## STATES ## | |
# | |
# clear screen, state that goes behind everything always probably | |
let clearScreenState = State( | |
name: "clearScreenState", | |
draw: proc (state: State) = | |
let ren = state.game.ren | |
ren.setDrawColor(0, 0, 0, 255) | |
ren.clear() | |
) | |
# title screen | |
let titleScreen = State( | |
name: "TitleScreen", | |
step: proc (state: State, dt: float) = | |
if getInput(state.game, Input.action) == InputState.pressed: | |
echo "title action!" | |
, | |
draw: proc (state: State) = | |
let ren = state.game.ren | |
ren.setDrawColor(0, 255, 0, 255) | |
ren.clear() | |
ren.setDrawColor(color(255, 255, 255, 255)) | |
ren.drawLine(0.cint, 0.cint, 160.cint, 120.cint) | |
ren.setDrawColor(color(255, 255, 255, 255)) | |
ren.drawLine(160.cint, 0.cint, 0.cint, 120.cint) | |
) | |
# splash screen | |
let splashScreen = State( | |
name: "SplashScreen", | |
step: proc (state: State, dt: float) = | |
if getInput(state.game, Input.action) == InputState.pressed: | |
echo "splash action!" | |
exit(state) | |
, | |
draw: proc (state: State) = | |
let game = state.game | |
game.ren.setDrawColor(255, 0, 0, 255) | |
game.ren.clear() | |
) | |
# | |
## MAIN ## | |
# | |
proc main = | |
sdlFailIf(not sdl2.init(INIT_VIDEO or INIT_TIMER or INIT_EVENTS)): | |
"SDL2 initialization failed" | |
defer: sdl2.quit() | |
sdlFailIf(not setHint("SDL_RENDER_SCALE_QUALITY", "0")): | |
"Linear texture filtering could not be enabled" | |
let window = createWindow(title = "nch", | |
x = SDL_WINDOWPOS_CENTERED, y = SDL_WINDOWPOS_CENTERED, | |
w = 160, h = 120, flags = SDL_WINDOW_SHOWN) | |
sdlFailIf window.isNil: "Window could not be created" | |
defer: window.destroy() | |
let renderer = window.createRenderer(index = -1, | |
flags = Renderer_Accelerated or Renderer_PresentVsync) | |
sdlFailIf renderer.isNil: "Renderer could not be created" | |
defer: renderer.destroy() | |
renderer.setDrawColor(0, 0, 0, 255) | |
var game = newGame(renderer) | |
game.setState(clearScreenState) | |
game.setState(titleScreen) | |
game.setState(splashScreen) | |
# game loop | |
while not game.exiting: | |
game.handleInput() | |
game.step() | |
game.draw() | |
game.cleanupStates() | |
game.fpsman.delay() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment