• 課題15: マウスのボタンが押された時に
  • 課題16: 円の描き方
  • 課題18: 三次元
  • 課題19: 速度
  • 課題20: キーボードからの入力
  • 課題21: 配列の使い方

●課題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

など試してみてください。

●課題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
このように頂点ごとに、透明度も変えられます。

●課題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です。
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: 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のところでだした物体の移動の例とほとんど同じです。 つまり実はあの課題はほとんど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: 配列の使い方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

このように値を保存する配列を増やしていけばよいわけです。