SSブログ

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

そでは今回は最後の、ブロックを積んで崩して行きましょう。


今回新しく出てくるコードは、


  NSMakeRect

  initWithFrame_

  addSubview

  removeFromSuperview


です。


ブロック崩しといえば、たくさんのブロックが配置されていてそれをボールで崩していくものですよね?

ss12-0.png


じゃぁ、そのブロックを一つ一つ並べていく作業からして行くのだろうな。


・・・なんて考えていないでしょうね?


いままでは、一つ二つおいて、好きな位置へ画像へと変更して行きましたが、それが数十個、数百個と増えていったらやり切れると思いますか?

できませんよね?

そこは、まぁ、目の前にあるのはコンピューターですよ。自動で並べることをやらせましょう。


まず、ブロックを配置していくベースを作ります。

今あるView1(NSView)の上にView2(サブView)を写真の位置になるように重ねて配置します。

ss12-4.png

そのサブViewをコントロールするためのコードを書き、


    property view2 : missing value


つないでいきましょう。

ss12-2.png

次に、そのサブViewの上にブロックを並べて行きましょう。


今回も(ダサい)ブロックを5個用意しました。


block01.pngblock02.pngblock03.pngblock04.pngblock05.png


これを横に6つ、縦に4つ並べて行きます。

 

 set ImageItem to thisApp's NSImageView's alloc()'s initWithFrame_(thisApp's NSMakeRect(blockX, blockY, blockSizeW, blockSizeH))


これで新しいImageViewの新しく構築して、


 ImageItem's setEditable_(false)

  ImageItem's setImageFrameStyle_(0)

 ImageItem's setImageAlignment_(0)

 ImageItem's setImageScaling_(1)

 set imageItemName to "block01.png"

 set aImage to NSImage's imageNamed_(imageItemName)

 ImageItem's setImage_(aImage)

各種設定を行い


  view2's addSubview_(ImageItem)

で設置します。


ちなみに上の

● setEditable

これは使えるようにするか否かの設定で、(設定しなくても)通常は『使えないことなない(false)』つまり『使える』状態になってます。使えないにすると半透明になってしまうので、その回避用。なんらかの仕様変更がこわいので設定しておきます。


setImageFrameStyle

はImageViewのフレームの仕様です。

  NSImageFrameNone フレーム無し (= 0)

  NSImageFramePhoto 細い線で細い影付き (= 1)

  NSImageFrameGrayBezel ベゼル付き (= 2)

  NSImageGroove 溝付き (= 3)

  NSImageFrameButton ボタンのようなべベル付き (= 4)

通常は、NSImageFrameNoneです。なにか、コードを入れてもうまくいかないので、後ろのインデックス番号を使用しています。


setImageAlignment

ImageViewの中でどの位置に寄せるのかを設定しています。

  NSImageAlignCenter 中心寄せ (=0)

  NSImageAlignTop 上寄せ (=1)

  NSImageAlignTopLeft2 左上寄せ (=2)

  NSImageAlignTopRight 右上寄せ (=3)

  NSImageAlignLeft 左寄せ (=4)

  NSImageAlignBottom 下寄せ (=5)

  NSImageAlignBottomLeft 左下寄せ (=6)

  NSImageAlignBottomRight 右下寄せ (=7)

  NSImageAlignRight  右寄せ (=8)

通常はNSImageAlignCenterです。


setImageScaling

  NSScaleProportionally 縦横比を維持してNSImageViewに合わせます (=0)

  NSScaleToFit NSImageViewに比率は無視して縦横合わせる (=1)

  NSScaleNone 拡大縮小せずそのまま (=2)

通常は、NSScaleProportionallyです。

 ちなみに、ここにはめ込む画像は、解像度(72dpiや300dpi)などにも大きく影響されるので画像を保存する際は72dpi等に統一しておいたほうが良いでしょうね。


そして最後に、ここまで構築していったイメージ情報をサブView貼り付けます。


  view2's addSubview_(ImageItem)


これをブロック全てに繰り返し行えば良いのです。

ハンドラにしておけば結構楽ですよ。


さて、疑問になるのは何故サブViewを使って配置したのかです。

ただの差別化したかったから?

いいえ、ちゃんとした意味があります。ちなみに、サブViewを使わずに直接今あるメインのViewに出力した例を見てみましょう。

ss12-err1.png


どうでしょう?

新しく作られたオブジェクト(つまりここではブロックたち)が全ての前面に来てみっともない配置になってしまいます。

それを回避するために、いろいろ考えずに新しいサブViewの上に配置していこうと思ったわけです。

そして、サブViewの配置するときにも特に注意して配置していたわけですが、

ss12-5.png


のように、上なら背面、下に行けば行くほど前面に出てくるというのが仕組みです。


さて次は、ブロックの当たり判定のコードをちょちょいっと入力します。

先ほどのブロックを表示したままでは、どこにあるのか?どうやって消したら良いのかに困ってしまいます。

ブロックを配置する際に、その情報をデータベース化?します。

  set blockObject to blockObject & {ImageItem}

  set blockPosition to blockPosition & {{blockX, blockY, blockSizeW, blockSizeH}}

この情報を使って、次から当たり判定やブロックの消去を行います。


 set {tamaCenterX, tamaCenterY} to {tamaX + tamaW, tamaY + tamaH}

 repeat with i from 1 to (count of blockPosition)

  set {block_x,block_y,block_w,block_h} to item i of blockPosition

  set {block_w,block_h} to {block_w + block_x,block_h + block_y}

  if (block_x < tamaCenterX) and (block_w > tamaCenterX) then

    if (block_y < tamaCenterY) and (block_H > tamaCenterY) then

      set moveY to 0 - moveY

      tell item i of blockObject to removeFromSuperview()

      set item i of blockPosition to {0,0,0,0}

    end if

  end if

 end repeat

 

これで判定のあったブロックのImageViewオブジェクトの存在を消し、

判定のために使った座標を、反応しない座標に変更しています。

全てのブロックが消えたかどうかの判定のために、ブロックが配置された直後に

 

set blockCount to count of blockObject


として数を覚えておき、

消えた際にカウンドをダウンしておきます。

それがゼロになったらクリアという判定も入れておきましょう。


 if blockCount is 1 then

  --|Clear !|

  tell TimerObj to invalidate()

  set blockObject to {}

  set blockPosition to {}

  textLabel1's setStringValue_("Clear !")

  set flg to false

  NSCursor's unhide()

 else

  set blockCount to blockCount - 1

  exit repeat

 end if

 

(判定が1だったら終わりになっていますが、すぐ次にカウンドがダウンしたら0になるでしょ?という意味で使用しています。) 


あとここまで説明していませんが、恒例の

  global blockSizeW, blockSizeH

  global blockObject, blockPosition, blockCount

グローバル設定もお忘れなく


しかしこのままでは、画面が同じ色のブロックが並ぶだけですよね?

そして、ここからの広がりのために最初のステージというハンドラを作りますか。(いくつか重複してますが)


    on stage01()

        set blockObject to {}

        set blockPosition to {}

        set {blockSizeW, blockSizeH} to {80, 20}

        set stageText to             "332533" & return

        set stageText to stageText & "343313" & return

        set stageText to stageText & "313343" & return

        set stageText to stageText & "335233"

        repeat with y from 1 to (count of (every paragraph of stageText))

            set oneLine to paragraph y of stageText

            repeat with x from 1 to (count of oneLine)

                set b_x to ((x - 1) * blockSizeW)

                set b_Y to ((y - 1) * (blockSizeH + 10)) + 200

                set blockColor to character x of oneLine

                my blockMakeing(b_x, b_Y, blockSizeW, blockSizeH ,blockColor)

            end repeat

        end repeat

        set blockCount to count of blockObject

    end stage01


    on blockMakeing(blockX, blockY, blockSizeW, blockSizeH, blockColor)

        set ImageItem to thisApp's NSImageView's alloc()'s initWithFrame_(thisApp's NSMakeRect(blockX, blockY, blockSizeW, blockSizeH))

        ImageItem's setEditable_(false)

        ImageItem's setImageFrameStyle_(0)

        ImageItem's setImageAlignment_(0)

        ImageItem's setImageScaling_(1)

        set imageItemName to "block0" & blockColor & ".png"

        set aImage to NSImage's imageNamed_(imageItemName)

        ImageItem's setImage_(aImage)

        view2's addSubview_(ImageItem)

 

        set blockObject to blockObject & {ImageItem}

        set blockPosition to blockPosition & {{blockX, blockY, blockSizeW, blockSizeH}}

    end blockMakeing


ちくっと、新しいハンドラを作って対応してみました。

ちょっと大雑把になってしまいましたが、必要となる部品の話はできたと思います。


最後に、全体のスクリプトを置いておきます。


これで、今回のブロック崩しを作ってみようは終わりになります。

2ヶ月もかけてしまいましたが、お付き合いありがとうございました。

 

 

 

 




 


script AppDelegate

    property parent : class "NSObject"


    property NSTimer : class "NSTimer"

    global TimerObj

    global flg


    property NSEvent : current application's class "NSEvent"

    property view1 : missing value

    property image1 : missing value

    property image2 : missing value

 

    property textLabel1 : missing value

    property Button1 : missing value

 

    property NSImage : class "NSImage"

    property thisApp : current application

    property view2 : missing value

    global blockSizeW, blockSizeH

    global blockObject, blockPosition, blockCount

 

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

    global tamaW,tamaH, tamaSizeX,tamaSizeY

    global flg

    global padX,padY, padW, padH, padSizeX,padSizeY

    global mouse0

    global tamaReset

 

    property NSCursor : class "NSCursor"

 

    on action1_(sender)

        if flg is false then

            (* NSViewの範囲 *)

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

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

 

            (* tamaの情報をリセット *)

            set {moveX,moveY} to {5,5}

            set {tamaX,tamaY} to tamaReset

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

            image1's setFrameOrigin_(BollPosition)

 

            (* Padの情報取得 *)

            set {padSizeX, padSizeY} to {100, 24}

            set {padSizeX, padSizeY} to {(padSizeX / 2), (padSizeY / 2)}

            set origin3 to image2's frame()'s origin

            set {padX,padY} to {origin3's x, origin3's y}

            set size3 to image2's frame()'s |size|

            set {padW, padH} to  {size3's width, size3's height}

            set {padW, padH} to {(padW / 2), (padH / 2)}

 

            (* 現在のマウスの位置を取得 *)

            set {mouseX,mouseY} to my mousePosition()

            set mouse0 to mouseX

 

            my timerStart()

            set flg to true

            button1's setAlphaValue_(0.0)

            textLabel1's setStringValue_("")

            NSCursor's hide()

        end if

    end action1_

 

    on stage01()

        set blockObject to {}

        set blockPosition to {}

        set {blockSizeW, blockSizeH} to {80, 20}

        set stageText to             "332533" & return

        set stageText to stageText & "343313" & return

        set stageText to stageText & "313343" & return

        set stageText to stageText & "335233"

        repeat with y from 1 to (count of (every paragraph of stageText))

            set oneLine to paragraph y of stageText

            repeat with x from 1 to (count of oneLine)

                set b_x to ((x - 1) * blockSizeW)

                set b_Y to ((y - 1) * (blockSizeH + 10)) + 200

                set blockColor to character x of oneLine

                my blockMakeing(b_x, b_Y, blockSizeW, blockSizeH ,blockColor)

            end repeat

        end repeat

        set blockCount to count of blockObject

    end stage01

 

    on blockMakeing(blockX, blockY, blockSizeW, blockSizeH, blockColor)

        set ImageItem to thisApp's NSImageView's alloc()'s initWithFrame_(thisApp's NSMakeRect(blockX, blockY, blockSizeW, blockSizeH))

        ImageItem's setEditable_(false)

        ImageItem's setImageFrameStyle_(0)

        ImageItem's setImageAlignment_(0)

        ImageItem's setImageScaling_(1)

        set imageItemName to "block0" & blockColor & ".png"

        set aImage to NSImage's imageNamed_(imageItemName)

        ImageItem's setImage_(aImage)

        view2's addSubview_(ImageItem)

 

        set blockObject to blockObject & {ImageItem}

        set blockPosition to blockPosition & {{blockX, blockY, blockSizeW, blockSizeH}}

    end blockMakeing

 

    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()

        my movePad()

    end mainLoop

 

    on abs(n)

        return (n ^ 2) ^ 0.5

    end abs

 

    on moveBall()

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

        set {tamaCenterX, tamaCenterY} to {tamaX + tamaW, tamaY + tamaH}

        set {Xposition1, Yposition1} to {(tamaCenterX - tamaSizeX), (tamaCenterY - tamaSizeY)}

        set {Xposition2, Yposition2} to {(tamaCenterX + tamaSizeX), (tamaCenterY + tamaSizeY)}

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

        if Yposition2 > viewY then set moveY to 0 - moveY

        if Yposition1 < 0 then

            tell TimerObj to invalidate()

            textLabel1's setStringValue_("Game Over !")

            set flg to false

            button1's setAlphaValue_(1.0)

            NSCursor's unhide()

        end if

        set decisionX to my abs((padX + padSizeX) - tamaCenterX)

        set decisionY to my abs((padY + padSizeY) - (tamaCenterY - tamaSizeY))

        if (decisionX < padSizeX) and (decisionY < padSizeY) then set moveY to my abs(moveY)

        repeat with i from 1 to (count of blockPosition)

            set {block_x,block_y,block_w,block_h} to item i of blockPosition

            set {block_w,block_h} to {block_w + block_x,block_h + block_y}

            if (block_x < tamaCenterX) and (block_w > tamaCenterX) then

               if (block_y < tamaCenterY) and (block_H > tamaCenterY) then

                    set moveY to 0 - moveY

                    tell item i of blockObject to removeFromSuperview()

                    set item i of blockPosition to {0,0,0,0}

 

                    if blockCount is 1 then

                        --|Clear !|

                        tell TimerObj to invalidate()

                        set blockObject to {}

                        set blockPosition to {}

                        textLabel1's setStringValue_("Clear !")

                        set flg to false

                        NSCursor's unhide()

                    else

                        set blockCount to blockCount - 1

                        exit repeat

                    end if

                end if

            end if

        end repeat

 

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

        image1's setFrameOrigin_(BollPosition)

    end moveBall

 

    on movePad()

        set {mouseX,mouseY} to my mousePosition()

        set padX to padX + (mouseX - mouse0)

        set padLeft to padX + padW - padSizeX

        set padRight to padX + padW + padSizeX

        if padLeft < 0 then set padX to padSizeX - padW

        if padRight > viewX then set padX to viewX - padW - padSizeX

        set mouse0 to mouseX

        set padPosition to {x:padX, y:padY}

        image2's setFrameOrigin_(padPosition)

    end movePad

 

    on mousePosition()

        set mouseLocate to NSEvent's mouseLocation()

        set mouseX to (mouseLocate's x) as integer

        set mouseY to (mouseLocate's y) as integer

        return {mouseX,mouseY}

    end mousePosition

 

    -- IBOutlets

    property theWindow : missing value

 

    on awakeFromNib()

        textLabel1's setStringValue_("")

    end awakeFromNib

 

    on applicationWillFinishLaunching_(aNotification)

        set flg to false

 

        (* tamaの情報取得 *)

        set {tamaSizeX, tamaSizeY} to {16, 16}

        set {tamaSizeX, tamaSizeY} to {(tamaSizeX / 2), (tamaSizeY / 2)}

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

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

        set size2 to image1's frame()'s |size|

        set {tamaW, tamaH} to  {size2's width, size2's height}

        set {tamaW, tamaH} to {(tamaW / 2), (tamaH / 2)}

 

        (*  tamaの位置の初期値を保存 *)

        set tamaReset to {tamaX,tamaY}

 

        my stage01()

    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

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