プログラミングの備忘録

プログラムをつくる過程を残すもの

なでしこの備忘録 -物体の運動・グループ-

こんにちは。
今回も「なでしこ」に触れてみます。
なでしこでもprocessingのようなウィンドウが表示されるので、お絵かきにも使えます。
ということで、円を動かすということをやってみたいと思います。


マウスの位置に円を描く

まずは円を描いてみます。

100,100から200,200へ円を描く

円の座標指定は、その円が内接する四角の左上の座標と右下の座標で指定します。

マウスポインタの位置に描かれるようにしてみます。(割と苦戦しました・・・)

オンの間
    xyは母艦ハンドルの0,0を窓ハンドル画面座標計算
    xは机上マウスX - (xyから「,」まで切り取る)
    yは机上マウスY - xy
    rは10
    
    x-r,y-rからx+r,y+rへ円を描く

    0.01秒待つ

中身を見てみます。
「オンの間」と「0.01秒待つ」で無限ループするようにしています。「オンの間」は「1の間」や「1でループ」なども使えるようです。また「0.01秒待つ」がないと次の処理までの時間が無さ過ぎて描画されません。(描画しているのかもしれませんが速すぎて見えない)
「xyは母艦ハンドルの0,0を窓ハンドル画面座標計算」は少々ややこしいですが、「xy」という変数に「母艦ハンドル」の座標(0,0)(左上)の位置のパソコン画面上での座標を「窓ハンドル画面座標計算」で得て代入しています。「母艦ハンドル」はなでしこのコードを実行すると表示されるウィンドウのことです。
「窓ハンドル画面座標計算」は(x,y)の形で返されるので、「xyから「,」まで切り取る」の処理で「,」の手前までの数字(つまりx)を得ています。「切り取る」の処理の後は残りの部分のみが代入された状態(つまりyのみ)になっているので、そのまま数字として使えます。
「机上マウスX,Y」はパソコン画面上の座標を返すため、母艦の位置を得て、その分引かないとうまく表示できません。
円を描く部分では、円の中心にマウスポインターが来るように、「r」(半径)を定義して「x-r,y-rからx+r,y+rへ」と調整して円を描いています。

しかし、これだとその前の処理で描いた円が残ったままなので、画面を一旦消す処理を加えます。(processingでいうところの「background(255);」)
「オンの間」の下に、インデントを入れて以下の処理を追加するだけです。

画面クリア

これでマウスポインタの位置だけに円が描かれるようになりました。


円を等速直線運動させる

さて、ここまでのことは一旦忘れて、円が等速直線運動をして壁に当たったら跳ね返るというようなプログラムをつくってみます。

まずは円を動かします。

xyは母艦ハンドルの0,0を窓ハンドル画面座標計算
xは200 - (xyから「,」まで切り取る)
yは200 - xy
rは10
vxは3
vyは1

オンの間
    画面クリア
    
    x = x + vx
    y = y + vy
    
    x-r,y-rからx+r,y+rへ円を描く

    0.01秒待つ

速さvxとvyを決めて、繰り返すたびにxとyにそれぞれ足していくことで、等速直線運動をさせます。

では、壁の処理を追加します。

母艦のWは600 #WはWidth(横幅)
母艦のHは600 #HはHeight(高さ)

xyは母艦ハンドルの0,0を窓ハンドル画面座標計算
xは200 - (xyから「,」まで切り取る)
yは200 - xy
rは10
vxは3
vyは1

オンの間
    画面クリア
    
    塗り色は白色
    0,0から500,500へ四角を描く
    
    x = x + vx
    y = y + vy  
    
    塗り色は黒色
    x-r,y-rからx+r,y+rへ円を描く
    
    もしxが500-r以上ならば
        xは500-r
        vx = vx * -1
    もしyが500-r以上ならば
        yxは500-r
        vy = vy * -1
    もしxがr以下ならば
        xはr
        vx = vx * -1
    もしyがr以下ならば
        yはr
        vy = vy * -1

    0.01秒待つ

母艦の大きさを壁ぴったりにするとなぜかはみ出るので、若干大きく設定しています。

これで、動く円を描画できました。
結局vxとかvyとかアルファベットが入ってきてしまって、日本語でつくれる利点を生かし切れていないような気もしますが・・・


グループの追加

なでしこにもprocessingでいうところの「クラス」があり、なでしこでは「グループ」と呼ばれます。

早速つくってみます。(以降のコードを書くにあたって、グループに関する記述が少なくて苦戦しました。動きはするので間違いでは無いと思いますが・・・)

母艦のWは600
母艦のHは600

丸で初期化する

オンの間
    画面クリア
    
    塗り色は白色
    0,0から500,500へ四角を描く
    
    丸で運動する
    丸で表示する
    丸で反射する

    0.01秒待つ

■丸
    ・初期化する~
        xyは母艦ハンドルの0,0を窓ハンドル画面座標計算
        xは200-(xyから「,」まで切り取る)
        yは200-xy
        rは10
        vxは5の乱数
        vyは5の乱数
    
    ・運動する~
        x = x + vx
        y = y + vy
        
    ・表示する~
        塗り色は黒色
        x-r,y-rからx+r,y+rへ円を描く
    
    ・反射する~
        もしxが500-r以上ならば
            xは500-r
            vx = vx * -1
        もしyが500-r以上ならば
            yxは500-r
            vy = vy * -1
        もしxがr以下ならば
            xはr
            vx = vx * -1
        もしyがr以下ならば
            yはr
            vy = vy * -1

グループ名を「■」で決めて、それ以下で要素(「メンバ」と呼ぶ)を「・」で羅列していく形です。
関数は「・(関数名)~(処理)」の形で書きます。 グループ内に移せたら、それぞれの処理があった位置に「(グループ名)で(関数名)する」と呼び出してやります。

では、せっかくグループに入れたので、丸を複数表示できるようにしてみます。
とりあえず、2つ表示できるようにします。

母艦のWは600
母艦のHは600
 
丸aとは丸
丸aのxは200-(xyから「,」まで切り取る)
丸aのyは200-xy
丸aのrは10
丸aのvxは5の乱数
丸aのvyは5の乱数

丸bとは丸
丸bのxは400-(xyから「,」まで切り取る)
丸bのyは400-xy
丸bのrは20
丸bのvxは5の乱数
丸bのvyは5の乱数

xyは母艦ハンドルの0,0を窓ハンドル画面座標計算

オンの間
    画面クリア
    
    塗り色は白色
    0,0から500,500へ四角を描く
    
    丸aが運動する
    丸aが表示する
    丸aが反射する
    
    丸bが運動する
    丸bが表示する
    丸bが反射する

    0.01秒待つ

■丸
    ・x
    ・y
    ・r
    ・vx
    ・vy
    
    ・運動~
        x = x + vx
        y = y + vy
        
    ・表示~
        塗り色は黒色
        x-r,y-rからx+r,y+rへ円を描く
    
    ・反射~
        もしxが500-r以上ならば
            xは500-r
            vx = vx * -1
        もしyが500-r以上ならば
            yxは500-r
            vy = vy * -1
        もしxがr以下ならば
            xはr
            vx = vx * -1
        もしyがr以下ならば
            yはr
            vy = vy * -1

「丸a」と「丸b」をそれぞれ設定して、表示しています。
「丸a」に関する記述を例にして説明します。
「丸aとは丸」で「丸a」が丸グループに属することをいいます。
「丸aの~」でグループでメンバにした変数それぞれの値を定義します。共通するもの(xy)についてはグループから出し、繰り返しの手前で実行するようにしました。
そして、繰り返し内の「丸aが~」でグループ内の関数を呼び出して処理しています。

ただ、これだと数が増えるにつれてコードも倍々に増えていってしまい煩雑になってしまうので、改良すべきです。
が、やり方がわからず。配列を使うのかと思いなんとかやってみたのですができませんでした。


追記(2021/11/24)
なでしこでゲーム作る話 #5 配列にグループを入れて使う - なでしこを明後日の方向に」を見ると、配列とグループが絡むときは「→」を使うらしいということがわかったのでやってみると、一応動きました。

母艦のWは600
母艦のHは600

丸配列とは配列

nを0から5まで繰り返す
    丸配列[n]を丸として作成
    丸配列[n]→xは200-(xyから「,」まで切り取る)
    丸配列[n]→yは200-xy
    丸配列[n]→rは10
    丸配列[n]→vxは5の乱数
    丸配列[n]→vyは5の乱数

xyは母艦ハンドルの0,0を窓ハンドル画面座標計算

オンの間
    画面クリア
    
    塗り色は白色
    0,0から500,500へ四角を描く
    
    nを0から5まで繰り返す  
        丸配列[n]→運動する
        丸配列[n]→表示する
        丸配列[n]→反射する

    0.01秒待つ

■丸
    ・x
    ・y
    ・r
    ・vx
    ・vy
    
    ・運動~
        x = x + vx
        y = y + vy
        
    ・表示~
        塗り色は黒色
        x-r,y-rからx+r,y+rへ円を描く
    
    ・反射~
        もしxが500-r以上ならば
            xは500-r
            vx = vx * -1
        もしyが500-r以上ならば
            yxは500-r
            vy = vy * -1
        もしxがr以下ならば
            xはr
            vx = vx * -1
        もしyがr以下ならば
            yはr
            vy = vy * -1

コードはあまり変わっていません。
「丸配列とは配列」で「丸配列」という配列をつくり、「丸配列[n]を丸として作成」で丸グループに所属することを言っています。
あとは丸配列[n]についてこれまでと同様にx,yなどを指定していくのですが、「丸配列[n]のxは200」ではだめで、「丸配列[n]→xは200」のように「→」で変数を指定しないとエラーが出てしまいます。
関数を呼び出すときも同様で、「丸配列[n]で運動する」や「丸配列[n]が運動する」ではだめで、「丸配列[n]→運動する」のようにしないとエラーが出ます。
(ちなみに、配列を用いずに丸aなどと指定したときに「丸a→xは200」ように「→」でつないでも普通に動きました) 「nを0から5まで繰り返す」だと0,1,2,3,4,5の6つの丸ができることになります。
以上


というわけで、今回はなでしこで丸い物体を等速直線運動させることと、他の言語の「クラス」にあたる「グループ」というものを導入することの2点についていろいろ書いてみました。
それでは、また次回。