読者です 読者をやめる 読者になる 読者になる

`(kakko ,man)

Find a guide into tomorrow by taking lessons from the past

Lisp Game Programming 再履修 <その5> Bordeaux-threads トライアル

再履修

Bordeaux-threads を sbclrc に書き加え、ライブラリとして使える状況になっているものの、未だ使ったことがない。
ならばと無理矢理使ってみたものの、微妙な結果に終わった。

defpackage の部分に、

;; -----------------------------------------------------------------------------------------------
(defpackage :game
  (:use :common-lisp :lispbuilder-sdl)
  (:nicknames :boulderdash)
  (:export #:Common-boulderdash))

:bordeaux-threads を追加し、

;; -----------------------------------------------------------------------------------------------
(defpackage :game
  (:use :common-lisp :lispbuilder-sdl :bordeaux-threads)
  (:nicknames :boulderdash)
  (:export #:Common-boulderdash))

Draw-game の部分で、

(defun Draw-game (level player-position status)
  (sdl:clear-display sdl:*black*)
  (loop for y from (- (cdr player-position) (floor +screen-tile-height+ 2)); player-positon -7
        for screen-y from 0  
        repeat +screen-tile-height+

clear-display を外し、

(defun Draw-game (level player-position status)
 ; (sdl:clear-display sdl:*black*)
  (loop for y from (- (cdr player-position) (floor +screen-tile-height+ 2)); player-positon -7
        for screen-y from 0  
        repeat +screen-tile-height+

ここのところを、

 ;<Draw Game>
  (Draw-game level player-position status)

clear-display と draw-game をスレッドにしたものに変更してみる。

;<Draw Game>
  (sdl:clear-display sdl:*black*)

  (let ((Drawthread (bordeaux-threads:make-thread #'(lambda ()                                     ; 1 thread not split screen
                                     (Draw-game level player-position status))
                                     :name "Drawthread")))  
	      	 (bordeaux-threads:join-thread Drawthread))                                        ; wait for end thread

当然、普通に動く!

じゃあさ。画面を2つに分けて描画する準備として、1つの thread が終わったら 次の thread が動くようにしたらどうよ。
まずは、Draw-game の部分を、

(defun Draw-game (level player-position status)
 ; (sdl:clear-display sdl:*black*)
  (loop for y from (- (cdr player-position) (floor +screen-tile-height+ 2)); player-positon -7
        for screen-y from 0  
        repeat +screen-tile-height+
        do (loop for x from (- (car player-position) (floor +screen-tile-width+ 2)); player-position -8
                 for screen-x from 0

画面を2つに分けて描画するため、player の位置を基準として、x-flag = 1 の時は右側とし、x-offset は左側を描画するときのスタート位置としてプログラムコードを変更し、

(defun Draw-game (level player-position status x-flag x-offset)
 ; (sdl:clear-display sdl:*black*)
  (loop for y from  (- (cdr player-position) (floor +screen-tile-height+ 2)); player-positon -7
        for screen-y from 0  
        repeat +screen-tile-height+
        do (loop for x from (if (= x-flag 1)
		              (- (car player-position) (floor +screen-tile-width+ 2)); player-position -8
			      (car player-position))
                 for screen-x from x-offset

先に変更したこのコードを、

;<Draw Game>
  (sdl:clear-display sdl:*black*)

  (let ((Drawthread (bordeaux-threads:make-thread #'(lambda ()                                     ; 1 thread not split screen
                                     (Draw-game level player-position status))
                                     :name "Drawthread")))  
	      	 (bordeaux-threads:join-thread Drawthread))                                        ; wait for end thread

左右を分割して描画するコードに再変更する。

 ;<Draw Game>
  (sdl:clear-display sdl:*black*)

   (let ((Drawthread1 (bordeaux-threads:make-thread #'(lambda ()                     ; split screen to left or right
			               (Draw-game level player-position status 1 0)) ; 1 -> screen left side    0 -> offset 0
                                       :name "Drawthread1")))
	 (bordeaux-threads:join-thread Drawthread1))
	    
   (let ((Drawthread2 (bordeaux-threads:make-thread #'(lambda ()
				       (Draw-game level player-position status 2 8)) ; 2 -> screen right side   8 -> offset 8
				       :name "Drawthread2")))		  
	 (bordeaux-threads:join-thread Drawthread2))		 

これまた、当然普通に動く!!

では、ここでお立合い。
下のように、1つの thread が終了する前にもう1つの thread を動かして表示したらどうよ。

;<Draw Game>
  (sdl:clear-display sdl:*black*)

  (let ((Drawthread1 (bordeaux-threads:make-thread #'(lambda ()                     ; split screen to left or right
			              (Draw-game level player-position status 1 0)) ; 1 -> screen left side    0 -> offset 0
                                      :name "Drawthread1"))  
	(Drawthread2 (bordeaux-threads:make-thread #'(lambda ()
			              (Draw-game level player-position status 2 8)) ; 2 -> screen right side   8 -> offset 8
				      :name "Drawthread2")))		  
	      	 (bordeaux-threads:join-thread Drawthread1)                         ; wait for end threads
		 (bordeaux-threads:join-thread Drawthread2))		 

動きます。ただし・・・・・・・・!
画面が「あばれる君」になります。
ニュアンス的には、empty(描画しない部分)が、ランダムな位置に点滅するようなイメージで、目がチカチカすると言えばわかるかな?
本当はこんな感じで描画されるはずが、
f:id:tomekame0126:20161125215402p:plain

こんな感じになる。(左側の wall の位置が欠けている)
f:id:tomekame0126:20161204163259p:plain

いい歳ですが、まだまだ未熟者ということで。