h1. 練習問題 11〜21 h2. 課題15 マウスのボタンが押された時に h2. 課題16 円の描き方 h2. 課題18 三次元 h2. 課題19 速度 h2. 課題20 キーボードからの入力 h2. 課題21 配列の使い方 h2. 課題11A マウスの位置に反応する形
require 'sgl' window 200,200 loop do x = mouseX y = mouseY rect x-5, y-5, x+5, y+5 flip endmouseXとmouseYでマウス位置を取得する.rectで四角形を描画する. rectの前に@color x, y, 0@をいれてみる. rectの後に下記をいれてみる.
line 0, 0, x, y line 200, 0, x, y line 0, 200, x, y line 200, 200, x, yh2. 課題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とendObjではさまれた領域で形を描く.
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頂点ごとに透明度も変えられる. h2. 課題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 waitwindowの前にuseSmoothを指定することによって,アンチエイリアスを かけることができる. beginObjの括弧の中は,@POLYGON@または@LINE_LOOP@を指定する. この二つがあればほぼ十分であるが,他に下記方法も指定できる. LINES, POINTS, LINE_STRIP, LINE_LOOP, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN, QUADS, QUAD_STRIP, POLYGON, h2. 課題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を使って回転移動拡大縮小などができ るようになる.pushとpopで囲まれていることが非常に重要である.また襦袢 として,translate, rotateZ, scaleの順番に指定することが重要.形を描く コマンドと,位置,回転角度などの指定を分離できる. h2. 課題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@のように して,あらかじめなんらかの値を代入することで,変数を使うということを示 す必要がある. h2. 課題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マウスを押されないでもついてくるようにする. h2. 課題18A 3D
require '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の物体の移動の例とほとんど同じだが,@translate 30, 40, 20@として 三つの値を指定している点,@rotateZ@だけではなく,@rotateY@ @rotateX@を 使っている点が違う.三つめの値はZ軸,奥行きである.手前が正の値,奥の ほうが負の値となる.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配列の使用と組み合わせてみている. h2. 課題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配列の使い方を変更した. h2. 課題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という 関係になる. それら以外のキーを押したときにどのようなキーコードになるかは, @c:\ruby\doc\rubysdl\rubysdl_const_list.txt@ に記述されている. 数字の0が押されたときは,@SDL::Key::K0@という値となる. h2. 課題21A 配列の使い方return
require '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このように値を保存する配列を増やしていくようにする.