#はじめに
NimでSDL2 ① 準備とウィンドウ表示
NimでSDL2 ② 画像を表示
NimでSDL2 ③ 入力処理
NimでSDL2 ④ FPS(frames per second)の調整
NimでSDL2 ⑤ 音を出す
文字列を描画します。
#概要
まずはttfを初期化。
でttfファイルを読み込んで、FontPtrを作成。
そのFontPtrから文字列を指定してサーフェイスを作成。
そのサーフェイスをテクスチャーに変換して描画する。(ちとめんどい)
コード
追記箇所はコメント参照
# sdl2/ttfをimport
import sdl2, sdl2/image, os, sugar, sets, sdl2/mixer, sdl2/ttf
template sdlFailIf(cond: typed, desc: string) =
if cond: raise Exception.newException(
desc & ": " & $getError())
type FPS* = ref object
frameTime, targetFramePeriod: uint32
proc newFPS*(fps: int): FPS =
FPS(targetFramePeriod: uint32(1000 / fps))
proc adjust*(self: FPS) =
let now = getTicks()
if self.frameTime > now:
delay(self.frameTime - now)
self.frameTime += self.targetFramePeriod
type SDL2Context = ref object
window: WindowPtr
renderer: RendererPtr
cleanups: seq[proc ()]
pressed: HashSet[cint]
press: HashSet[cint]
fps: FPS
proc cleanup(self: SDL2Context) =
while self.cleanups.len > 0:
(self.cleanups.pop)()
proc init(self: SDL2Context, title: string, w, h: cint): SDL2Context {.discardable.} =
result = self
sdlFailIf(not sdl2.init(INIT_VIDEO), "SDL2 init")
self.cleanups.add(() => sdl2.quit())
self.window = createWindow(title = title,
x = SDL_WINDOWPOS_CENTERED,
y = SDL_WINDOWPOS_CENTERED,
w = w, h = h,
flags = SDL_WINDOW_SHOWN)
sdlFailIf(self.window.isNil, "createWindow")
self.cleanups.add(() => self.window.destroy)
sdlFailIf(image.init(IMG_INIT_PNG) != IMG_INIT_PNG, "image init")
self.cleanups.add(() => image.quit())
self.renderer = self.window.createRenderer(
index = -1,
flags = Renderer_Accelerated or Renderer_PresentVsync)
sdlFailIf(self.renderer.isNil, "createRenderer")
self.cleanups.add(() => self.renderer.destroy)
self.renderer.setDrawColor(r=0, g=128, b=128)
self.pressed = initHashSet[cint]()
self.fps = newFPS(60)
sdlFailIf(mixer.openAudio(
MIX_DEFAULT_FREQUENCY,
MIX_DEFAULT_FORMAT,
MIX_DEFAULT_CHANNELS,
4096) != 0, "openAudio")
self.cleanups.add(() => closeAudio())
# ttf初期化
sdlFailif(ttfInit() == SdlError, "ttfInit")
# クリーンアップ処理追加
self.cleanups.add(() => ttfQuit())
proc loadTexture(self: SDL2Context, path: string): TexturePtr =
result = self.renderer.loadTexture(path)
sdlFailIf(result.isNil, "loadTexture")
proc keyStateUpdate*(self: SDL2Context, event: KeyboardEventPtr) =
case event.kind
of KeyDown:
self.pressed.incl(event.keysym.sym)
self.press.incl(event.keysym.sym)
of KeyUp: self.pressed.excl(event.keysym.sym)
else: discard
proc pollEvent(self: SDL2Context): bool =
result = true
var event = defaultEvent
self.press.clear
while pollEvent(event):
case event.kind:
of QuitEvent: return false
of KeyDown, KeyUp: self.keyStateUpdate(event.key)
else: discard
proc mainLoop(self: SDL2Context) =
let
w: cint = 256
h: cint = 256
speed: cint = 3
neko = self.loadTexture("genbaneko.png")
var
windowWidth: cint
windowHeight: cint
let music = mixer.loadMUS("bgm.ogg")
sdlFailIf(music.isNil, "loadMUS")
let sound = mixer.loadWav("sound.wav")
sdlFailIf(sound.isNil, "loadWav")
self.window.getSize(windowWidth, windowHeight)
var dst = rect(windowWidth div 2 - w div 2, windowHeight div 2 - h div 2, w, h)
# ttfフォント読み込み
let font = openFont("./mplus-1p-regular.ttf", 48)
# エラーチェック
sdlFailIf(font.isNil, "openFont")
let
# ttfフォントから文字列のサーフェイスを作成
strSurface = font.renderUtf8Blended("ご安全に!!", color(255, 0, 0, 0))
# サーフェイスをテクスチャーに変更
strTexture = self.renderer.createTextureFromSurface(strSurface)
# サーフェイスの描画先Rectを作成
var strRect = rect(windowWidth div 2 - strSurface.w div 2, dst.y + dst.h - strSurface.h,
strSurface.w, strSurface.h)
while self.pollEvent:
if K_RIGHT in self.pressed: dst.x += speed
if K_LEFT in self.pressed: dst.x -= speed
if K_DOWN in self.pressed: dst.y += speed
if K_UP in self.pressed: dst.y -= speed
if K_m in self.press:
if playingMusic() == 0:
sdlFailif(playMusic(music, 0) == -1, "playMusic")
else:
sdlFailif(haltMusic() == -1, "haltMusic")
if K_s in self.press:
sdlFailif(playChannel(-1, sound, 0) == -1, "playChannel")
self.renderer.clear
self.renderer.copyEx(neko, nil, dst.addr, 0.0, nil, SDL_FLIP_NONE)
# 文字列のテクスチャーを描画
self.renderer.copyEx(strTexture, nil, strRect.addr, 0.0, nil, SDL_FLIP_NONE)
self.renderer.present
self.fps.adjust
proc main() =
let sdl2 = SDL2Context()
defer: sdl2.cleanup
sdl2.init("SDL2 Font sample", 640, 480).mainLoop
main()
結果
終わりに
SDL2の基本的な機能はできたと感じ。
これまでのコードを参考に色々やってもらえればと〜。
以上〜。