SNIPPETS
Engine Initialization
# mygame.nim
import
nimgame2 / [
nimgame,
settings,
]
mainscene # your first scene
game = newGame()
if game.init(w = 640, h = 480, title = "My Awesome Game"):
game.scene = newMainScene() # your scene constructor
game.run()
Scene Initialization
# mainscene.nim
import
nimgame2 / [
nimgame,
entity,
scene,
settings,
texturegraphic,
types
]
type
MainScene = ref object of Scene
myGraphic: TextureGraphic
myEntity: Entity
proc init*(scene: MainScene) =
# don't forget the parent initialization!
Scene(scene).init()
# create the graphic
scene.myGraphic = newTextureGraphic()
# load graphic file
discard scene.myGraphic.load("data/gfx/my_image.png")
# create the entity
scene.myEntity = newEntity()
# assign the graphic to the entity
scene.myEntity.graphic = scene.myGraphic
# add your entity to the scene
scene.add(scene.myEntity)
proc free*(scene: MainScene) =
# free the texture
scene.myGraphic.free()
proc newMainScene*(): MainScene =
# scene constructor
new result, free
result.init()
method event*(scene: MainScene, event: Event) =
# call it if your entities have their own event handlers
scene.eventScene(event)
# if you want to handle some events manually, you do it here
if event.kind == KeyDown:
case event.key.keysym.scancode:
of ScancodeEscape:
# stop the engine (see nimgame2/settings.nim)
gameRunning = false
else: discard
method render*(scene: MainScene) =
# don't forget to call the parent render!
scene.renderScene()
# if you want to draw something on top of a rendered scene,
# you do it here
method update*(scene: MainScene, elapsed: float) =
# don't forget to call the parent update!
scene.updateScene(elapsed)
# scene-level logic goes here
Entity Initialization
# myentity.nim
import
nimgame2 / [
nimgame,
entity,
texturegraphic,
]
type
MyEntity* = ref object of Entity
proc init*(entity: MyEntity, graphic: TextureGraphic) =
# don't forget to call the parent initialization!
entity.initEntity()
# assign the graphic
entity.graphic = graphic
# set the center point
entity.centrify()
# assign the physics only if you need it
entity.physics = defaultPhysics
proc newMyEntity*(graphic: TextureGraphic): MyEntity =
# entity constructor
new result
result.init(graphic)
method update*(entity: MyEntity, elapsed: float) =
# don't forget to call the parent update!
entity.updateEntity(elapsed)
# entity-level logic goes here
Sprite Initialization
# somewhere in the entity initialization routine
# assign the graphic
entity.graphic = graphic
# set the sprite dimensions and offset
# (if the graphic has a border)
entity.initSprite((24, 48), offset = (16, 16))
# add animations
discard scene.d.addAnimation(
"run_right", [0, 1, 2, 3])
discard scene.d.addAnimation(
"run_left", [0, 1, 2, 3], flip = Flip.horizontal)
# or, if your frames are in order,
# use toSeq() from types.nim
discard scene.d.addAnimation(
"jump_right", toSeq(4..7))
discard scene.d.addAnimation(
"jump_left", toSeq(4..7), flip = Flip.horizontal)
Collider Initialization
# somewhere in the entity initialization routine
entity.collider = newBoxCollider(entity, (0, 0), entity.graphic.dim)
TextGraphic Usage
# somewhere in the scene initialization routine
# BitmapFont
# create a bitmap font
scene.bitmapFont = newBitmapFont()
# load the font file, giving the dimensions of a single character
discard scene.bitmapFont.load("data/font/bitmap.png", (8, 16))
# create a text graphic
scene.bitmapText = newTextGraphic()
# assign the font
scene.bitmapText.font = scene.bitmapFont
# set the text
scene.bitmapText.lines =
[ "Text line 1",
"Text line 2"]
# create an entity
scene.bitmapEntity = newEntity()
# assign the graphic
scene.bitmapEntity.graphic = scene.bitmapText
# add to the scene
scene.add(scene.bitmapEntity)
# TrueTypeFont
# create a TrueType font
scene.trueTypeFont = newTrueTypeFont()
# load the font file, giving the font size
discard scene.trueTypeFont.load("data/font/truetype.ttf", 16)
# create a text graphic
scene.trueTypeText = newTextGraphic()
# assign the font
scene.trueTypeText.font = scene.trueTypeFont
# set the text
scene.trueTypeText.lines =
[ "Text line 1",
"Text line 2"]
# create an entity
scene.trueTypeEntity = newEntity()
# assign the graphic
scene.trueTypeEntity.graphic = scene.trueTypeText
# add to the scene
scene.add(scene.trueTypeEntity)
ProcGraphic Usage
# somewhere in the initialization routine
proc customProc(graphic: ProcGraphic,
pos: Coord,
angle: Angle,
scale: Scale,
center: Coord,
flip: Flip,
region: Rect) =
# your custom drawing routine goes here
proc init*(scene: MyScene) =
Scene(scene).init()
# create a ProcGraphic
scene.customGraphic = newProcGraphic()
# assign the procedure
scene.customGraphic.procedure = customProc
# create an entity
scene.myEntity = newEntity
# assign the graphic
scene.myEntity.graphic = scene.customGraphic
# add to the scene
scene.add(scene.myEntity)
IndexedImage Usage
# somewhere in the initialization routine
let myImage = newIndexedImage("data/gfx/unit.gif")
var color = myImage.palette[8] # get palette color
color.r = 255
color.g = 0
color.b = 0
myImage.palette[8] = color # set palette color
# generate graphic
let myGraphic = newTextureGraphic()
discard myGraphic.assignTexture myImage.render()
PerspectiveImage Usage
# somewhere in the initialization routine
let myImage = newPerspectiveImage("data/gfx/pimage.png")
let myGraphic = newTextureGraphic()
# render with distortion
myGraphic.assignTexture myImage.render(pdHor, 64, 32)
let myEntity = newEntity()
myEntith.graphic = myGrapghic
scene.add(myEntity)
TextureAtlas Usage
# somewhere in the initialization routine
let myAtlas = newTextureAtlas("data/gfx/atlas.png", "data/csv/atlas.csv")
entity1.graphic = myAtlas["image1"]
entity2.graphic = myAtlas["image2"]
Tween Usage
let tween = newTween[Entity,Coord](
target = myEntity,
get = proc(t: Entity): Coord = t.pos,
set = proc(t: Entity, val: Coord) = t.pos = val
)
tween.procedure = inQuad
tween.setup(
start = myEnttiy.pos,
finish = myEntityPos + (100.0, 0.0),
duration = 3.0,
loops = -1
)
tween.play()
Emitter Usage
# somewhere in the initialization routine
# init emitter
myEmitter = newEmitter(myScene)
myEmitter.randomVel = (10.0, 10.0)
myEmitter.randomAcc = (5.0, 5.0)
myEmitter.randomTTL = 5.0
myScene.add(myEmitter)
# init emitter particle
myEmitter.particle = newParticle()
myEmitter.particle.graphic = myParticleGraphic
myEmitter.particle.initSprite((5, 5))
myEmitter.particle.centrify()
discard myEmitter.particle.addAnimation("play", toSeq(0..4), 1/5)
myEmitter.particle.play("play", 1, kill = true)
# somewhere in the update routine
if emitCondition:
myEmitter.emit(5) # emit 5 particles
TileMap Usage
# somewhere in the initialization routine
# tiles
scene.tilesGraphic = newTextureGraphic()
discard scene.tilesGraphic.load("data/gfx/tile.png")
# map
scene.map = newTileMap(scaleFix = true)
scene.map.graphic = scene.tilesGraphic
scene.map.initSprite((64, 64), offset = (0, 0))
scene.map.map = loadCSV[int](
"data/csv/map.csv",
proc(input: string): int = discard parseInt(input, result)
)
scene.map.passable.add(0)
scene.add(scene.map)
TileMap Collision List
# checking specific tile collisions
let
collider = TilemapCollider(map.collider)
collisions = collider.collisionList(myEntity.collider)
for tile in collisions:
echo
"Collided with " & $tile.value & " at " & $tile.mapx & ":" & $tile.mapy
Camera Usage
# somewhere in the initialization routine
scene.camera = newEntity()
scene.map = newMyMap()
scene.map.parent = scene.camera # this entity is bound to the camera
scene.add(scene.map)
scene.player = newMyPlayer()
scene.player.parent = scene.map # this entity is bound to the map
scene.add(scene.player)
# this entity isn't bound to the camera
scene.ui = newUI()
scene.add(scene.ui)
# boud camera to this entity
scene.cameraBond = scene.player
# place camera bond entity at the center
scene.cameraBondOffset = game.size / 2
# somewhere in the update routine
if scene.cameraBond == nil:
if ScancodeRight.down: scene.camera.pos.x += step
# ...
else:
if ScancodeRight.down: scene.player.pos.x += step
# ...
Sound Usage
# somewhere in the initialization routine
# load a sound file
scene.soundEffect = newSound("data/sfx/effect.wav")
# set the volume
scene.soundEffect.volume = Volume.high div 2
# somewhere else
# the call
scene.soundEffect.play()
Music Playlist Usage
# somewhere in the initialization routine
# load all music files
var musicData: Assets[Music]
musicData = newAssets[Music]("data/music",
proc(file: string): Music = newMusic(file))
# global playlist
playlist = newPlaylist()
# fill the playlist
for track in musicData.values:
playlist.list.add(track)
# somewhere else
# next random track
discard playlist.play()
# somewhere in the update routine
playlist.update()
GUI: Actions
# action procedure
proc myBtnAction(widget: GuiWidget) =
echo "clicked my button"
# somewhere in the initialization routine
# skin loading
let mySkin = newTextureGraphic()
discard mySkin.load("data/gfx/button_skin.png")
# button initialization
myBtn = newGuiButton(mySkin)
myBtn.action = myBtnAction
scene.add(myBtn)
GUI: Text Input (+ Mosaic)
import
nimgame2 / [
scene,
mosaic,
texturegraphic,
truetypefont,
gui/widget,
gui/textinput,
]
# somewhere in the initialization routine
# mosaic creation
let myMosaic = newMosaic("data/gfx/textinput_skin.png")
let mySkin = newTextureGraphic()
discard mySkin.assignTexture myMosaic.render(patternStretchBorder(16, 1))
# text input initialization
myTextInput = newGuiTextInput(mySkin, myFont)
myTextInput.text.limit = 16 # set text length limit
scene.add(myTextInput)
GUI: Radio Groups
import
nimgame2 / [
scene,
texturegraphic,
truetypefont,
gui/widget,
gui/radio,
]
type
MyScene = ref object of Scene
radioButtons: array[3, GuiRadioButton]
radioGroup: GuiRadioGroup
# somewhere in the initialization routine
scene.radioGroup = newGuiRadioGroup() # create group
# init each button
for i in 0..scene.radioButtons.high:
scene.radioButtons[i] = newGuiRadioButton(scene.radioGroup, scene.mySkin)
scene.radioButtons[0].toggled = true # toggle the first button
# add to the scene
scene.add(scene.radioGroup)
for btn in scene.radioButtons:
scene.add(btn)
GUI: ProgressBar
# somewhere in the initialization routine
scene.bar = newProgressBar((200, 50), 0xFF0000FF'u32, 0xFF0000FF'u32, myFont)
scene.bar.min = 0
scene.bar.max = 100
scene.bar.direction = Direction.leftRight
scene.bar.outline = (1, 1) # one pixel outline
scene.add(scene.bar)
# on update
scene.bar.value = newValue