日常英語のようなプログラミング言語で
1行ごとに何をやっているか確認しながらコードを書く Page 05



17: リピート文2 フォーエバー「forever」

注: このページで作るゲームは macOS High Sierra で不具合が出るようです。原因を調べています。
これからポン・ゲーム(PONG)を作ります。もっと効率良くスマートな方法もあかもしれませんが、今まで学んだ基礎的な知識をもう少し発展させた、対戦相手のいない単純なインターラクティブなアニメーションです。このページで作るスタックはこのビデオのようになります。



実際のスタックはメッセージ・ボックスからこのスクリプトを送ってください。これから作るポン・ゲーム(PONG)が試せます。

go stack url "http://kenjikojima.com/livecode/anime/LC__PONG.livecode"

まず前ページではリピートを3回だけ繰り返していたのを、ゲームが終わるまでグラフィックが動くように「forever(永久に)」に変えます。カスタム・コマンド「moveGrc」は、グラフィック1の円の1辺がスタックのエッジにぶつかった時に、次のアクションに移れるように「and」ではなく「or」を使います。これから作るポン・ゲームでは, グラフィック1がエッジにぶつかるポイントは「topLeft」と「bottomRight」だけで良いでしょう。グラフィック1の円はパラメータで設定するピクセル数だけリピートして動くのですが、その都度「wait 10 ticks 10ティックス待つ」では長すぎるので、この行を削除します。

command moveGrc pItem1, pItem2
   repeat forever  -- ゲームセットまでリピートを繰り返す
      set the loc of grc 1 to item 1 of the loc of grc 1 + pItem1, \
            item 2 of the loc of grc 1 + pItem2
      if the topLeft of grc 1 is not within the rect of this cd or \
            the bottomRight of grc 1 is not within the rect of this cd then 
         beep
         send mouseUp to btn "reset"
         exit repeat
      end if
      -- wait 10 ticks この行を削除する
   end repeat
end moveGrc

これまでは向きの違う動きのスクリプトを書いたボタンを作って、それぞれクリックしていましたが、ボタンは必要ないので真ん中の「reset リセット」だけを残して、あとは全て削除してください。マウスを「Pointer Tool」にして、ボタン「reset リセット」以外をセレクトしてデリート・キーを叩けばボタンが削除できます。ボタン「リセット」は後で「ブロック」に変えます。削除したボタンの代わりにグラフィック1の円をスタート・ボタンにします。デフォルトで作ったグラフィックは中が透明なので、クリックできるように不透明にしてください。グラフィック1をセレクトしてインスペクターを開いたら、グラフィックの名前を「ball」にして、「opaque オペーク(不透明)」にチェックします。バージョン7と8ではインスペクターが少し違っています。



メッセージ・ボックスからスクリプトを送って、グラフィック1の名前(name)を「ball」にして、オペーク(opaque)にするのは以下です。

set the name of grc 1 to "ball"
set the opaque of grc 1 to true
  

グラフィック1の名前を「ball」に設定 グラフィック1のオペーク(不透明)を真に設定


グラフィック「ball」のスクリプト・エディターを開くとボタンの時のように「on mouseUp」「end mouseUp」は書かれていません。しかしカードに置かれたオブジェクト(グラフィック、イメージ等)は中に「on mouseUp」「end mouseUp」を書き込めば、マウスアップされた時にそのスクリプトは実行されます。グラフィック「ball」には、もうひとつ「on mouseDown」のハンドラーに「grab me」を書き込んで、ボールをマウスでドラッグできるようにします。「mouseDown」はマウスを下に下ろした時に、中のスクリプトが実行されます。「grab」は英語で「ひっつかむ」という意味で、スクリプトの「grab me」の「me」は書いてあるオブジェクトそのもの、つまりここではグラフィック「ball」を指しています。以下のスクリプトをグラフィック「ball」に書き込みます。

on mouseDown  -- マウスをダウンした直後に ステートメントが実行される
   grab me
end mouseDown

on mouseUp
   moveGrc 2, -2   --1回で移動するピクセル数は X = 2 と Y = −2 にします
end mouseUp



グラフィック「ball」をマウスでドラッグ(グラブ grab)して、どこでもカードの上で放すと、グラフィック「ball」は右上に進んでスタックのエッジにぶつかってカードのセンターに戻ります。これまでを試してうまくいかないようでしたら、カードのスクリプトをもう一度チェックしてください。

グラフィック「ball」に書いたカスタム・コマンド「moveGrc」のパラメータを「2, -2」にしているので、毎回ボールを離した時ボールは右上に進みます。ボールの進む方向はランダムで上下左右選ぶように書き換えますから、グラフィック「ball」に書いたカスタム・コマンド「moveGrc」のパラメータ「2, -2」は削除します。ボールのマウスアップ・ハンドラーのスクリプトは「moveGrc」だけにしてください。

-- グラフィック「ball」の新しいスクリプト
on mouseDown
   grab me
end mouseDown

on mouseUp
   moveGrc  -- 2, -2 パラメータを削除する
end mouseUp

削除したパラメータの代わりに、カードのスクリプト・エディターに移動するピクセル数と、向きを指示するスクリプトを書き込みます。移動するピクセル数はいつも2ピクセルとして、向きはプラスかマイナスで決まるので、「any item」を使ってランダムに「+2」と「-2」が得られるスクリプトを書きます。「any」は幾つかあるカンマで区切られた項目などから、無作為に1つ選び出す時に使われます。 始めに

get (-2, 2) 
  

「it」 に(-2, 2) を取り込む。「put (-2, 2) into it」と同じ結果になる

「get」は「put」と似ていますが、ある値(value)をいつでも「it」に収納します。感覚的には「it」という自分に、取り込むという感じでしょうか。「put」はそれに対して、ある対象物に値を入れる感じです。上に書いた「get (-2, 2) 」では「it」の中身は「-2, 2」になります。この「it」にある2つのアイテム(カンマで繋がれた項目) からどちらかの値をランダム(無作為)に選び出すのに、「any item of it (itに収納されているどちらかの項目)」を使います。「get」で「it」に値(-2,2)を取り込む処から始めから書きます。「it」からランダムに選び出した値は「put」を使って「tX」と「tY」に入れます。

get (-2, 2) 
put any item of it into tX  -- -2 か +2 のどちらかが tX に収納される
put any item of it into tY  -- -2 か +2 のどちらかが tY に収納される

カードに書きこむカスタム・コマンド「moveGrc」の全部を書いてみます。

command moveGrc  -- pItem1, pItem2 パラメータは必要ないので削除する
   get (-2, 2) 
   put any item of it into tX   -- it に収納されているどちらかのアイテムを tX に入れる
   put any item of it into tY   -- it に収納されているどちらかのアイテムを tY に入れる 
   
   repeat forever
      set the loc of grc 1 to item 1 of the loc of grc 1 + tX, \
            item 2 of the loc of grc 1 + tY  -- pItem1, pItem2 は tX とtY に変える
      if the topLeft of grc 1 is not within the rect of this cd or \
            the bottomRight of grc 1 is not within the rect of this cd then 
         beep
         send mouseUp to btn "reset"
         exit repeat
      end if

   end repeat
end moveGrc

これで試してみると、向きの違う動きで進んだボールはスタックのエッジにブツかった時、ボタン「リセット」にマウスアップが送られてボールはカードの真ん中に戻ります。

次にボールがスタックのエッジにブツかった時、跳ね返って進むスクリプトにして行きます。上で書き換えたスクリプトで「tX, tY」は4種類の違う組み合わせが作られます。

2,2  (ボールは右下に進む)
-2,2 (ボールは左下に進む)
2,-2 (ボールは右上に進む)
-2,-2(ボールは左上に進む)

・スタックの右側面(x=width, y=heightのどこか)に「+2, +2」でぶつかったら左下(-2, +2)にして進む
・スタックの底(x=widthのどこか, y=height)に「-2, +2」でぶつかったら左上(-2, -2)にして進む
・スタックの天(x=width のどこか, y=0)に「+2,-2」でぶつかったら 右下(+2, +2)にして進む
・スタックの左側面(x=0, y=heightのどこか)に「-2,-2」でぶつかったら 右上(+2, -2)にして進む

他の組み合わせも考えられますが、とりあえずこの4つで、ボールがエッジにバウンスすることにしましょう。


18: スウィッチ文「switch」で方向を変える

2,2  (ボールは右下に進む) ---> (エッジにバウンスしたら)-2, 2(左下に進む)
-2,2 (ボールは左下に進む) ---> (エッジにバウンスしたら)-2, -2(左上に進む)
2,-2 (ボールは右上に進む) ---> (エッジにバウンスしたら)2, 2(右下に進む)
-2,-2(ボールは左上に進む) ---> (エッジにバウンスしたら)2, -2(右上に進む)

ボールの進む方向は「tX, tY」の値によって、この4種類のバウンスする値に振り分けるスクリプトを「swicth文」で作ります。スイッチ(switch)は、いくつかの可能性のあるバリュー(value)から、該当するものを選ぶ構文です。「switch」は複数の可能性を並列に用意して、「case ケース」を使って、「この場合は」 「この場合は」と上から順にチェックして、該当するバリュー(value)に当たった時、その中 に用意したスクリプト(ステートメント)を実行します。「switch文」の基本構造は以下の通りです。

switch スウィッチする表現
  case 表現が該当する語1(value バリュー)
    語1が該当すれば、実行するステートメント
   break   -- 必ずブレイクを書く
  case 表現が該当する語2(value バリュー)
    語2が該当すれば、実行するステートメント
   break   -- 必ずブレイクを書く
 default  -- その他表現が該当するすべての語(value バリュー)
   デフォルトで実行するステートメント
end switch

「スウィッチする表現」はこの場合「tX,tY」です。「case」はボールが進んでいる時(バウンスする前)の「tX,tY」の値、例えば「2,2」が該当すれば「tX,tY」の値を「-2,2」に入れ替えます。この場合はデフォルトで実行するステートメントはありません。

   switch tX,tY  -- tX,tY に何が入っているか
      case 2,2  -- tX,tY が 2,2 の場合
         put -2 into tX
         put 2 into tY
         break	-- 該当するものが見つかったらswitch から抜ける
      case  -2,2  -- tX,tY が -2,2 の場合
         put -2 into tX
         put -2 into tY
         break	-- 該当するものが見つかったらswitch から抜ける
      case 2,-2  -- tX,tY が 2,-2 の場合
         put 2 into tX
         put 2 into tY
         break	-- 該当するものが見つかったらswitch から抜ける
      case -2,-2  -- tX,tY が -2,-2 の場合
         put 2 into tX
         put -2 into tY
         break	-- 該当するものが見つかったらswitch から抜ける
   end switch
   -- スウィッチを出たところで tX と tY は新しい値になっている

上に書いたカードに書きこむカスタム・コマンド「moveGrc」全文にこの「switch」を書き込みますが、ボールがスタックのエッジにバウンスして方向を変えて、動きが中断されないで更に進んで行くように、「send mouseUp to btn "reset"」と「exit repeat」は削除します。まだこれはテストなので、いつでも「shiftKey シフトキー」を押した時にボールの進行がストップするスクリプトも加えておきます。

command moveGrc 
   get (-2, 2) 
   put any item of it into tX
   put any item of it into tY
   repeat forever
   
      if the shiftKey is down then exit to top
      -- もしシフトキーが押されたら すべてのスクリプトから抜ける(exit to top)
      -- ボールがストップする
      
      set the loc of grc 1 to item 1 of the loc of grc 1 + tX, \
            item 2 of the loc of grc 1 + tY
      if the topLeft of grc 1 is not within the rect of this cd or \
            the bottomRight of grc 1 is not within the rect of this cd then 
         beep
         -- send mouseUp to btn "reset"  削除する
         -- exit repeat  削除する
         
         switch tX,tY
            case 2,2
               put -2 into tX
               put 2 into tY
               break	
            case  -2,2
               put -2 into tX
               put -2 into tY
               break
            case 2,-2
               put 2 into tX
               put 2 into tY
               break      
            case -2,-2
               put 2 into tX
               put -2 into tY
               break
         end switch
         
      end if
   end repeat
end moveGrc



これでグラフィック「ball」をドラッグしてマウスアップして放すと、スタックのエッジで跳ね返ってだいぶらしくなってきました。ストップさせるには「shiftKey シフトキー」を叩きます。


19: ボールをバウンスさせるブロック

ボタン「reset」の名前(Name)を「block」にして、レイベル(Label)は「ブロック」とします。名前(Name)はプログラミング中で使う名前、レイベル(Label)はインターフェイス上に表示されます。レイベル(Label)に何も設定されていなければ、名前(Name)が表示されます。ボタン「block」の中のスクリプトは必要ないので削除しても良いです。このブロックはボタンでなく、他のグラフィックなどのオブジェクトでも良いです。スタックの縦のサイズを少し長めに「height = 450」くらいに伸ばして下さい。



グラフィック「ball ボール」がボタン「ブロック」にぶつかったら、スタックのエッジにぶつかったようにバウンスするスクリプトを追加して行きます。グラフィック「ボール」が下にある「ブロック」にぶつかるのはボールの「bottomRight 」と「bottomLeft」ですから、このどちらかが「the rect of btn "block" ボタン『ブロック』の矩形」の「within 中」にあるかをチェックするスクリプトを、グラフック「ボール」がバウンスする時の条件に「or」でつないで書き加えます(下に書いたスクリプトの赤字の部分を追加します)。

if the topLeft of grc "ball" is not within the rect of this cd or \
    the bottomRight of grc "ball" is not within the rect of this cd or \
    the bottomRight of grc "ball" is within the rect of btn "block" or \
    the bottomLeft of grc "ball" is within the rect of btn "block" then
  beep
  switch tX,tY -- が続く
  	case .....
  	
  end switch
end if

ボタン「block ブロック」を左右に移動させるスクリプトが必要です。マウスが動いた時天地には動かないで、左右だけ動くようにします。「the mouseLoc」でマウスのロケーション(XY座標)を得ることができますから、Y座標はボタン「block ブロック」そのまま、X座標(item 1 of the mouseLoc)だけ移動するようにしました。

set the loc of btn "block" to item 1 of the mouseLoc, item 2 of the loc of btn "block"

ボタン「ブロック」のロケーションを、マウスロックの項目1,ボタン「ブロック」のロケーションの項目2に設定

このスクリプトを「repeat forever」の中の始めの行に書き加えます。もうひとつボールがスタックの一番下に到達した時に、ゲームオーバーになるスクリプトを加えます。ゲームオーバーは、グラフィック「ボール」の動きをストップさせてカードの中央に戻し、ボタン「ブロック」もマウスの動きから外して始めの位置に戻すようにします。グラフィック「ボール」がスタックの底に触れたのを知るにはグラフィック「ボール」の「item 2 of the bottomLeft(または bottomRight)」がカードの高さと同じか越えていれば良いわけです。

if item 2 of the bottomLeft of grc "ball" >= the height of this cd then
   set the loc of btn "block" to  \
	 item 1 of the width of this card div 2, item 2 of the loc of btn "block"
   set the loc of grc "ball" to the loc of this cd
   exit repeat
   

もしボールのボトムレフトの項目2の値(Y値)が このカードの高さと同じか大きければ    ボタン「ブロック」のロケーションを \     (項目1のこのカードの横幅)の2分の1, 項目2のボタン「ブロック」のロケーションに設定    グラフィック「ボール」をこのカードのロケーションに設定    リピートから抜ける

ビープ音を鳴らして「ボール」をストップさせて、「ボール」と「ブロック」を元の位置に戻すスクリプトを書き込みます。

ここまでのカスタム・コマンド「moveGrc」全文を下に書きます。

command moveGrc 
   get (-2, 2) 
   put any item of it into tX
   put any item of it into tY
   repeat forever
      set the loc of btn "block" to \
            item 1 of the mouseLoc, item 2 of the loc of btn "block"
      if the shiftKey is down then exit to top
      set the loc of grc "ball" to item 1 of the loc of grc "ball" + tX, \
            item 2 of the loc of grc "ball" + tY
      if item 2 of the bottomLeft of grc "ball" >= the height of this cd then
         beep
         set the loc of btn "block" to \
               item 1 of the width of this card div 2,  item 2 of the loc of btn "block"
         set the loc of grc "ball" to the loc of this cd
         exit repeat
      else   -- 上にif文を追加したので、次の条件を書き込む前に「else もしくは」を書く
         if the topLeft of grc "ball" is not within the rect of this cd or \
               the bottomRight of grc "ball" is not within the rect of this cd or \
               the bottomRight of grc "ball" is within the rect of btn "block" or \
               the bottomLeft of grc "ball" is within the rect of btn "block" then
            beep
            switch tX,tY
               case 2,2
                  put -2 into tX
                  put 2 into tY
                  break	
               case  -2,2
                  put -2 into tX
                  put -2 into tY
                  break
               case 2,-2
                  put 2 into tX
                  put 2 into tY
                  break      
               case -2,-2
                  put 2 into tX
                  put -2 into tY
                  break
            end switch
          end if 
       end if --「if文」を追加したので最後に「end if」で追加した条件を閉じる
   end repeat
end moveGrc



20: オプション・メニューからボールのスピードを選ぶ

これでほとんど完成ですが、オプション・メニューを付けてボールのスピードを3種類選べるようにします。



ツール・パレットから「Option Menu」をカード右上にドラッグ&ドロップして、セレクトした状態でインスペクターを開きます。「Name」を「ballSpeed」にして「Menu Items」は日本語で「ゆっくり」「少し早く」「もっと早く」の3行で書き込んでください(上図)。

スクリプトで同じボタンを作るには以下です。「cr」は改行の「return」と同じです。

create btn "ballSpeed"
set the style of btn "ballSpeed" to "menu"
set the menuMode of btn "ballspeed" to "option"
set the text of btn "ballSpeed" to "ゆっくり" & cr & "少し早く" & cr & "もっと早く"

これまでボールのスピードは2ピクセルでしたが、作ったボタン・メニューから選んだ値でスピードを変えます。スピードの値は「tSpeed」に収納します。ボタンのレイベル(Label)をif文で調べて、スピードの値(ピクセル数)を「tSpeed」収納します。

command moveGrc 
   if the label of btn "ballSpeed" is "ゆっくり" then 
      put 2 into tSpeed   -- 2ピクセルのスピード
   else if the label of btn "ballSpeed" is "少し早く" then 
      put 6 into tSpeed   -- 6ピクセルのスピード
   else   -- それ以外 3つの選択なので書かなくても"もっと早く"
      put 10 into tSpeed   -- 10ピクセルのスピード
   end if
   get (-tSpeed, tSpeed)   -- 上で取得した値がtSpeedに入っている
   put any item of it into tX
   put any item of it into tY
   repeat forever
      set the loc of btn "block" to \
            item 1 of the mouseLoc, item 2 of the loc of btn "block"
      if the shiftKey is down then exit to top
      set the loc of grc "ball" to item 1 of the loc of grc "ball" + tX, \
            item 2 of the loc of grc "ball" + tY
      if item 2 of the bottomLeft of grc "ball" >= the height of this cd then
         beep
         set the loc of btn "block" to \
               item 1 of the width of this card div 2,  item 2 of the loc of btn "block"
         set the loc of grc "ball" to the loc of this cd
         exit repeat
      else
         if the topLeft of grc "ball" is not within the rect of this cd or \
               the bottomRight of grc "ball" is not within the rect of this cd or \
               the bottomRight of grc "ball" is within the rect of btn "block" or \
               the bottomLeft of grc "ball" is within the rect of btn "block" then
            beep
            switch tX,tY
               case tSpeed,tSpeed   -- どちらもプラスの値
                  put -tSpeed into tX
                  put tSpeed into tY
                  break	
               case  -tSpeed,tSpeed   -- tXがマイナス tYがプラスの値
                  put -tSpeed into tX
                  put -tSpeed into tY
                  break
               case tSpeed,-tSpeed   -- tXがプラス tYがマイナスの値
                  put tSpeed into tX
                  put tSpeed into tY
                  break      
               case -tSpeed,-tSpeed   -- どちらもマイナスの値
                  put tSpeed into tX
                  put -tSpeed into tY
                  break
            end switch
         end if
      end if
   end repeat
end moveGrc

以上がカードに書き込むスクリプトです。

もしうまく動かない時は、メッセージ・ボックスからこのスクリプトを送ってください。実際のスタックがデスクトップにダウンロードされますから、スクリプトを見ることができます。

go stack url "http://kenjikojima.com/livecode/anime/LC__PONG.livecode"





2016年6月15日



役に立ったらドネーションをよろしく。
著者・アーティスト:小島健治

Eメール:index@kenjikojima.com

Page 04
12: リピート文1、ティックス「ticks」
13: ポイントがあるかないかを知るウィズイン「within」
14: if 文「もし何々ならば ... 」
15: ビープを鳴らしてリピートの途中から抜ける
16: 「or」と「and」の違い


21: 未定




ⓒ 小島健治 / Kenji Kojima