●課題11A: マウスの位置に反応する形require 'sgl' window 200,200 loop do x = mouseX y = mouseY rect x-5, y-5, x+5, y+5 flip end mouseXとmouseYというのがポイントです。rectのところで四角を描いています。 ●課題12A: 複雑な形の描画require 'sgl' window -200, -200, 200, 200 beginObj(POLYGON) vertex 60, 90 vertex -120, 60 vertex -90, -90 vertex 120, -90 endObj wait 「window -200, -200, 200, 200」このように四つの値を指定することができます。 beginObj(POLYGON) color 100, 0, 0, 100 vertex 60, 90 color 0, 100, 0, 100 vertex -120, 60 color 0, 0, 100, 100 vertex -90, -90 color 100, 100, 0, 100 vertex 120, -90 endObjこのように頂点ごとに色を指定できます。 beginObj(POLYGON) color 100, 0, 0, 0 vertex 60, 90 color 0, 100, 0, 100 vertex -120, 60 color 0, 0, 100, 100 vertex -90, -90 color 100, 100, 0, 0 vertex 120, -90 endObjこのように頂点ごとに、透明度も変えられます。 ●課題13A: スムースな線の描画require 'sgl' useSmooth window -200, -200, 200, 200 beginObj(LINE_LOOP) color 100, 0, 0, 100 vertex 60, 90 color 0, 100, 0, 50 vertex -120, 60 color 0, 0, 100, 50 vertex -90, -90 color 100, 100, 0, 100 vertex 120, -90 endObj wait windowの前にポツンと置いてあるuseSmoothがポイントです。 beginObjの括弧の中は、一般的には POLYGON または LINE_LOOP を指定します。 この二つだけ使えればほぼ全ての形は描けます。それ以外にもいくつか指定 できる形があるのですが、使い方は同じなので特にとりあげません。以下に 一覧だけをあげておきます。 LINES, POINTS, LINE_STRIP, LINE_LOOP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN, QUADS, QUAD_STRIP, POLYGON, ●課題14A: 物体の移動require 'sgl' useSmooth window -200, -200, 200, 200 push translate 100, 0 rotateZ 10 scale 2 rect -5, -5, 5, 5 pop wait 今回でてきた新しいコマンドが、push, pop, translate, rotateZ, scaleです。 このコマンドを使うと、形を描くコマンドと、その位置、回転などを指 定するコマンドとを分離することができます。 ●課題15A: ボタンが押されたその時にrequire 'sgl' def setup window -200, -200, 200, 200 background 0 $x = 0 $y = 0 end def onMouseDown(x, y) $x = x $y = y end def display line 0, 0, $x, $y end mainloop ここで扱っているコマンドの使い方は、いままとまったく違うものです。 いままではプログラムはかかれている順番通りに実行されるというものでし た。しかしここで行っているのは、まずコマンドを登録して、それがその後 呼ばれて実行されるというものです。このようにプログラムの実行の順番が まったく違うというのがいままでと異なる点です。 まず、setup, onMouseDown, displayというコマンドを登録しています。 その後mainloopというコマンドをよんでいます。このメインループの中で、 全てのプログラムが実行され、適宜setup, displayがよびだされます。 そして、マウスのボタンが押された瞬間に、onMouseDownという関数が呼ばれます。 そのonMouseDownの前に、$xという$のついた変数がつかわれています。 これはなんでしょうか。なぜ$をつける必要があるのでしょうか。これがプ ログラムの実行の順番がかわったことと関係しています。実行の順番が、上 から下という単純な順番ではなくなったので、変数が使える範囲というのも 単純な順番ではわからなくなったのです。通常の変数は、使う範囲が限られ ていて、違うコマンドの中身では同じようには使えませんでした。 そこで$のついた変数を使います。$のついた変数は、プログラムにずっ とその値を使いつづけることを指定します。$のついた変数が、違うコマン ドにまたがって使われているのがわかるでしょう。このように違うコマンド にまたがって使われる変数には$をつける必要があるのです。 またプログラム中にあらわれているように、$x = 0 といった感じで、 あらかじめなんらかの値を代入して、この変数を使うということを示す必要があります。 ●課題16A: 円require 'sgl' def setup window -200, -200, 200, 200 background 100 $x = 0 $y = 0 end def onMouseDown(x, y) $x = x $y = y end def display color 100, 0, 0 circle($x, $y, 100) end mainloop 円を描きます。マウスボタンを押すと、ボタンを押したところに移動します。 プログラムの構造は課題15Aで導入された、新しい構造を使っています。 def display colorHSV 66, 100, 100, 30 circle($x, $y, 100, POLYGON) end 塗り潰された円を描きます。 def display colorHSV 33, 100, 100, 30 circle($x, $y, 100, POLYGON, 5) end 五角形を描きます。いままで円を書いてきましたが、実は正確には32角形を描いていたのです。 その証拠に上記circle文の5のところを32にすると、普通の円と同じになります。 def display x = mouseX y = mouseY colorHSV 8, 100, 100, 50 circle(x, y, 100, POLYGON, 7) end マウスを押されないでもついてくるようにするには、上記のようにします。 ●課題18A: 3Drequire 'sgl' window -200, -200, 200, 200 push color 100, 0, 0 translate 30, 40, 20 rotateZ 10 rotateY 20 rotateX 30 scale 20 rect -5, -5, 5, 5 pop wait 課題14のところでだした物体の移動の例とほとんど同じです。 つまり実はあの課題はほとんど3Dの説明と同じことだったわけですね。 違いは、translate 30, 40, 20というふうに三つの値を指定しているところ、 rotateZだけじゃなく、rotateY rotateXを使っているところです。 もちろん三つめの値はZ軸、つまり奥行きです。 手前にくるのが正の値、奥のほうに行くのが負の値です。 また、vertexを使った形の描画でも、今はvertexの後に値を二つだけ指定していますが、 これも同じように三つの値を指定することで3Dに対応できます。 require 'sgl' def setup window -200, -200, 200, 200 background 100 end def display x = mouseX y = mouseY push color 100, 0, 0 translate x, y, 0 rotateX x rotateY y scale 20 rect -5, -5, 5, 5 pop end mainloop 上記のように、マウスの移動と組み合わせることもできます。 require 'sgl' def setup window -200, -200, 200, 200 background 100 $pos = [] #中身が空の配列を用意します。 end def display x = mouseX y = mouseY $pos << [x, y] #配列に、現在のマウスの位置を追加します。 $pos.each {|pos| #配列の各々の要素について、{}の中身を実行します。 #その各々の要素は、posという変数に入ります。 x = pos[0] y = pos[1] push colorHSV 0, 100, 100, 10 translate x, y, 0 rotateX x rotateY y scale 20 rect -5, -5, 5, 5 pop } if 10 < $pos.length #もし配列がたまりすぎた場合は、先頭から順に捨てていきます。 $pos.shift end end mainloop 配列の使用と組み合わせてみました。 ●課題19A: 速度require 'sgl' def setup window -200, -200, 200, 200 background 100 $x = 0 $y = 0 end def display x = mouseX y = mouseY speed = 20.0 vx = (x - $x)/speed vy = (y - $y)/speed $x = $x + vx $y = $y + vy color 100, 0, 0 circle($x, $y, 50, POLYGON) end mainloop いままで物の位置だけを扱ってきましたが、そこに速度を導入しています。 円がマウスのところに近付こうとします。 require 'sgl' def setup window -200, -200, 200, 200 background 100 $pos=[] for i in 0..9 $pos[i] = [-200 + i * 40, 0] #最初の位置を指定します。 end end def display x = mouseX y = mouseY speed = 10.0 for i in 0..9 pos = $pos[i] vx = (x - pos[0]) / speed #マウスに吸い寄せられる速度 vy = (y - pos[1]) / speed speed += 2.0 #円によって速度が異なるようにする。 pos[0] = pos[0] + vx #マウスに吸い寄せられた位置 pos[1] = pos[1] + vy color 100, 0, 0, 10 circle(pos[0], pos[1], 50, POLYGON) end end mainloop 配列の使い方をわかりやすく説明しています。 require 'sgl' def setup window -200, -200, 200, 200 background 100 $pos=[] $orgpos=[] for i in 0..19 $pos[i] = [-200 + i * 40, 0] #最初の位置を指定します。 $orgpos[i] = [-200 + i * 40, 0] #最初の位置をもう一つ別の配列に保存しておきます。 end end def display x = mouseX y = mouseY for i in 0..19 pos = $pos[i] #現在の円の位置 orgpos = $orgpos[i] #元々の位置 if mouseDown #マウスのボタンが押されているときだけ、マウスに吸いつく。 vx = x - pos[0] vy = y - pos[1] mag = Math.sqrt(vx * vx + vy * vy) mag = mag / 40 mag = mag * mag + 1 vx = vx / mag vy = vy / mag pos[0] = pos[0] + vx pos[1] = pos[1] + vy end speed = 3.0 vx2 = (orgpos[0] - pos[0]) / speed #元々の位置に吸い寄せられる速度 vy2 = (orgpos[1] - pos[1]) / speed pos[0] = pos[0] + vx2 #マウスに吸い寄せられた位置 pos[1] = pos[1] + vy2 color 100, 0, 0, 30 circle(pos[0], pos[1], 50, POLYGON) end end mainloop マウスにすいよせられる円です。マウスボタンを押しているときだけ反応します。 簡単そうに見えるかもしれませんが、実際にやってることは難しいです。 require 'sgl' def setup window -200, -200, 200, 200 background 100 $xpos = [] #配列を準備する。 $ypos = [] for i in 0..9 $xpos[i] = -200 + i * 40 $ypos[i] = 0 end end def display x = mouseX y = mouseY speed = 10.0 for i in 0..9 vx = (x - $xpos[i]) / speed #マウスに吸い寄せられる速度 vy = (y - $ypos[i]) / speed speed += 2.0 #円によって速度が異なるようにする。 $xpos[i] = $xpos[i] + vx #マウスに吸い寄せられた位置 $ypos[i] = $ypos[i] + vy color 100, 0, 0, 10 circle($xpos[i], $ypos[i], 50, POLYGON) end end mainloop 配列の使い方をもう少しわかりやすくしました。 ●課題20A: キーボードからの入力の仕方require 'sgl' def setup window 200, 200 background 100 $key = 0 end def onKeyDown(key) p key $key = key end def display colorHSV $key, 100, 100 line $key, 0, $key, 200 end mainloop アルファベットのキーを押すと、keyというところに1〜26の値がはいっ てきます。Aを押したときは1、Zを押したときは26です。 授業の範囲内ではアルファベットのキーだけでやってみてください。 以下はそれ以外のキーも使いたい人のためのアドバンスな知識として書いています。 それら以外のキーを押したときは、いろいろな数値がはいってきます。 例えば数字の0が押されたときは、SDL::Key::K0という値がはいってきます。 このへんはSDLという元のライブラリの数値をそのまま使っています。 この数値の一覧は、c:\ruby\doc\rubysdl\rubysdl_const_list.txtを見てみてください。 ●課題21A: 配列の使い方returnrequire 'sgl' def setup window -200, -200, 200, 200 background 100 $pos = [] #中身が空の配列を用意します。 for a in 0..10 #配列の要素それぞれについて繰り返します。 $pos[a] = 0 #中身に全部0を入れておきます。 end $index = 0 #現在配列のどこの部分を指しているかを示す変数です。 end def display $pos[$index] = mouseX #配列の$indexの示すところに現在のマウスのx座標を入れます。 for a in 0..10 #配列の要素それぞれについて繰り返します。 x = $pos[a] color 0 line x, -100, x, 100 #縦線を描きます。 end $index = $index + 1 #現在を示す$indexを、次の値のところにセットします。 if 10 < $index #$indexが配列の大きさを越えてしまったら、0にセットしなおします。 $index = 0 end p $pos #この行で、$posという配列の中身がどうなっているかを表示しています。 end mainloop 配列の使い方の基本形です。 縦線が、マウスの動きを追って動きます。つまりマウスのx座標だけを保存しています。 x座標、y座標を保存するとどのようになるでしょうか。 require 'sgl' def setup window -200, -200, 200, 200 background 100 $xpos = [] #中身が空の配列を、x座標、y座標について用意します。 $ypos = [] for a in 0..10 #配列の要素それぞれについて繰り返します。 $xpos[a] = 0 $ypos[a] = 0 end $index = 0 #現在配列のどこの部分を指しているかを示す変数です。 end def display $xpos[$index] = mouseX $ypos[$index] = mouseY for a in 0..10 #配列の要素それぞれについて繰り返します。 x = $xpos[a] y = $ypos[a] color 0 circle x, y, 50 end $index = $index + 1 #現在を示す$indexを、次の値のところにセットします。 if 10 < $index #$indexが配列の大きさを越えてしまったら、0にセットしなおします。 $index = 0 end p $xpos p $ypos end mainloop このように値を保存する配列を増やしていけばよいわけです。 |