2012年7月24日火曜日

[ドリトル] キーボード操作でドリフト亀

ドリトルでキーボードイベントを拾ってみた。

button1 = Button ! "button" "UP" create.
button1:action = [self! "hoge" set].

GUIオブジェクトを作成する際に第 2 引数でキーと関連付けておけば、 キー押下時に当該オブジェクトの action 命令が呼び出される。うーん、シンプル。

label1 = Label ! "label" create.
button1 = Button ! "button" "UP" create hide.
button1:action = [label1! "hoge" set].

こんな感じにイベントを受け取るオブジェクトが hide されていてもちゃんと action は発生する。

キーを押しっぱなしにすれば連続してイベントを受け取れるのだが、キーイベントの発生の特性から、 最初の1つ目のイベント発生からやや間をおいて2つ目以降のイベントが発生する。
リアルタイムに何かを連続的に制御するようなプログラムではタイムラグが発生するような感じになると思う。

value = 1.
button1 = Button ! "button" "UP" create.
button1:action = [
  self! (value) set.
  value = value + 1].




ドリトルのサンプルの中の宝物拾いのプログラムがあったので似たようなものを作ってみよう。
素直に曲がるタートルにしてもつまらないので、 この前の自転タートルの要領で、 ドリフトしながら曲がっていくタートルを作ってみる。
  • プロトタイプとして使うように作る(DriftTurtle)
  • leftTurn、rightTurn では見かけの向きだけが変わり、進行方向はすぐには変わらない。
  • 実際の進行方向は見かけの向きの方向へ徐々に変わる。
こんな感じで。作りは前回同様、自タートルは進行方向を向いて非可視、内部タートルが見かけの向きを向く可視タートル。
衝突判定は内部タートル側に発生するので、それを外部タートル側へ引き渡す処理が必要。

DriftTurtle = Turtle ! create.
DriftTurtle ! "" setShape 0.05 scale.
DriftTurtle ! penup hide.
DriftTurtle ! 1 linewidth pendown.

DriftTurtle:leftturn = [ | deg | self:innerTurtle ! (deg) leftturn. self.].
DriftTurtle:rightturn = [ | deg | self:innerTurtle ! (deg) rightturn. self.].
DriftTurtle:forward = [ | step; forward | ! (step) forward.
    self:innerTurtle ! (!xPosition?) (!yPosition?) moveto. self.].
DriftTurtle:movetocenter = [ | ; movetocenter | ! movetocenter. self:innerTurtle ! movetocenter. self.].

DriftTurtle:init = [ 
  self:innerTurtle = Turtle ! create penup.
  self:innerTurtle:owner = self.
  self:innerTurtle:collision = [ | target moveself |   
     owner ! (target) (moveself) collision. ].

  self:driftTimer = Timer ! create 0.1 interval 600 duration.
  self:driftTimer ! [ | ; deg1 deg2 degDiff leftturn | 
    deg1 = ! direction? .
    deg2 = self:innerTurtle ! direction? .
    degDiff =  deg2 - deg1.
    [ degDiff > 180 ] ! then [degDiff = degDiff - 360 ] execute.
    [ degDiff < -180] ! then [degDiff = degDiff + 360 ] execute.

    ! (degDiff / 15.0 ) leftturn.
    self:innerTurtle ! (! xPosition?) (! yPosition?) moveto.
  ] execute.
].
DriftTurtle:create = [ | ; create created | created = !create. created! show init. created].

//----- End of DriftTurtle definition. ------------

t1 = DriftTurtle ! create.

btnLeft = Button! "←" "LEFT" create.
btnRight = Button! "→" "RIGHT" create.
btnCenter = Button! "戻る" "UP" create.

btnLeft:action = [ t1 ! 10 leftturn.] .
btnright:action = [ t1 ! 10 rightturn.] .
btncenter:action = [ t1 ! movetocenter. ].

timer1 = Timer!create.
timer1 ! 0.02 interval 600 duration.
timer1 ! [ | ; r1 r2 dr|
  t1 ! 4 forward.
] execute.

t1:collision = [ | subject |
  subject ! hide.
  targets ! (subject) remove.
  [ (targets ! size?) == 0] ! then [
    Label ! "complete." create.
    timer1 ! stop.
  ] execute.
].

TARGET_NUM = 10.
targets = Array ! create.
[ | ; target |
  target = Turtle!create.
  target ! "apple.png" setShape penup.
  target ! (random(600) - 300) (random(400) - 200) moveto.
  targets ! (target) add.
] ! (TARGET_NUM) repeat.


進行方向と見かけの向きの補正は 0.1秒ごとに 1/15 ずつ縮っていく。
なので進行方向と見かけの向きの差が大きいほど曲がるのだが、差が 180 度を越えると反対側に曲がり始めるので注意が必要。

なかなかむかつく感じに動くタートルになった。
うっかりするとすぐ場外になってどこに行ったか分からなくなるので「↑」でセンターに戻るようにしてある。

動きがわかるように、pendown してあるが弱いPCだと線が多くなって遅くなるかもしれない。 不要なら作成した t1 を penup すればいい。


0 件のコメント:

コメントを投稿