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
end
mouseXと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, y
h2. 課題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

wait
windowの前に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
このように値を保存する配列を増やしていくようにする.