ExcelVBAゲームプログラミング?

初心者でもきっとできる!
Excelさえ持っていれば特別なソフトは不要!
すぐにでも始められる簡単ゲームプログラミング!
今すぐ始めよう!

サンプルやゲームのダウンロードができる別館も好評運営中です。
ご意見やご質問、ゲームの感想等は掲示板までお気軽に。是非、皆さんの声を聞かせてください。運営、開発の励みになります。



各種ダウンロードはコチラ ↓ 意見・感想・質問はコチラ ↓
影倉庫 Shadow warehouse サポート掲示板
ブログの全体像はコチラ ↓ リンクのページはコチラ ↓
サイトマップ 自分本位なリンク


スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。






Chapter.115 [ ブロック崩しゲーム10:ボールの処理 ]

■ボールの処理に組み込む

前回と前々回、ちょっと数学的な話が続きました。少し難解な内容ではありましたが、大事なのはそれをプログラムにどう活用するかです。今回は、前回までで作成した線分が関係する処理を、それぞれボールの処理に組み込んでいきます。

今回作成するボールの処理は、かなり規模の大きなプロシージャになります。ポイントとしては、前回までに作成している線分関係の処理が、それぞれどのような意味のプロシージャなのか、それをよく理解して作成していくことです。ボール処理の様々なところで登場しますので、その都度どういう意味合いでプロシージャが呼び出されているのかを理解していないと、わけがわからなくなると思います。

前もって、再度前回までに作成しているプロシージャを確認しておきましょう。

CrossLine …… 線分の交差を判定しBool型で結果を返す
CrossPoint …… 線分の交点をVector型で返す

これが前回までに作成したふたつのプロシージャでしたね。交差を判定する CrossLine と、交点の座標を算出する CrossPoint のふたつを活用しながら、ブロック崩しの核となるボールの処理を作成していきます。CrossPoint のほうは、ユーザー定義型である Vector 型で結果を返してきますので、注意しましょう。


■ボール処理の概要

さて、それではボール処理を実際に見ていきます。

ボールを処理する際は、必要な情報をひとつひとつ取得しながら、様々なケースを想定して処理を組んでいきます。おおまかな手順で言うと、まずはボールの現在の座標(移動する前の位置)と、移動したあとの座標を明確にします。ここまでは、どんな場合でも必ず同じように行う必要がありますね。

移動後の座標が明確になると、今度はそこに壁やブロックが存在するのかどうかを判断します。もし、壁やブロックがそこにあって、ボールを反射させる必要があるなら、ボールの移動する向きを反転させたりしなければなりませんね。

このように考えると、ボールの処理のおおまかな流れは次のようになります。

ボールの現在位置と移動後の位置を明確にする
    ▼
そこに壁があるかを調べる
    ▼
壁があるならボールの移動方向を反転する
    ▼
ボールが画面上の上半分にあるか下半分にあるか調べる
    ▼
上半分にあるならブロックと衝突しているかもしれない
    ▼
ブロックとの衝突があるのかどうか調べる
    ▼
ブロックと衝突しているならボールの移動方向を反転する
    ▼
下半分にあるならバーと衝突しているかもしれない
    ▼
バーとの衝突があるのかどうか調べる
    ▼
バーと衝突しているならボールの移動方向を反転する
    ▼
最終的にボールがどこに置かれるのか決定する

こんな感じになりますね。


■ボールの処理

このプロシージャは大別してみっつのブロックから成り立っています。それぞれのブロックの役割をしっかり理解していくことが大切です。

各ブロックはコードを色分けして表示しています。それを参考にしながら考えてみてください。

Sub Ball_Move()

    Dim L As Long
    Dim S As Single
    Dim SS As Single

    Dim fX As Boolean
    '横方向での衝突があったかどうかを保持するフラグ

    Dim fY As Boolean
    '縦方向での衝突があったかどうかを保持するフラグ

    Dim oX As Single
    '線分の処理に利用するX座標

    Dim oY As Single
    '線分の処理に利用するY座標

    Dim CP As Vector
    '線分の交点座標を保持するためのVector型変数
    
    With Ball
        fX = False 'フラグを初期化する
        fY = False 'フラグを初期化する
        .aX = .bX + .vX * .Sp '移動後のボールのX座標を求める
        .aY = .bY + .vY * .Sp '移動後のボールのY座標を求める
        CP.X = .aX
        CP.Y = .aY
        If .aX < W_Ball / 2 Then
            fX = True
            CP = CrossPoint(.aX, .aY, _
                            .bX, .bY, _
                            W_Ball / 2, 0, _
                            W_Ball / 2, H_Field)
        End If
        If .aX > W_Field - W_Ball / 2 Then
            fX = True
            CP = CrossPoint(.aX, .aY, _
                            .bX, .bY, _
                            W_Field - W_Ball / 2, 0, _
                            W_Field - W_Ball / 2, H_Field)
        End If
        If .aY < W_Ball / 2 Then
            fY = True
            CP = CrossPoint(.aX, .aY, _
                            .bX, .bY, _
                            0, W_Ball / 2, _
                            W_Field, W_Ball / 2)
        End If
        If .aY > H_Field Then
            .Vis = False
        End If

        If .aY <= H_Field / 2 Then
            For L = 1 To 25
                If Block(L).Vis Then
                    If Not fX Then
                        SS = W_Ball / 2
                        fX = False
                        If .vX < 0 Then
                            S = Block(L).X + W_Block / 2
                            oX = S + SS
                        Else
                            S = Block(L).X - W_Block / 2
                            oX = S - SS
                        End If
                        fX = CrossLine(.aX, .aY, _
                                       .bX, .bY, _
                                       oX, Block(L).Y - H_Block / 2 - SS, _
                                       oX, Block(L).Y + H_Block / 2 + SS)
                        If fX Then
                            CP = CrossPoint(.aX, .aY, _
                                            .bX, .bY, _
                                            oX, Block(L).Y - H_Block / 2 - SS, _
                                            oX, Block(L).Y + H_Block / 2 + SS)
                            Block(L).Vis = False
                            If .Sp < 12.5 Then .Sp = .Sp + 0.5
                        End If
                    End If
                    If Not fY Then
                        SS = W_Ball / 2
                        fY = False
                        If .vY < 0 Then
                            S = Block(L).Y + H_Block / 2
                            oY = S + SS
                        Else
                            S = Block(L).Y - H_Block / 2
                            oY = S - SS
                        End If
                        fY = CrossLine(.aX, .aY, _
                                       .bX, .bY, _
                                       Block(L).X - W_Block / 2 - SS, oY, _
                                       Block(L).X + W_Block / 2 + SS, oY)
                        If fY Then
                            CP = CrossPoint(.aX, .aY, _
                                            .bX, .bY, _
                                            Block(L).X - W_Block / 2 - SS, oY, _
                                            Block(L).X + W_Block / 2 + SS, oY)
                            Block(L).Vis = False
                            If .Sp < 12.5 Then .Sp = .Sp + 0.5
                        End If
                    End If
                End If
                UserForm1.Controls("Label" & L).Visible = Block(L).Vis
            Next
            If fX Then
                .vX = -.vX
                .aX = CP.X
                .aY = CP.Y
            End If
            If fY Then
                .vY = -.vY
                .aX = CP.X
                .aY = CP.Y
            End If

        Else
            If .vY > 0 Then
                If Not fX And Not fY Then
                    SS = W_Ball / 2
                    fX = False
                    If .vX < 0 Then
                        S = Bar.X + W_Bar / 2
                        oX = S + SS
                    Else
                        S = Bar.X - W_Bar / 2
                        oX = S - SS
                    End If
                    fX = CrossLine(.aX, .aY, _
                                   .bX, .bY, _
                                   oX, Bar.Y - H_Bar / 2 - SS, _
                                   oX, Bar.Y + H_Bar / 2 + SS)
                    If fX Then
                        CP = CrossPoint(.aX, .aY, _
                                        .bX, .bY, _
                                        oX, Bar.Y - H_Bar / 2 - SS, _
                                        oX, Bar.Y + H_Bar / 2 + SS)
                    End If
                    fY = False
                    S = Bar.Y - H_Bar / 2
                    oY = S - SS
                    fY = CrossLine(.aX, .aY, _
                                   .bX, .bY, _
                                   Bar.X - W_Bar / 2 - SS, oY, _
                                   Bar.X + W_Bar / 2 + SS, oY)
                    If fY Then
                        CP = CrossPoint(.aX, .aY, _
                                        .bX, .bY, _
                                        Bar.X - W_Bar / 2 - SS, oY, _
                                        Bar.X + W_Bar / 2 + SS, oY)
                    End If
                End If
            End If
            If fX Then
                .vX = -.vX
                .aX = CP.X
                .aY = CP.Y
            End If
            If fY Then
                .vY = -.vY
                .aX = CP.X
                .aY = CP.Y
                S = Bar.X - W_Bar / 2
                SS = Bar.X + W_Bar / 2
                If .aX >= S Then
                    If .aX <= S + (W_Bar / 3) Then .vX = -Abs(.vX)
                End If
                If .aX <= SS Then
                    If .aX >= SS - (W_Bar / 3) Then .vX = Abs(.vX)
                End If
                If .aX > S + (W_Bar / 3) Then
                    If .aX < SS - (W_Bar / 3) Then .vY = -Abs(.vY) * 1.05
                End If
            End If

        End If
        If .aX < W_Ball / 2 Then .aX = W_Ball / 2
        If .aX > W_Field - W_Ball / 2 Then .aX = W_Field - W_Ball / 2
        If .aY < W_Ball / 2 Then .aY = W_Ball / 2
        .bX = .aX
        .bY = .aY
    End With
    
    With UserForm1
        .Ima_ball.Left = Ball.aX - W_Ball / 2
        .Ima_ball.Top = Ball.aY - W_Ball / 2
    End With
    
End Sub

とても長いプロシージャですね。
ちょっと気がめいりそうになりますが、順番に見ていきましょう。

まず、最初の黄色い文字の部分では、壁との衝突があったのかどうかを調べています。あらかじめ宣言してあった定数をうまくつかって、ボールと、左・上・右の壁との衝突があったのかどうかを判定しています。

壁の向こう側にめりこんでしまうような座標にボールが到達している場合には、これは衝突をしていることと同じです。ボールの移動前の座標と、移動後の座標をつないで一本の線分を作り、さらに、壁を一本の線分と考えて、線分同士の交差判定を行っていますね。(プロシージャ CrossPoint を呼び出している部分)

変数 CP は、Vector 型の変数です。ですから、プロシージャ CrossPoint が返してくる交点座標の情報を受け取ることができます。CrossPoint を呼び出したあと、変数 CP に取得されている座標情報を調べれば、ボールが存在するべき座標がわかるというわけです。

もし、下の壁よりもボールが向こう側にある場合は、これはボールを落としてしまっているということになりますね。ですからこの場合は、ボールを見えないようにしています。
これで、ボールと壁との処理はすべて完了です。


続いて、ボールが画面上の上半分にいるのか、それとも下半分にいるのかを調べ、その結果によって処理を分割しています。

ボールが上半分にいる場合には、ブロックと衝突をしている可能性があるため、ブロックとの衝突があるのかどうかを調べていきます。これが緑色の文字で書かれているコードの部分ですね。

ブロックひとつひとつと順番に衝突判定を行っていき、もし衝突が発生しているなら壁のときと同様に線分による処理を行います。最終的に線分同士の交点座標を算出して、それをボールの最終的な移動後の位置として設定するわけです。

ボールが下半分にいる場合は、ブロックと衝突する可能性はありません。その代わり、バーとの衝突が発生している可能性はありますね。バーとの衝突判定を行っているのは水色の文字で示されている部分です。
ここでも、ブロックとボールのときに行ったのと同様に、バーとボールの衝突判定を行っています。もしバーとボールが衝突しているのなら、線分による衝突判定を行ってボールの最終的な位置を算出しています。


どのような衝突判定の場合でも、まずはプロシージャ CrossLine を使って、線分の交差があるのかどうかを判定しています。ボールの移動前の座標と、移動後の座標を繋いで一本の線分を作り、対象となるブロックやバーの一辺を線分として考え、これら二本の線分の交差を判定します。
線分同士が交差しているなら、これは衝突が起こっていることと同じになります。衝突が起こっているなら、今度は線分と線分との交点を算出するために CrossPoint を呼び出し、交点座標にボールを配置することで、ボールの最終的な座標位置を決定しています。


■まとめ

さて、はたしてこの解説を見ている人が、この説明だけでどれだけ理解できているのか不安ですが、いかがでしょうか。プロシージャ自体がかなり大きいので、ちょっと理解するのが大変かもしれません。

ポイントとなるのは、コードにつけられた色を参考にして、その部分が一体どのような処理を行っている部分なのかをしっかり理解して考えることです。
今現在は、ボールと何との衝突を判定している部分なのか、それが明確になっていないとなかなかスムーズに理解することは難しいでしょう。壁、ブロック、バー、そしてボール。これらがどのような関係にあるのかをしっかり理解して処理を考えましょう。

実際に動くサンプルは、次回、ダウンロードできるようにするつもりです。
そして、次回は恐らくブロック崩しゲームの最終回になると思います。完成したブロック崩しゲームのサンプルは、そのときにお披露目します。



■格言

現在の状態を把握して処理する
線分関連の処理の意味を理解する


前回までの上積みが、ここへきて重要になります。
意味がわからない場合は少し戻って、もう一度考えてみるのもいいかもしれません。

関連記事






Comment

Name
E-mail
URL
Comment
Pass  *
Secret? (管理者にだけ表示)

メールフォーム

影斬に物申すという方はこちら

名前 :
メール:
件名 :
本文 :

可能な限り要望には応えますが、必ず返信や回答ができることを、保障するものではありません。
ご了承ください。

Chapters

コンテンツ一覧


■Chapter 一覧■
    全てのChapterの一覧です。
    直接アクセスしたい方はこちらをご利用下さい。

    Chapter.1 [ 知っておくべき心得 ]
    Chapter.2 [ Excelってなんだろう ]
    Chapter.3 [ Excelの基本画面 ]
    Chapter.4 [ VBAとは? ]
    Chapter.5 [ モジュールについて ]
    Chapter.6 [ 変数 ]
    Chapter.7 [ 変数の型と宣言 ]
    Chapter.8 [ プロシージャとスコープ ]
    Chapter.9 [ ゲームつくる様々な手法 ]
    Chapter.10 [ ユーザーフォーム ]
    Chapter.11 [ プロパティウィンドウ ]
    Chapter.12 [ 乱数 ]
    Chapter.13 [ 条件分岐 ]
    Chapter.14 [ ゲーム画面のデザイン ]
    Chapter.15 [ コード記述の基本作法 ]
    Chapter.16 [ じゃんけんゲーム:1 名前をつける ]
    Chapter.17 [ じゃんけんゲーム:2 フォームの起動 ]
    Chapter.18 [ じゃんけんゲーム:3 乱数の種 ]
    Chapter.19 [ じゃんけんゲーム:4 イベント ]
    Chapter.20 [ じゃんけんゲーム:5 引数 ]
    Chapter.21 [ じゃんけんゲーム:6 役判定 ]
    Chapter.22 [ じゃんけんゲーム:7 予測と制限 ]
    Chapter.23 [ Withステートメント ]
    Chapter.24 [ 画像を表示させる ]
    Chapter.25 [ 画像表示の発展形 ]
    Chapter.26 [ 繰り返し処理 For文 ]
    Chapter.27 [ 繰り返し処理 Do~Loop文 ]
    Chapter.28 [ Exitステートメント ]
    Chapter.29 [ フォーム上の位置情報 ]
    Chapter.30 [ API基礎知識 ]
    Chapter.31 [ API補足知識 ]
    Chapter.32 [ メインループを考える ]
    Chapter.33 [ 同期処理の概念 ]
    Chapter.34 [ 移動処理その1:画面設定と考え方 ]
    Chapter.35 [ 移動処理その2:DoEvents ]
    Chapter.36 [ 移動処理その3:キー入力判定API ]
    Chapter.37 [ 条件分岐のさらなる探求 Select Case ]
    Chapter.38 [ アニメーション ]
    Chapter.39 [ 配列変数 ]
    Chapter.40 [ ゲームの初期化 ]
    Chapter.41 [ シューティングゲーム1:ゲーム設計 ]
    Chapter.42 [ シューティングゲーム2:メインプロセス ]
    Chapter.43 [ シューティングゲーム3:構造体 ]
    Chapter.44 [ シューティングゲーム4:定数 ]
    Chapter.45 [ シューティングゲーム5:プレイヤーキャラクター ]
    Chapter.46 [ シューティングゲーム6:ショットを撃つ① ]
    Chapter.47 [ シューティングゲーム7:ショットを撃つ② ]
    Chapter.48 [ シューティングゲーム8:Mod演算子の活用 ]
    Chapter.49 [ シューティングゲーム9:敵キャラクター登場 ]
    Chapter.50 [ シューティングゲーム10:衝突判定 ]
    Chapter.51 [ シューティングゲーム11:衝突の実体 ]
    Chapter.52 [ シューティングゲーム12:敵の攻撃 ]
    Chapter.53 [ シューティングゲーム13:爆発エフェクト ]
    Chapter.54 [ シューティングゲーム14:残機数表示① ]
    Chapter.55 [ シューティングゲーム15:残機数表示② ]
    Chapter.56 [ シューティングゲーム16:スコアの表示 ]
    Chapter.57 [ シューティングゲーム17:タイトル画面 ]
    Chapter.58 [ シューティングゲーム18:ボスキャラクター ]
    Chapter.59 [ シューティングゲーム19:最後の仕上げへ ]
    Chapter.60 [ シューティングゲーム20:いよいよ完成STG ]
    Chapter.61 [ カードゲームで使えるめくり効果 ]
    Chapter.62 [ ラジアンと角度 ]
    Chapter.63 [ ラジアンの活用:円運動 ]
    Chapter.64 [ ラジアンの活用:任意の角度へ移動する ]
    Chapter.65 [ APIによるサウンド再生:基礎 ]
    Chapter.66 [ APIによるサウンド再生:MIDIと多重再生 ]
    Chapter.67 [ APIによるサウンド再生:MCIコマンドとループ再生 ]
    Chapter.68 [ Function プロシージャ ]
    Chapter.69 [ 値渡しと参照渡し ]
    Chapter.70 [ デバッグ1:イミディエイトウィンドウ ]
    Chapter.71 [ デバッグ2:ローカルウィンドウ ]
    Chapter.72 [ デバッグ3:コード実行の中断 ]
    Chapter.73 [ オブジェクトってなんだ ]
    Chapter.74 [ プロパティ・メソッド・イベント ]
    Chapter.75 [ オブジェクト変数 ]
    Chapter.76 [ オブジェクトとコレクション ]
    Chapter.77 [ 特殊な繰り返し:For Each ]
    Chapter.78 [ エラー処理 ]
    Chapter.79 [ On Error と GoTo文 ]
    Chapter.80 [ Resumeステートメント ]
    Chapter.81 [ バイトとビット ]
    Chapter.82 [ ウィンドウメッセージとイベント ]
    Chapter.83 [ 文字列の基礎 ]
    Chapter.84 [ 文字列操作① ]
    Chapter.85 [ 文字列操作② ]
    Chapter.86 [ タイピングゲーム1:仕様を決める ]
    Chapter.87 [ タイピングゲーム2:キー入力検知 ]
    Chapter.88 [ タイピングゲーム3:文字列照合 ]
    Chapter.89 [ タイピングゲーム4:判定関数 ]
    Chapter.90 [ タイピングゲーム5:ゲーム画面設計 ]
    Chapter.91 [ タイピングゲーム6:問題文のソート ]
    Chapter.92 [ タイピングゲーム7:動的配列 ]
    Chapter.93 [ タイピングゲーム8:キーダウンイベント ]
    Chapter.94 [ タイピングゲーム9:正打数の表示 ]
    Chapter.95 [ タイピングゲーム10:タイムの表示 ]
    Chapter.96 [ クリックゲーム1:イベントの種類 ]
    Chapter.97 [ クリックゲーム2:画面設計 ]
    Chapter.98 [ クリックゲーム3:クリック座標検知 ]
    Chapter.99 [ クリックゲーム4:キャラクター準備 ]
    Chapter.100 [ クリックゲーム5:キャラクターの配置 ]
    Chapter.101 [ クリックゲーム6:キャラクター移動とNot演算子 ]
    Chapter.102 [ クリックゲーム7:クリックのヒット判定 ]
    Chapter.103 [ クリックゲーム8:ヒットマークエフェクト ]
    Chapter.104 [ クリックゲーム9:サウンド処理の実装 ]
    Chapter.105 [ クリックゲーム10:マウスカーソルの変更 ]
    Chapter.106 [ ブロック崩しゲーム1:仕様と概要を決める ]
    Chapter.107 [ ブロック崩しゲーム2:基本概念の確認 ]
    Chapter.108 [ ブロック崩しゲーム3:ベクトルとは ]
    Chapter.109 [ ブロック崩しゲーム4:変数や定数の宣言 ]
    Chapter.110 [ ブロック崩しゲーム5:初期化処理の実装 ]
    Chapter.111 [ ブロック崩しゲーム6:ブロックの配置 ]
    Chapter.112 [ ブロック崩しゲーム7:根幹処理とバーの処理 ]
    Chapter.113 [ ブロック崩しゲーム8:線分と線分の交差を判定 ]
    Chapter.114 [ ブロック崩しゲーム9:線分同士の交点 ]
    Chapter.115 [ ブロック崩しゲーム10:ボールの処理 ]
    Chapter.116 [ ブロック崩しゲーム11:最終調整して完成へ ]
    Chapter.117 [ テキストファイル操作基礎 ]
    Chapter.118 [ テキストファイル操作:読み込み編 ]
    Chapter.119 [ テキストファイル操作:CSV読み込み編 ]
    Chapter.120 [ テキストファイル操作:様々な読込編 ]
    Chapter.121 [ テキストファイル操作:バイナリ編 ]
    Chapter.122 [ テキストファイル操作:暗号化編 ]
    Chapter.123 [ テキストファイル操作:復号化編 ]
    Chapter.124 [ クラスモジュールとは ]
    Chapter.125 [ クラスモジュール:メソッド編 ]
    Chapter.126 [ クラスモジュール:プロパティ編 ]
    Chapter.127 [ クラスモジュール:イベント拡張編 ]
    Chapter.128 [ クラスモジュール:イベント自作編 ]
    Chapter.129 [ APIによる描画処理1:ハンドル ]
    Chapter.130 [ APIによる描画処理2:デバイスコンテキスト ]
    Chapter.131 [ APIによる描画処理3:ペン オブジェクト ]
    Chapter.132 [ APIによる描画処理4:ブラシ オブジェクト ]
    Chapter.133 [ APIによる描画処理5:図形描画準備編 ]
    Chapter.134 [ APIによる描画処理6:図形描画実践編 ]
    Chapter.135 [ APIによる描画処理7:画像描画の仕組み編 ]
    Chapter.136 [ APIによる描画処理8:ビットブロック転送編 ]
    Chapter.137 [ APIによる描画処理9:ラスタオペレーション ]
    Chapter.138 [ APIによる描画処理10:マスク描画 概念編 ]
    Chapter.139 [ APIによる描画処理11:マスク描画 実践編 ]


    コードやVBAに関する質問などはサポート掲示板(別館)までお気軽にどうぞ。




fc2 seotool Excel VBA ゲーム プログラミング 講座

Counter

twitter


Shadow BBS - 影掲示板

VBA 関連書籍



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。