【Godot】Collisionノードを使用せずにSprite同士の当たり判定を行う方法

通常、Sprite同士の当たり判定を行う場合、Collision ノードを使用します。これは異なる形状のオブジェクトや細かい調整が効きやすい反面、ノードを毎回組み合わせる必要があるので、ちょっとした当たり判定を行いたい場合にやや回りくどいです。(ただ通常は Collision を使ったほうが良いケースが多いので、この記事はややマニアックな方法となります)

ということで、この記事では Collision ノードを使用せずに Sprite同士の当たり判定を行う方法を紹介します。

Sprite同士の当たり判定

Geometry.intersect_polygons_2d() を使用するとポリゴンの頂点リストを PoolVector2Array として渡すことで衝突判定が行えるのでこれを利用します。

実装サンプルコード

以下、実装してみたサンプルコードとなります。

# スプライト同士が衝突しているかどうか
func _is_hit(spr1:Sprite, spr2:Sprite) -> bool:
    # Spriteの画像データを頂点として取得する
    var v1 = _spr_to_vec2array(spr1)
    var v2 = _spr_to_vec2array(spr2)
    
    if Geometry.intersect_polygons_2d(v1, v2):
        # 衝突している
        return true
    
    return false;

# スプライトから頂点リストを作る
func _spr_to_vec2array(spr:Sprite) -> PoolVector2Array:
    var ret = PoolVector2Array()
    
    var pos:Vector2 = spr.position
    var rect:Rect2 = spr.get_rect()
    # スケールを反映
    var w  = rect.size.x * spr.scale.x
    var h  = rect.size.y * spr.scale.y
    var w2 = w / 2
    var h2 = h / 2
    
    var v1 = Vector2(0, 0) # 左上
    var v2 = Vector2(w, 0) # 右上
    var v3 = Vector2(w, h) # 右下
    var v4 = Vector2(0, h) # 左下
    if spr.centered:
        # 中央揃え
        v1 = Vector2(-w2, -h2) # 左上
        v2 = Vector2( w2, -h2) # 右上
        v3 = Vector2( w2,  h2) # 右下
        v4 = Vector2(-w2,  h2) # 左下
        
    # 回転(ラジアン)を求める  
    var rad = spr.rotation
    ret.push_back(pos + v1.rotated(rad))
    ret.push_back(pos + v2.rotated(rad))
    ret.push_back(pos + v3.rotated(rad))
    ret.push_back(pos + v4.rotated(rad))
    
    return ret

ただ、Spriteの変形は様々な方法があるので、ここでひとまず、「中央揃えかどうか」「スケール値」「回転値」のみの対応としています。

完成プロジェクト

今回作成したプロジェクトを添付しておきます。