質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.35%
C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

3119閲覧

Unity 2D Animationに追従する当たり判定を取りたい。

o29

総合スコア1

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/09/06 08:33

前提・実現したいこと

Unity 2D AnimationとSpringJointを使ったソフトボディのオブジェクトを作ったのですが、ボーンに対応してspriteSkinで変形させたspriteの当たり判定の取り方がわかりません…。
別のオブジェクトを使って転がすようなゲームを作りたいので、porigonCollider2Dで自動生成される程度の正確な当たり判定が取りたいです。
ソフトボディの実装はこちらの動画を参考にして作りました。
リンク

□porigonCollider2Dを更新し続ける。
リンク
→自動生成のporigonCollider2DはspriteSkinで変形する前の形になるのでダメだった。

□meshを使う。
リンク
→meshとsprite、spriteSkinを同じオブジェクトに両立して実装させることが難しく、他の方法を模索。

□spriteSkinで変更されたspriteの値を取ってporigonCollider2Dに直接入れる。
リンク
リンク
→spriteSkinがメソッドで返してくれる値とporigonCollider2Dに入れる為の値が違うので変換する必要があるが、何がどういった値を示しているか理解できていない。

Unity 2D Animationを使わなくても、当たり判定が取れるもちもちしたものが実装できればよいのですが他に方法が思いつきません。
知識不足で頓挫してしまってるのは承知ですが、なにか解決のヒントを頂けたら非常にありがたいです。

◆環境

Unity 2020.3.15f2

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

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

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

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

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

guest

回答1

0

ベストアンサー

□spriteSkinで変更されたspriteの値を取ってporigonCollider2Dに直接入れる。

というのはいい案かと思います。その方針で検討してみました。
オブジェクトに下記のようなスクリプトをアタッチしたところ...

lang

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5using UnityEngine.U2D.Animation; 6 7[RequireComponent(typeof(PolygonCollider2D), typeof(SpriteSkin))] 8public class SpriteSkinColliderAdjuster : MonoBehaviour 9{ 10 private new PolygonCollider2D collider; 11 private SpriteSkin skin; 12 13 private readonly List<Vector3> deformedVertices = new List<Vector3>(); 14 private List<List<ushort>> outlines; 15 private List<Vector2[]> outlineVertices; 16 17 private void Awake() 18 { 19 // 必要なコンポーネントを取得しておく 20 this.collider = this.GetComponent<PolygonCollider2D>(); 21 this.skin = this.GetComponent<SpriteSkin>(); 22 23 // スプライトのメッシュの外周を成す頂点のインデックスを調べる 24 var spriteRenderer = this.GetComponent<SpriteRenderer>(); 25 var sprite = spriteRenderer.sprite; 26 var indices = sprite.triangles; 27 IEnumerable<Edge> CreateEdges(int triangleIndex) 28 { 29 var i0 = triangleIndex * 3; 30 var i1 = i0 + 1; 31 var i2 = i1 + 1; 32 yield return new Edge(indices[i0], indices[i1]); 33 yield return new Edge(indices[i1], indices[i2]); 34 yield return new Edge(indices[i2], indices[i0]); 35 } 36 var edges = Enumerable.Range(0, indices.Length / 3).SelectMany(CreateEdges).ToArray(); 37 var redundantEdges = edges.Where(e => edges.Contains(new Edge(e.To, e.From))).ToArray(); 38 var outlineEdges = new HashSet<Edge>(edges.Except(redundantEdges)); 39 this.outlines = new List<List<ushort>>(); 40 while (outlineEdges.Any()) 41 { 42 var outline = new List<ushort>(); 43 var firstEdge = outlineEdges.First(); 44 outlineEdges.Remove(firstEdge); 45 var origin = firstEdge.From; 46 outline.Add(origin); 47 var nextIndex = firstEdge.To; 48 while (nextIndex != origin) 49 { 50 outline.Add(nextIndex); 51 var nextEdge = outlineEdges.First(e => e.From == nextIndex); 52 outlineEdges.Remove(nextEdge); 53 nextIndex = nextEdge.To; 54 } 55 56 this.outlines.Add(outline); 57 } 58 this.outlineVertices = new List<Vector2[]>(Enumerable.Range(0, this.outlines.Count).Select(i => new Vector2[this.outlines[i].Count])); 59 } 60 61 private void Update() 62 { 63 // メッシュが変形されていれば... 64 if (this.skin.HasCurrentDeformedVertices()) 65 { 66 // まず変形されたメッシュの頂点座標を取得する 67 this.deformedVertices.Clear(); 68 this.deformedVertices.AddRange(this.skin.GetDeformedVertexPositionData()); 69 70 // 外周のインデックスを参照し、該当する頂点の座標を取得・整理する 71 for (var i = 0; i < this.outlines.Count; i++) 72 { 73 var outline = this.outlines[i]; 74 var positions = this.outlineVertices[i]; 75 for (var j = 0; j < outline.Count; j++) 76 { 77 positions[j] = this.deformedVertices[outline[j]]; 78 } 79 } 80 81 // コライダーにパスをセットする 82 this.collider.pathCount = this.outlines.Count; 83 for (var i = 0; i < this.outlines.Count; i++) 84 { 85 this.collider.SetPath(i, this.outlineVertices[i]); 86 } 87 } 88 } 89 90 private readonly struct Edge : IEquatable<Edge> 91 { 92 public Edge(ushort from, ushort to) 93 { 94 this.From = from; 95 this.To = to; 96 } 97 98 public readonly ushort From; 99 public readonly ushort To; 100 101 public bool Equals(Edge other) 102 { 103 return (this.From == other.From) && (this.To == other.To); 104 } 105 106 public override bool Equals(object obj) 107 { 108 return obj is Edge other && this.Equals(other); 109 } 110 111 public override int GetHashCode() 112 { 113 unchecked 114 { 115 return (this.From.GetHashCode() * 397) ^ this.To.GetHashCode(); 116 } 117 } 118 } 119}

下図のように変形しました。

図

投稿2021/09/06 22:12

Bongo

総合スコア10811

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

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

o29

2021/09/07 15:33

ありがとうございます! 教えていただいた方法で想像していた通りの実装が出来ました。 正直、スクリプトの内容について理解出来てない部分も多々あるので、開発を進めつつこのコードを参考に理解を深めようと思います。 また、素早く回答していただいてとても助かりました。 本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問