開発
Lispbuilder-SDL に触れてみた
Shota Oikawa
先日、FUKUSHIMA Hackathon 2017 に参加しました。そこで出会った方々とお話をして、コードをたくさん書きたいなーという気分になりました。
かれこれ 2,3ヶ月ほど Common Lisp を書いてないなー、でも最近趣味で絵を描いてるから、この二つで何か作りたいなー。そう思い、Lisp で画像系を扱うライブラリとか無いかなと探していたら、Lispbuilder-SDL なるものを見つけました。
Lispbuilder-SDL
Lispbuilder-SDL は、Common Lisp で大規模でインタラクティブなアプリケーションを構築するためのクロスプラットフォームパッケージです。SDL をラッパーしており、一般的にゲーム開発に使用されるライブラリです。
将来的に作りたいもの
Common Lisp で動くデスクトップマスコットです。Windows では Live2D を使うと簡単に作成できるのですが、ubuntu では対応してないのが非常に残念です。
プログラムを黙々と書いていると、癒やしが欲しくなってくるのです…。
Lispbuilder-SDL を動かすための準備
使用している環境
- ubuntu 16.04 LTS
- windows 10 (絵は SAI を使用して描いているため)
- spacemacs
- sbcl ( Lisp の処理系)
- SLIME ( Common Lisp のための統合開発環境です。 emacs 上で動かせます)
sbcl (Steel Bank Common Lisp)
こちらのサイトから最新版をダウンロードするのが良いと思います。
Lispbuilder-SDL
こちらのサイトを参考にしてインストールを行いました
http://d.hatena.ne.jp/tana-laevatein/20101023/1287782485
SLIME は、あると楽に開発できるので、もっと Lisp を書きたいという方は是非使用してみてください!
肩慣らし(ウィンドウの表示)
環境が構築できたら、手始めにウィンドウの表示を行います。(準備運動ですね)
(defvar *screec-width* 800) ;; window の横のサイズを 800 pixel
(defvar *screec-height* 600) ;; window の縦のサイズを 600 pixel
;; sdl:with-init で初期化から終了までを行う
(sdl:with-init ()
(sdl:window *screec-width* *screen-height* :title-caption "window creation") ;; window を 800 x 600 で初期化
(setf (sdl:frame-rate) 60) ;; ここの数値を上げると、よりヌルヌル動く。fps 設定のようなもの
(sdl:update-display)
(sdl:with-events ()
(:quit-event () t)
(sdl:update-display)
(:idle ()
(sdl:clear-display sdl:*black*)
(sdl:update-display))))
実行します…
無事に出力されました!
素材の用意
次に、デスクトップマスコットにしたいキャラを描いていきます。時間が無いので、2,3 時間でちゃちゃっと描きました。(SAI で)
素材のフォーマットは透過PNGにしました。
簡単な差分も
(自分にとって)短時間で描いた割には可愛く描けた気がする!やったね!
画像を出力する
先程のコードに画像を表示するコードを追加していきます。
その際の注意点があります。透過PNGをそのまま読み込んでも透過処理をしてくれないので、読み込む際に α チャネルを有効にする必要があります。
(defvar *image* nil) ;; 表示したい画像1
(defvar *image2* nil) ;; 表示したい画像2
(defvar *screen-width* 800) ;; 画面横サイズ 800 pixel
(defvar *screen-height* 600) ;; 画面縦サイズ 600 pixel
;;;----------------------------------------------------------------------------
;; αチャネルを有効にすることで、透過PNGをちゃんと透過させる
;;;----------------------------------------------------------------------------
(defun load-png-image (png-file)
(sdl:convert-to-display-format :surface (sdl:load-image png-file)
:enable-alpha t
:pixel-alpha t))
;;;----------------------------------------------------------------------------
;;; Toggles fullscreen/window mode.
;;;----------------------------------------------------------------------------
(let ((currently-fullscreen? nil))
(defun toggle-fullscreen ()
(if currently-fullscreen?
(sdl:resize-window *screen-width* *screen-height* :sw t :resizable t)
(sdl:resize-window *screen-width* *screen-height* :sw t :fullscreen t))
(setf currently-fullscreen? (if currently-fullscreen? nil t))))
(sdl:with-init ()
(sdl:window *screen-width* *screen-height* :title-caption "plot-png-demo")
(setf (sdl:frame-rate) 60)
(setf *image* (load-png-image "png/demo1.png"))
(setf *image2* (load-png-image "png/demo2.png"))
(sdl:initialise-default-font sdl:*font-10x20*)
(sdl:update-display)
(sdl:with-events ()
(:quit-event () t)
(:key-down-event ()
(when (sdl:key-pressed-p :sdl-key-escape) ;; esc を入力したら画面を閉じる
(sdl:push-quit-event))
(when (sdl:key-pressed-p :sdl-key-space) ;; space を入力したら全画面モードとウィンドウモードを切り替える
(toggle-fullscreen)))
(:video-expose-event () (sdl:update-display))
(:idle ()
(sdl:clear-display sdl:*black*)
(sdl:draw-surface-at *image* #(0 0))
(sdl:with-color (sdl:*cyan* nil nil)
(sdl:with-surface (sdl:*default-display* nil nil)
(sdl:draw-string-solid "This is my original charactor!!!" #(0 0))))
(sdl:update-display))))
おぉ…Common Lisp に優しくない code タグですね(笑)、# がコメントアウト扱いになっている…これは泣いてしまいそうw
実行します…
無事に出てきてくれてありがとう…
将来的にはデスクトップマスコット化させたいです
TODO
デスクトップマスコットとして実現するためには、ウィンドウ自体の透明化が必須です。しかし、ウィンドウ自体を透明化?させるコードの書き方が分からないので、道のりはまだ長そうです。
せっかく Common Lisp で書いているので、emacs や SLIME で返ってくるエラー出力とかを拾って、デスクトップマスコットに教えてもらうというのもやってみたいです。