回答編集履歴

1

垂直な崖を登れてしまう現象に対する修正案を追記

2021/05/05 21:49

投稿

Bongo
Bongo

スコア10811

test CHANGED
@@ -163,3 +163,129 @@
163
163
 
164
164
 
165
165
  ![図](3cf3f33b832a67fafaec2ddf9609a44d.gif)
166
+
167
+
168
+
169
+ #追記
170
+
171
+
172
+
173
+ なるほど、ほぼ垂直に切り立った崖に突っ込んだ場合は...
174
+
175
+
176
+
177
+ - 崖のふもとにいる時は、レイキャスト時に足元の平坦な地面が検出され、傾いていないので移動力が制限されない。つまり条件的にご質問者さんが最初に試した時の80°の斜面と同じになって、崖のわずかな傾きによって少しずつ登れてしまう。
178
+
179
+ - 少しずつ崖を登っていって平坦部分から浮かんでいき、レイキャストがヒットしなくなると宙に浮いているのと同じ状況になる。空中にいる時に移動入力があった場合には移動力を制限しないようにしたため、やはり引き続き崖を登れてしまう。
180
+
181
+
182
+
183
+ といった状態になってしまったようですね。
184
+
185
+ 代案として、まずスクリプト内に下記のように`impulseSum`および`OnCollisionStay`を追加し...
186
+
187
+
188
+
189
+ ```lang-csharp
190
+
191
+ // 他のコライダーとの衝突によって受けた力積を
192
+
193
+ // OnCollisionStay内で足し合わせていくようにしました
194
+
195
+ Vector3 impulseSum;
196
+
197
+
198
+
199
+ void OnCollisionStay(Collision other)
200
+
201
+ {
202
+
203
+ impulseSum += other.impulse;
204
+
205
+ }
206
+
207
+ ```
208
+
209
+
210
+
211
+ さらに最初の回答で提示しました移動部分を下記のように変更し、足の下へのレイキャストで法線を得る代わりに、衝突で受ける力積を法線と見なして傾き判定を行うというのはどうでしょうか。
212
+
213
+
214
+
215
+ ```lang-csharp
216
+
217
+ // velocityの倍率を表す変数
218
+
219
+ float velocityMultiplier = 1.0f;
220
+
221
+
222
+
223
+ // レイキャストに代わって、力積の総和の大きさで接地しているか
224
+
225
+ // (あるいは壁に触れているか)を判定し...
226
+
227
+ float impulseSumMagnitude = impulseSum.magnitude;
228
+
229
+ if (impulseSumMagnitude > 0.01f)
230
+
231
+ {
232
+
233
+ // 力積の方向を法線と見なすことにしました
234
+
235
+ Vector3 normal = impulseSum / impulseSumMagnitude;
236
+
237
+
238
+
239
+ if (Mathf.Approximately(normal.y, 0.0f))
240
+
241
+ {
242
+
243
+ // もし足場が垂直なら、velocityMultiplierを0倍に設定
244
+
245
+ velocityMultiplier = 0.0f;
246
+
247
+ }
248
+
249
+ else
250
+
251
+ {
252
+
253
+ // 傾き具合を調べ、velocityMultiplierを調整
254
+
255
+ Vector2 normalXZ = new Vector2(normal.x, normal.z);
256
+
257
+ Vector2 velocityXZ = new Vector2(velocity.x, velocity.z);
258
+
259
+ float slopeAngle = Mathf.Rad2Deg * Mathf.Atan2(-Vector2.Dot(normalXZ, velocityXZ) / normal.y, velocityXZ.magnitude);
260
+
261
+ float t = Mathf.Clamp01((slopeAngle - slopeLowerThreshold) / (slopeUpperThreshold - slopeLowerThreshold));
262
+
263
+ velocityMultiplier = 1.0f - (t * t * (3.0f - (t * 2.0f)));
264
+
265
+ }
266
+
267
+ }
268
+
269
+
270
+
271
+ // 判定の後は、impulseSumをゼロにリセットしておきます
272
+
273
+ impulseSum = Vector3.zero;
274
+
275
+
276
+
277
+ // velocityの大きさを調整
278
+
279
+ velocity *= velocityMultiplier;
280
+
281
+
282
+
283
+ // 上下のキー入力でキャラクターを移動させる
284
+
285
+ transform.localPosition += velocity * Time.fixedDeltaTime;
286
+
287
+ ```
288
+
289
+
290
+
291
+ ![図2](c9195bab7724ddcf05de1841af1e3334.gif)