回答編集履歴

1

追加調査の結果を追記

2018/02/11 22:52

投稿

Bongo
Bongo

スコア10811

test CHANGED
@@ -5,3 +5,123 @@
5
5
  Colliderのmaterialプロパティなら、自動的にマテリアルが複製されて他のオブジェクトに影響は及ばないようですが、Collider2Dの場合は適宜自前でマテリアルを複製してやる必要があるかもしれません。
6
6
 
7
7
  [How to change material friction from code for a circle collider 2d? - Unity Answers](https://answers.unity.com/questions/797691/how-to-change-material-friction-from-code-for-a-ci.html)がご参考になりそうです。
8
+
9
+
10
+
11
+ ### [追記]
12
+
13
+ 追記いただいた現象についてちょっと調べてみました。
14
+
15
+
16
+
17
+ まず[Change a Collider 2D physics material at runtime? - Unity Answers](https://answers.unity.com/questions/579648/change-a-collider-2d-physics-material-at-runtime.html)によると、sharedMaterialの変更は自動的には反映されず、一旦コライダーの[enabled](https://docs.unity3d.com/ScriptReference/Behaviour-enabled.html)をfalseにし、再度trueに戻してやる必要があるようです。
18
+
19
+
20
+
21
+ 次に、[OnCollisionEnter2D](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnCollisionEnter2D.html)内でボールの速度を見てみたところ、すでに跳ね返り後の速度になっていました。この挙動は[Unity - Manual: Execution Order of Event Functions](https://docs.unity3d.com/Manual/ExecutionOrder.html)の解説とも合致していて、OnCollision系メソッドが呼ばれるのは物理状態更新後のタイミングだそうです。
22
+
23
+ ですので、仮に先に申し上げたようにsharedMaterialのbouncinessを変更し、コライダーのenabledをfalseにし、再度trueに戻したとしても、新しい反発係数が適用されるのは次回の衝突時になるようですね。
24
+
25
+ bouncinessを変更したその時の跳ね返りも新しい反発係数を適用するには、結局[AddForce](https://docs.unity3d.com/ScriptReference/Rigidbody2D.AddForce.html)で過剰分・不足分の力積を加えて補正してやることになりそうです。
26
+
27
+
28
+
29
+ ```C#
30
+
31
+ using UnityEngine;
32
+
33
+
34
+
35
+ [RequireComponent(typeof(Collider2D), typeof(Rigidbody2D))]
36
+
37
+ public class BallController : MonoBehaviour {
38
+
39
+
40
+
41
+ private Collider2D collider;
42
+
43
+ private Rigidbody2D rigidbody;
44
+
45
+
46
+
47
+ public void Start()
48
+
49
+ {
50
+
51
+ // あらかじめCollider2DとRigidbody2Dを取得しておく
52
+
53
+ this.collider = this.GetComponent<Collider2D>();
54
+
55
+ this.rigidbody = this.GetComponent<Rigidbody2D>();
56
+
57
+
58
+
59
+ // マテリアルを複製し、sharedMaterialの変更が他へ及ばないようにする
60
+
61
+ var material = this.collider.sharedMaterial;
62
+
63
+ var newMaterial = new PhysicsMaterial2D(material.name + " (Instance)");
64
+
65
+
66
+
67
+ newMaterial.bounciness = material.bounciness;
68
+
69
+ newMaterial.friction = material.friction;
70
+
71
+ this.collider.sharedMaterial = newMaterial;
72
+
73
+ }
74
+
75
+
76
+
77
+ private void OnCollisionEnter2D(Collision2D coll)
78
+
79
+ {
80
+
81
+ var material = this.collider.sharedMaterial;
82
+
83
+ var currentBounciness = material.bounciness; // 現在の反発係数
84
+
85
+ var nextBounciness = 0.5f; // 新しい反発係数
86
+
87
+
88
+
89
+ // 今回の衝突で加わった法線方向の力積の総和を求める
90
+
91
+ var impulse = Vector2.zero;
92
+
93
+
94
+
95
+ foreach (var contact in coll.contacts)
96
+
97
+ {
98
+
99
+ impulse += contact.normalImpulse * contact.normal;
100
+
101
+ }
102
+
103
+
104
+
105
+ // sharedMaterialのbouncinessを変更し、colliderのenabledを切り替えて変更を適用させる
106
+
107
+ material.bounciness = nextBounciness;
108
+
109
+ this.collider.enabled = false;
110
+
111
+ this.collider.enabled = true;
112
+
113
+
114
+
115
+ // 上記のみでは現在の跳ね返りには新しい反発係数が適用されないので、差分を補償する追加の力積をrigidbodyに加える
116
+
117
+ var extraImpulse = ((nextBounciness - currentBounciness) / (1.0f + currentBounciness)) * impulse;
118
+
119
+
120
+
121
+ this.rigidbody.AddForce(extraImpulse, ForceMode2D.Impulse);
122
+
123
+ }
124
+
125
+ }
126
+
127
+ ```