teratail header banner
teratail header banner
質問するログイン新規登録
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

99閲覧

Unityにて、2DオブジェクトをLine Rendererで引いた線で分割できるようにしたいです。

gakut

総合スコア15

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2025/07/07 12:12

編集2025/07/07 12:16

0

1

実現したいこと

2Dオブジェクト(折り紙)をハサミで切るアクションを実現させたいです。

発生している問題・分からないこと

線を引いた所だけを消去して、残った部分はそれぞれにPolygonCollider2Dをつけて折り紙の断片オブジェクトとしてゲーム内に残したいです。

該当のソースコード

C#

1// タッチで線を引いてその線上の点を取得するコードです。RayCastは切断対象の折り紙を取得し、CreateCutPieceで折り紙を切断して断片を作ります。 2 3using UnityEngine; 4using System.Collections.Generic; 5using Clipper2Lib; 6 7public class ScissorsTool : MonoBehaviour 8{ 9 private LineRenderer lineRenderer; 10 private List<Vector3> points = new List<Vector3>(); 11 private bool isDrawing = false; 12 private bool wasScissorsMode = false; 13 14 void Start() 15 { 16 lineRenderer = GetComponent<LineRenderer>(); 17 lineRenderer.positionCount = 0; 18 lineRenderer.widthMultiplier = 0.2f; 19 } 20 21 void Update() 22 { 23 bool isScissorsMode = GameModeManager.Instance.IsScissorsMode; 24 25 if (wasScissorsMode && !isScissorsMode) { 26 isDrawing = false; 27 lineRenderer.positionCount = 0; 28 points.Clear(); 29 } 30 31 wasScissorsMode = isScissorsMode; 32 33 if (!isScissorsMode) 34 return; 35 36 // マウスでハサミを追従(またはタッチ) 37 if (Input.GetMouseButtonDown(0)) 38 { 39 StartDrawing(); 40 } 41 else if (Input.GetMouseButton(0) && isDrawing) 42 { 43 Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); 44 mousePos.z = 0f; 45 46 if (points.Count == 0 || Vector3.Distance(points[points.Count - 1], mousePos) > 0.05f) 47 { 48 points.Add(mousePos); 49 lineRenderer.positionCount = points.Count; 50 lineRenderer.SetPosition(points.Count - 1, mousePos); 51 } 52 } 53 else if (Input.GetMouseButtonUp(0) && isDrawing) 54 { 55 EndDrawing(); 56 } 57 } 58 59 void StartDrawing() 60 { 61 isDrawing = true; 62 points.Clear(); 63 lineRenderer.positionCount = 0; 64 } 65 66 void EndDrawing() 67 { 68 isDrawing = false; 69 70 HashSet<GameObject> detectedOrigami = new HashSet<GameObject>(); 71 72 for (int i = 0; i < points.Count - 1; i++) 73 { 74 Vector2 start = points[i]; 75 Vector2 end = points[i + 1]; 76 Vector2 dir = (end - start).normalized; 77 float distance = Vector2.Distance(start, end); 78 79 RaycastHit2D[] hits = Physics2D.RaycastAll(start, dir, distance, LayerMask.GetMask("Origami")); 80 foreach (var hit in hits) 81 { 82 detectedOrigami.Add(hit.collider.gameObject); 83 } 84 } 85 86 foreach (GameObject obj in detectedOrigami) 87 { 88 Debug.Log("検知: " + obj.name); 89 } 90 91 OrigamiProcessor.CreateCutPiece(points, detectedOrigami); 92 93 foreach(var origami in detectedOrigami) { 94 Destroy(origami); 95 } 96 } 97}

C#

1// 折り紙を切って折り紙の断片を生成します。Clipper2Libというライブラリで実行しています。 2ここが一番の問題だと思われます。ハサミの切り取り線と切断対象の折り紙の形状を取得して、その形状の差分で断片(CutPart)を取得します。 3 4using UnityEngine; 5using System.Collections.Generic; 6using Clipper2Lib; 7 8public static class OrigamiProcessor 9{ 10 const double scale = 10000; 11 12 public static Paths64 ConvertColliderToClipperPaths(PolygonCollider2D collider) 13 { 14 Paths64 paths = new Paths64(); 15 16 for (int i = 0; i < collider.pathCount; i++) 17 { 18 Vector2[] points = collider.GetPath(i); 19 Path64 path = new Path64(); 20 21 foreach (Vector2 point in points) 22 { 23 long x = (long)(point.x * scale); 24 long y = (long)(point.y * scale); 25 path.Add(new Point64(x, y)); 26 } 27 28 paths.Add(path); 29 } 30 31 return paths; 32 } 33 34 public static Path64 ConvertCutLineToClipperPath(List<Vector2> localCutPoints) 35 { 36 Path64 cutPath = new Path64(); 37 38 foreach (var point in localCutPoints) 39 { 40 long x = (long)(point.x * scale); 41 long y = (long)(point.y * scale); 42 cutPath.Add(new Point64(x, y)); 43 } 44 45 return cutPath; 46 } 47 48 public static void CreateCutPiece(List<Vector3> points, HashSet<GameObject> detectedOrigami) 49 { 50 foreach(GameObject origami in detectedOrigami) 51 { 52 List<Vector2> localCutPoints = new List<Vector2>(); 53 54 PolygonCollider2D polygon = origami.GetComponent<PolygonCollider2D>(); 55 foreach (var point in points) { 56 localCutPoints.Add(polygon.transform.InverseTransformPoint(point)); 57 } 58 59 Paths64 subj = ConvertColliderToClipperPaths(polygon); 60 Path64 clip = ConvertCutLineToClipperPath(localCutPoints); 61 62 Paths64 cutResult = Clipper.Difference(subj, new Paths64 { clip }, FillRule.NonZero); 63 64 foreach (var poly in cutResult) { 65 // 新しい GameObject を作成 66 GameObject part = new GameObject("CutPart"); 67 part.transform.position = origami.transform.position; 68 part.transform.rotation = origami.transform.rotation; 69 part.transform.localScale = origami.transform.localScale; 70 71 part.layer = origami.layer; 72 73 // PolygonCollider2Dを追加 74 var collider = part.AddComponent<PolygonCollider2D>(); 75 76 // ワールド→ローカルに戻して設定 77 Vector2[] localPoints = new Vector2[poly.Count]; 78 for (int i = 0; i < poly.Count; i++) 79 { 80 localPoints[i] = new Vector2( 81 (float)(poly[i].X / scale), 82 (float)(poly[i].Y / scale) 83 ); 84 } 85 86 collider.SetPath(0, localPoints); 87 88 var originalPTM = origami.GetComponent<PolygonToMesh>(); 89 var partPTM = part.AddComponent<PolygonToMesh>(); 90 partPTM.origamiMaterial = originalPTM.origamiMaterial; 91 } 92 } 93 } 94}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

切ることはできるのですが、引いた線とは関係ない箇所が消去(切断)されてしまいます(特に切断線と交差する線を引いた時や、線が折り返した時に起こります)。
他にもCSGで試したのですが、線と折り紙が交わっているのに交わっていない判定をされてしまいます。
※こんな感じです。白線をマウスで引いてます。元々正方形なのですが、変な切れ込みが入ってしまいます。

補足

現在、折り紙はPolygon Collider2Dを形成して、そのPolygon Collider2Dに合わせてMeshを張っているという感じです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

切り取り線が閉ループでないためにライブラリ側が切り取り線を閉ループへと補正する結果、意図しない部分を切り取り線が囲ってしまいこのような切り取りエラーが出ていました。
なので、切り取り線をこちら側で閉ループに修正することで、補正が入らずに想定した切り取りができるようになりました!!

投稿2025/07/09 06:45

gakut

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問