実現したいこと
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を張っているという感じです。

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。