【Godot】Polygon2Dを分割するサンプル

Polygon2Dを分割するサンプルを作りました

Polygon2Dを分割するサンプル

今回はソースコードとサンプルプロジェクトのみです。まだ不十分なところも多いので、今後修正される可能性があります

  • 分割する対象を最初に存在するオブジェクト($obj)のみとしています(切れなかったときの判定が未実装)
  • 分割後にオブジェクトの Rigidbody2D の移動値が初期化されています

サンプルコード

extends Node2D

# マウス開始座標
var start_pos = Vector2()
# カットするオブジェクト(Rigit2D)
onready var obj = $obj

func _process(delta: float) -> void:
    if Input.is_action_just_pressed("ui_click"):
        start_pos = get_global_mouse_position()
    if Input.is_action_just_released("ui_click"):
        var end_pos = get_global_mouse_position()
        var dir = end_pos - start_pos
        var distance = dir.length()
        dir = dir.normalized() # 方向はノーマライズ必須.
        var ofs = obj.position
        var pos = start_pos - ofs # オフセットを消しておく
        # カットするシェイプを作成
        var cut_shape = create_beam_polygon(dir, distance, 3, 3, pos)
        var cut_p = Polygon2D.new()
        # 表示用は位置が異なる
        var cut_shape2 = create_beam_polygon(dir, distance, 3, 3, start_pos)
        cut_p.set_polygon(cut_shape2)
        add_child(cut_p)
        
        # ポリゴン分割する
        var new_polygons:Array = Geometry.clip_polygons_2d($obj/Polygon2D.polygon, cut_shape)
        obj.queue_free()
        
        # 分割したポリゴンを生成
        for p in new_polygons:
            var rigid = RigidBody2D.new()
            var poly = Polygon2D.new()
            var col = CollisionPolygon2D.new()
            poly.set_polygon(p)
            poly.modulate = Color.red
            col.set_polygon(p)
            rigid.position = ofs # オフセットを足し込む
            rigid.add_child(poly)
            rigid.add_child(col)
            add_child(rigid)

#creates a beam with a seperate start and end width
# https://github.com/SoloByte/godot-polygon2d-fracture
# @param dir 方向
# @param distance 距離
# @param start_width 開始の幅
# @param end_width 終端の幅
# @param start_point_local
func create_beam_polygon(dir : Vector2, distance : float, start_width : float, end_width : float, start_point_local := Vector2.ZERO) -> PoolVector2Array:
    var beam : PoolVector2Array = []
    if distance == 0: 
        return beam
    
    if start_width <= 0.0 and end_width <= 0.0:
        return beam
    
    if distance < 0:
        dir = -dir
        distance *= -1.0
    
    var end_point : Vector2 = start_point_local + (dir * distance)
    var perpendicular : Vector2 = dir.rotated(PI * 0.5)
    
    if start_width <= 0.0:
        beam.append(start_point_local)
        beam.append(end_point + perpendicular * end_width * 0.5)
        beam.append(end_point - perpendicular * end_width * 0.5)
    elif end_width <= 0.0:
        beam.append(start_point_local + perpendicular * start_width * 0.5)
        beam.append(end_point)
        beam.append(start_point_local - perpendicular * start_width * 0.5)
    else:
        beam.append(start_point_local + perpendicular * start_width * 0.5)
        beam.append(end_point + perpendicular * end_width * 0.5)
        beam.append(end_point - perpendicular * end_width * 0.5)
        beam.append(start_point_local - perpendicular * start_width * 0.5)
    
    return beam

マウスの移動に対応する線分のポリゴンを作るために、create_beam_polygon() という関数を使っています。この関数は、参考にしたプロジェクトからお借りしたものとなります

プロジェクトファイル

※(2025.8.24追記) Godot4でAPIが変更されたため、上記プロジェクトはエラーとなります。そのため参考コードからマージして修正する必要があります。

参考