t-hom’s diary

主にVBAネタを扱っているブログです。

VBA 正円同士の当たり判定用クラス

ゲームでは正確性よりもスピードが求められる場面がある。
当たり判定もその一つで、キャラ同士がぶつかったかどうかの判定は矩形や正円などに単純化して表現される。

今回Twitterで羽毛田氏がたい焼きのキャラの当たり判定の方法を模索してるようなので以下の画像を提案してみた。
f:id:t-hom:20180909081504p:plain

キャラを正円の組み合わせで表現できれば、3×3で9通りの正円の当たり判定を行えば良いことになる。

今回はキャラ同士ではなく、正円同士がぶつかっているかどうかの判定用にクラスを書いてみた。

クラス名はCollisionSenser。
コードはこちら。

Public Name As String
Public X As Double
Public Y As Double
Public Radius As Double

Function DoesHit(c As CollisionSenser)
    DoesHit = Radius + c.Radius > CalcDiagonalDistance(Abs(X - c.X), Abs(Y - c.Y))
End Function

Private Function CalcDiagonalDistance(a, b)
    CalcDiagonalDistance = VBA.Math.Sqr(a ^ 2 + b ^ 2)
End Function

Public Property Get Self() As Object
    Set Self = Me
End Property

パブリックフィールドとして名前とX座標とY座標と半径を持たせており、当たり判定用のDoesHit関数はCollisionSenserオブジェクトを受け取って自分と当たっているかどうかを返す。

正円同士の当たりは、円の中心同士の距離が半径の合計を超えているかどうかで判定できる。
f:id:t-hom:20180909082209p:plain

円の中心同士の距離は三平方の定理で求まる。
f:id:t-hom:20180909082451p:plain

■三平方の定理
A^2 + B^2 = C^2

つまりC = sqr(A^2 + B^2)

以下のコードでテストしてみた。

Sub TestCollisionSenser()
    Dim CollisionSensers As Collection
    Set CollisionSensers = New Collection

    Dim sh As Shape
    For Each sh In Selection.ShapeRange
        With New CollisionSenser
            .Name = sh.Name
            .Radius = sh.Width / 2
            .X = sh.Left + .Radius
            .Y = sh.Top + .Radius
            CollisionSensers.Add .Self
        End With
    Next
    
    Dim cs1 As CollisionSenser, cs2 As CollisionSenser
    For Each cs1 In CollisionSensers
        For Each cs2 In CollisionSensers
            If Not cs1 Is cs2 Then
                If cs1.DoesHit(cs2) Then
                    Debug.Print cs1.Name & " does hit to " & cs2.Name
                End If
            End If
        Next
    Next
End Sub

複数の円を選択してコードを実行すると、
f:id:t-hom:20180909082728p:plain

イミディエイトウィンドウに次のように表示される。

Oval 5 does hit to Oval 6
Oval 6 does hit to Oval 5
Oval 6 does hit to Oval 10
Oval 9 does hit to Oval 11
Oval 10 does hit to Oval 6
Oval 11 does hit to Oval 9

あとはキャラ用のクラスがこのCollisionSenserを必要数保持すれば複雑な形のキャラ同士でも簡易当たり判定できるかと思う。

以上

経緯


当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。