2次元アニメーションの基礎(2)

1.ウィンドウ座標の変換

  これまで画面上の座標はピクセル単位で扱ってきたが,科学技術計算等を図示する場合には,一般に用いられているデカルト座標系に置き換えることができれば,より容易に描画が可能となる.
 そこで,VBのピクチャボックス内での座標系を再設定する方法を学ぶ.

1)VBでの座標系の設定

 Form1上にピクチャボックスを配置した場合,初期状態ではTwipという単位(1論理インチ 1440 Twip)という単位で扱われることになる.これまでは,これをよりわかりやすいように,ピクセル単位に変換するという作業を行なってきた.しかし,いずれの方法によってもピクチャボックスの左上隅の点が原点とした,下方向に+,右方向に+という座標系となる.
 一方,デカルト座標系では,上方向に+という座標系であるから,デカルト座標系をもとにした数式を計算する場合に,その座標変換を行う必要がある.
 ピクチャボックスコントロールでは,この座標変換を容易に設定することが可能である.(これは既往のBASICでも同様である)

 例えば,原点(0,0)を中心し,左上隅が(-1,1),右下隅が(1,-1)となる座標系をもつウィンドウを定義するとしよう.

プロパティの変更による方法

1)ピクチャコントロールボックスをForm1上に貼り付ける.
2)ピクチャコントロールボックスの大きさを正方形になるように設定する.
 (プロパティ Picture1.WidthとPicture1.Heightが同じ値になる)
3)以下のようにPicture1のプロパティを修正する.(コード内からの変更も可能である)
    Picture1.ScaleMode = 0
    Picture1.ScaleHeight = -2
    Picture1.ScaleWidth = 2
    Picture1.ScaleTop = 1
    Picture1.ScaleLeft = -1
 これにより原点を中心とする座標系が定義される.

メソッドを用いた方法

1)ピクチャコントロールボックスをForm1上に貼り付ける.
2)ピクチャコントロールボックスの大きさを正方形になるように設定する.
3)以下のコードをプログラム内で呼び出す.
 Picture1.Scale (-1,1)-(1,-1)
 これにより原点を中心とする座標系が定義される.

Scaleメソッド 
Picture1.Scale (左上隅の座標)-(右下隅の座標)
 

 

2)円の描画

例えば,この座標系で円を描画してみよう. (以前にピクセルモードで書いた円のプログラムをそのまま利用できる)

Option Explicit
Const PAI = 3.1415

Private Sub Form_Load()
    Picture1.Width = 3000
    Picture1.Height = 3000
    Picture1.ScaleMode = 0
    Picture1.ScaleHeight = -2
    Picture1.ScaleWidth = 2
    Picture1.ScaleTop = 1
    Picture1.ScaleLeft = -1
End Sub

Private Sub Command1_Click()
    Dim n As Integer
    Dim x As Single, y As Single
   For n = 0 To 360
         x = Cos(n / 180 * PAI)
         y = Sin(n / 180 * PAI)
         If n = 0 Then
            Picture1.PSet (x, y)
         Else
            Picture1.Line -(x, y)
        End If
    Next
End Sub
 

3)多角形の描画

 上述のプログラムの
        For n = 0 To 360 
 の部分に
 例えば,For n = 0 TO 360 Step 60
 などのように,Stepとして設定する数値を90,120等と変えれば,任意の正多角形の描画が可能となる.
 

 2.VBのタイマーコントロール

 タイマーコントロールを用いれば,アニメーションの速度を制御することができることは,前回の資料に記載しているが,ここでは,タイマーコントロールを用いることによって,実行しているプログラムがCPUを独占するということを避けるためのタイマーコントロールの利用について述べる.

 例えば,時計を表示したいという場合に,

   Do
        Text1.Text = Time         'Timeは現在の時間を返す関数である.
   Loop
 
  という処理を行なうと,プログラムは常に動きつづけ,CPUを独占してしまう.
 
 時計は1秒毎に描画が更新されればよいのであるから,ここで1秒毎にプログラムを実行するようにタイマーコントロールを用いる.

1)タイマーコントロールとラベル(Aと表示されたコントロール)をForm1上に貼り付ける.
2)Form1上から

Option Explicit
Private Sub Form_Load()
    Label1.Caption = ""
    Timer1.Interval = 1000
    Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer()
    Label1.Caption = Time  
End Sub

 上記のようにタイマーコントロールを利用したプログラムを実行すれば,1秒毎にプログラムが稼動するため,CPUの独占ということを避けることができる.

 (参考)アラーム機能

 例えばテキストボックスを追加し,以下のようなコードを追加すれば,アラーム機能が追加可能
Private Sub Timer1_Timer()
    Label1.Caption = Time  
    If Time >= Text1.Text Then Beep
End Sub
 

(参考)TIme関数からの時間,分,秒の抽出

       Timeで得られた時間の文字列から,以下のように文字列を抽出することが可能である.
        H = Val( Left$(Time, 2))
        M= Val( Mid$(Time,4,2))
        S = Val( Mid$(Time,7,2))
 
    Val 関数は文字列を数値化する関数
    Left$関数は,文字列の左側から,指定した文字列を抽出する関数
    Mid$関数は,文字列中の指定した位置から,指定した文字数を抽出する関数

 なお,これらの抽出を用いなくとも,VBの標準関数を用いれば,HMSの抽出は容易である.
 
    H = Hour(Now)
    M = Minute(Now)
    S = Second(Now)

 

3.物理的現象のシミュレーション(2次元アニメーション)

シミュレーション(Simulation):
 電子計算機を用い複雑な自然現象や経済現象などについてモデルを作り, 予測結果をはじきだす手法, 模擬実験. (ニューアンカー英和辞典より)

 2次元アニメーションを作成するためには,単位時間あたりにおける物体の移動方向と移動量を数値的に得て,それをシミュレートする必要がある.そのためには,若干の数学的知識や物理に関する知識が必要とならざるを得ない.
 例えば,投げたボールについてアニメーションしてみよう.(ただし空気抵抗は考慮しない)
 時間t に対するボールの変位 y は,落下運動の式をもとにすれば,以下の式により表現される.

    y = vy0t - gt2/2      vy0:y方向への初速度,g:重力加速度(9.8m/s2)
 
  右辺第2項が負となるのは, ボールを上に投げることにより,負の重力加速度が働くからである.

 一方,x方向への変位は,
  x =vx0t            vx0:x方向への初速度

 さらに投げたボールが再び地面に達したときには,そこで衝突による力の減衰が働くから,ここで初速度を再設定するとともに,再びtの値を初期化して計算を行う必要がある.
 これらを実際にプログラミングすると以下のようになる.

Option Explicit

Dim t As Single, x0 As Single, y0 As Single, vx0 As Single, vy0 As Single, reduce As Single
Const g = 9.8  '重力加速度の設定

Private Sub Form_Load()
    Picture1.AutoRedraw = True
    Picture1.BackColor = &HFFFFFF
    Picture1.ScaleMode = 0
    Picture1.Width = 6000
    Picture1.Height = 3000
    Picture1.ScaleWidth = 200
    Picture1.ScaleHeight = -100
    Picture1.ScaleTop = 98
    Picture1.ScaleLeft = -50
    Timer1.Enabled = False
    Timer1.Interval = 100
    x0 = -50  'ホールの初期位置(X方向)
    y0 = 0  'ボールの初期位置(y方向)
    reduce = 0.7  '衝突時の速度減衰率
End Sub

Private Sub Command1_Click()
    If Timer1.Enabled = True Then
        Timer1.Enabled = False
    Else
        t = 0      '時間の初期化
        vx0 = 10    'x方向初速度(m/s)
        vy0 = 40    'y方向初速度(m/s)
        Timer1.Enabled = True
    End If
End Sub

Private Sub Timer1_Timer()
    Dim x  As Single, y As Single
    x = vx0 * t + x0       'x方向の位置計算
    y = vy0 * t - g * t ^ 2 / 2   'y方向の位置計算
 
    Picture1.Cls 
    Picture1.FillStyle = 0
    Picture1.FillColor = &HFF
    Picture1.Circle (x, y), 2, &HFF
 
    If t > Timer1.Interval / 1000 And y <= 0 Then   '地面に達したら
        t = 0                       '時間を初期化
        x0 = x                      '現在の位置を初期位置に再設定
        y0 = y
        vy0 = vy0 * reduce           '速度の減衰を行なう.
        vx0 = vx0 * reduce
    End If
    t = t + Timer1.Interval / 1000  '次の計算時間tを計算
End Sub