SSブログ

【Macでゲームを作ろう】ブロック崩しを作っていく第3回 [AppleScript辞書はつくれるか?]

今回は、ブロックを崩していくボールを動かします。

 

今回新しく紹介するのは

    class "NSTimer"

です。

 

 

まずは前準備として、球の画像を用意します。

 tama.png

 

その球の画像を、Xcodeのプロジェクトに登録します。

ss8-1.png

それから、XIBのウインドウビューの上に 画像を表示させる image WellとPush Button を設置します。


ss8-3.png ss8-2.png

 

  ss8-4.png

※今回はImage Wellを使いましたが、本当はImage View をつかいます。今回は、表示される枠を使って説明する部分がありまして使用しています。


Image Well (Image View) には画像が登録されていませんので、先ほどプロジェクトに読み込んだ tama.png を登録しましょう。

ss8-5.png


イメージビューオブジェクトを選択して、右上のメニューAttributes inspecter を選び、

Image Viweグループ内のImage:に tama と入力。(tama.pngとしなくても、プロジェクト内に登録されたものは読み込むみたいですね)

これで画像が表示されます。


アプリケーション本体のDeregateと各オブジェクトを接続します。

AppDeregate.applescriptに下記のコードを入力します

 

  property view1 : missing value  

  property image1 : missing value  

 

  on action1_(sender)

—-(* ここは後で入力します *)

  end action1_

 

image1は Image Well と

action1_ はボタンと

そして、view1はNSViewオブジェクトと接続します。

ss8-8.png

 

NSViewオブジェクトって? そんなの設置してないよ?と思うでしょうが、これはウインドウに最初から用意されているものです。

ウインドウ(NSWindow)に他のオブジェクトを設置したり表示したりするための地盤の役目をするものがNSViewです。

基本的なものなので、意識して用意しなくても最初からセットとして準備してくれています。今回は情報のコントロールするために接続します。

 

では、球を移動するためのコードを入力しましょう。


    global viewX,viewY, tamaX,tamaY, moveX,moveY

 

    on applicationWillFinishLaunching_(aNotification)

        set {moveX,moveY} to {10,10}

    end applicationWillFinishLaunching_

 

      on action1_(sender)

        set origin1 to view1's frame()'s |size|

        set {viewX,viewY} to {origin1's width, origin1's height}

        set origin2 to image1's frame()'s origin

        set {tamaX,tamaY} to {origin2's x, origin2's y}

  my moveBall()

    end action1_

 

    on moveBall()

        set {tamaX,tamaY} to {tamaX + moveX, tamaY + moveY}

        if (tamaX < 0) or (tamaX > (viewX - 0)) then set moveX to 0 - moveX

        if (tamaY < 0) or (tamaY > (viewY - 0)) then set moveY to 0 - moveY

        set BollPosition to {x:tamaX, y:tamaY}

        image1's setFrameOrigin_(BollPosition)  

    end moveBall  

 

最初はglobal命令でハンドラをまたいだ変数データのやり取りができるようにします。


次にapplicationWillFinishLaunching_という、ウインドウが開かれたら実行されるアクションハンドラを使って、球の移動量を設定しています


origin1にベースとなるview1のサイズを取得し、数値をviewX,viewYに入れています。

origin2に球のimage1の原点位置を取得し、数値をtamaX,tamaYに入れています。

その後、実際の移動をさせるためのコードをmoveBallハンドラで処理させる命令をだしています。


新しく作られたハンドラmoveBall内で、球の位置に移動量を加算しています。

次に球の位置がベースとなるview1からはみ出す位置になったら、反対に戻る移動するように移動量を変更しています。

最後に、球の新しい位置をImage Wellに送っています。


ここまでで、実行すると、ボタンをクリックするごとに球の画像が移動していきます。


でも、ゲームでの球の移動は、ユーザーがクリックされたら移動しなさい。というものではないですよね?

勝手に自動で動くものでなければいけないはずです。


移動するために繰り返しmoveBallハンドラが実行されなければいけないはずです。

では、action1ハンドラ内に繰り返すためのリピート文(repeat)を入れれば良いのでしょうか?

それは間違いです。たしかに repeat をつかえば移動はしますが、その中で繰り返してしまうため他の命令を受け付けなくなってしまいます。

ですから、繰り返すのではなく、『一定の時間毎に命令を実行させる』コードを使用します。

それは、NSTimerというクラスのコードになります。


○ NSTimerを使うための初期準備

    property NSTimer : class "NSTimer"


○ 開始するためのコード

NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(|繰り返す間隔|, |対象となるスクリプト名|, "ハンドラ名", |ハンドラに最初だけ渡す値|, |繰り返し実行するかの許可|)


○ 終了するために使うコード

invalidate()

 

があります。

 

    property NSTimer : class "NSTimer"

    global TimerObj

    global flg


    on applicationWillFinishLaunching_(aNotification)

        set {moveX,moveY} to {10,10}

        set flg to false

    end applicationWillFinishLaunching_


    on action1_(sender)

      if flg is false then

        set origin1 to view1's frame()'s |size|

        set {viewX,viewY} to {origin1's width, origin1's height}

        set origin2 to image1's frame()'s origin

        set {tamaX,tamaY} to {origin2's x, origin2's y}

  --my moveBall()

        my timerStart()

        set flg to true

      else

        try

          tell TimerObj to invalidate()

        end try

        set flg to false

      end if

    end action1_


    on timerStart()

        try

            set TimerObj to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.01, me, "mainLoop", missing value, true)

        on error

            set TimerObj to missing value

        end try

    end timerStart


    on mainLoop()

        my moveBall()

    end mainLoop


  NSTimerを実行するためのオブジェクトをTimerObjに収めてコントロールしています。

TimerStart()ハンドラで、タイマーオブジェクトを作って開始しています。

|対象となるスクリプト名|は、このスクリプト自身なので"me"にします。

タイマーが有効な間実行する部分の"ハンドラ名"は、"mainLoop"にして、ハンドラを別に作っています。

タイマーを停止するには、tell TimerObj to invalidate() で停止します。

 

タイマーをスタートする時、または停止する時に try を使っていますが、何かの不具合があった場合の予防策ですので、入力しておいたほうが無難だと思います。

(細かいところを説明するのめんどくさくなった。)

 

ここまでで、動くだけは動くと思います。

ss8-9.png

次回は、動き方の不具合について書いていきます。




ここまでのコード全体
(*ここから*)

 


script AppDelegate


property parent : class "NSObject"


 


    property NSTimer : class "NSTimer"


    global TimerObj


    global flg


 


    property view1 : missing value


    property image1 : missing value


 


    --property Button1 : missing value


    global viewX,viewY, tamaX,tamaY, moveX,moveY


    global flg


 


    on action1_(sender)


    if flg is false then


        set origin1 to view1's frame()'s |size|


        set {viewX,viewY} to {origin1's width, origin1's height}


        set origin2 to image1's frame()'s origin


        set {tamaX,tamaY} to {origin2's x, origin2's y}


        --my moveBall()


        my timerStart()


        set flg to true


        else


        try


            tell TimerObj to invalidate()


        end try


        set flg to false


    end if


    end action1_


 


    on timerStart()


    try


        set TimerObj to NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.01, me, "mainLoop", missing value, true)


        on error


        set TimerObj to missing value


    end try


    end timerStart


 


    on mainLoop()


        my moveBall()


    end mainLoop


 


    on moveBall()


        set {tamaX,tamaY} to {tamaX + moveX, tamaY + moveY}


        if (tamaX < 0) or (tamaX > (viewX - 0)) then set moveX to 0 - moveX


        if (tamaY < 0) or (tamaY > (viewY - 0)) then set moveY to 0 - moveY


        set BollPosition to {x:tamaX, y:tamaY}


        image1's setFrameOrigin_(BollPosition)


    end moveBall


 


-- IBOutlets


property theWindow : missing value



    on applicationWillFinishLaunching_(aNotification)


        set {moveX,moveY} to {10,10}


        set flg to false


    end applicationWillFinishLaunching_


    on applicationShouldTerminateAfterLastWindowClosed_(sender)


        return true


    end applicationShouldTerminateAfterLastWindowClosed_


on applicationShouldTerminate_(sender)


return current application's NSTerminateNow


end applicationShouldTerminate_



end script

 

(*ここまで*)


nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。