まずは、以下のようなプログラムからはじめよう。
val (vx,vy)=(10,10) //移動速度のx成分とy成分
val c=s.circle(0,0,20)
s.loop{
s.translate(vx,vy)
Thread.sleep(100)
}
(サンプル1も参照)
![]() |
枠のデータ設定 |
(つまり、壁に当たると反射するように動かす)
vx, vy を(valでなく)var変数に変える。
var (vx,vy)=(10,10)
SimpleShapeオブジェクト(circleを含む)の現在位置を求める関数を作っておく(このほうがコードが簡略になる)。
def pos(o:net.kogics.kojo.staging.SimpleShape):Point=c.origin+c.offset
![]() |
方向の反転(の書き方) |
ループの中(sleepの直前ぐらいが適切な場所だろう)で以下の判断を行う
if(pos(c).x>rx||pos(c).x<lx)vx= -vx
if(pos(c).y>ty||pos(c).y<by)vy= -vy
ifの条件式の () の中で「または」の意味の論理演算子 ||
を使わずに書くなら、
if(pos(c).x>rx)vx= -vx
if(pos(c).x<lx)vx= -vx
if(pos(c).y>ty)vy= -vy
if(pos(c).y<by)vy= -vy
という4行の記述になる。
(サンプル2も参照)
(なるべく整理したほうが望ましい)。
![]() |
各図形ごとの速度成分の変数 |
オブジェクト(と速度成分値をタプルにしたもの)の集合体を生成するコード。
var l = for (i <- 1 to 30) yield
(s.circle(i * 5, random(20)-10, 2),
i * 0.2, i * 0.3)
loopの中でこれらの各要素を、translateメソッドで移動させる。
for ((c, vx, vy) <- l)
c.translate(vx, vy)
このとき、6.2のコードを forのループの中にそのまま移行した、
for ((c, vx, vy) <- l) {
c.translate(vx, vy)
if(pos(c).x>rx||pos(c).x<lx)vx= -vx
if(pos(c).y>ty||pos(c).y<by)vy= -vy
}
のようなコードは、動作しない。その理由は、
喩えて言えば、作業場での一時的な変更項目は、倉庫には反映されていない、ということ。
以上をまとめると以下のようなコードになる。
l=for ((c, vx, vy) <- l) yield {
c.translate(vx, vy)
(c,
if(pos(c).x>rx||pos(c).x<lx)-vx else vx ,
if(pos(c).y>ty||pos(c).y<by)-vy else vy
)
}
(サンプル3も参照)
![]() |
メインループとイベント駆動 |
ユーザ主導で発生させるイベントに対する応答を
画面上のオブジェクトにあらかじめ教えておく、という書き方もできる。
例えば以下のような呼び方。
tCanvas.onMouseClick{(x,y)=>
s.circle(x,y,100).fill(red)
}
=>
を置き、上記の例では、onMouseClickメソッドのレシーバとして
tCanvas(キャンバスを表すオブジェクト)を使ったので、
キャンバス上のどこでクリックしても有効だった。
それに対して、
val c=s.circle(0,0,100)
c.onMouseClick{(x,y)=>
println(x,y)
}
のように描画オブジェクトに対してイベントハンドラを設定することもできる。