C#で自前の物理演算を行って2Dアクションゲームを作っています。
次の画像に示すように、ブロックの角でめりこみが発生してしまいます。
画像はないですが、下からジャンプしてブロックの下側の角にぶつかったときにもめりこみが発生し、ブロックとのめりこみから逃げるようにキャラクターが上方向に勝手に持ち上げられてしまうような現象も起きてしまいました。
コライダーの様子をシーンタブ内で見てみるとコライダーは衝突していないようにも見えるので、なおさら不思議です。
プレイヤーを動かしているコードは次の2つで、ブロックはTilemapを使ってColliderをGridにしています。また、そのうえでCompositeColliderにしております。プレイヤー側はBoxColliderを用いています。
C#
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class KinematicObject : MonoBehaviour 6{ 7 Rigidbody2D rb2d; 8 9 public float minGroundNormalY = 0.65f; 10 public float gravityModifier = 1f; 11 12 protected bool isGrounded; 13 protected Vector2 groundNormal; 14 protected Vector2 targetVelocity; 15 protected Vector2 velocity; 16 protected ContactFilter2D contactFilter; 17 protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16]; 18 protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16); 19 20 protected const float minMoveDistance = 0.001f; 21 protected const float shellRadius = 0.01f; 22 protected const float minVelocityY = -10f; 23 24 void OnEnable() 25 { 26 rb2d = GetComponent<Rigidbody2D>(); 27 } 28 29 void Start() 30 { 31 contactFilter.useTriggers = false; 32 contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer)); 33 contactFilter.useLayerMask = true; 34 35 groundNormal = Vector2.up; 36 } 37 38 void Update() 39 { 40 targetVelocity = Vector2.zero; 41 ComputeVelocity(); 42 } 43 44 protected virtual void ComputeVelocity() 45 { 46 } 47 48 void FixedUpdate() 49 { 50 51 if (!isGrounded && velocity.y < 0) 52 { 53 velocity += 1.25f * gravityModifier * Physics2D.gravity * Time.deltaTime; 54 } 55 else 56 { 57 velocity += gravityModifier * Physics2D.gravity * Time.deltaTime; 58 } 59 60 velocity.x = targetVelocity.x; 61 velocity.y = velocity.y > minVelocityY ? velocity.y : minVelocityY; 62 63 isGrounded = false; 64 65 Vector2 deltaPosition = velocity * Time.deltaTime; 66 67 Vector2 moveAlongGround = new Vector2(groundNormal.y, -groundNormal.x); 68 69 Vector2 move = deltaPosition.x * moveAlongGround; 70 71 PerformMovement(move, false); 72 73 move = Vector2.up * deltaPosition.y; 74 PerformMovement(move, true); 75 76 } 77 78 void PerformMovement(Vector2 move, bool yMovement) 79 { 80 float distance = move.magnitude; 81 82 if (distance > minMoveDistance) 83 { 84 int count = rb2d.Cast(move, contactFilter, hitBuffer, distance + shellRadius); 85 hitBufferList.Clear(); 86 for (int i = 0; i < count; i++) 87 { 88 hitBufferList.Add(hitBuffer[i]); 89 } 90 91 for (int i = 0; i < hitBufferList.Count; i++) 92 { 93 Vector2 currentNormal = hitBufferList[i].normal; 94 if (currentNormal.y > minGroundNormalY) 95 { 96 isGrounded = true; 97 if (yMovement) 98 { 99 groundNormal = currentNormal; 100 currentNormal.x = 0; 101 } 102 } 103 float projection = Vector2.Dot(velocity, currentNormal); 104 if (projection < 0) 105 { 106 velocity = velocity - projection * currentNormal; 107 } 108 float modifiedDistance = hitBufferList[i].distance - shellRadius; 109 distance = modifiedDistance < distance ? modifiedDistance : distance; 110 } 111 } 112 rb2d.position = rb2d.position + distance * move.normalized; 113 } 114}
C#
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class PlayerController : KinematicObject 6{ 7 public float maxSpeed = 5f; 8 public float jumpTakeOffSpeed = 8f; 9 10 private SpriteRenderer spriteRenderer; 11 private Animator animator; 12 13 void Awake() 14 { 15 spriteRenderer = GetComponent<SpriteRenderer>(); 16 animator = GetComponent<Animator>(); 17 } 18 19 protected override void ComputeVelocity() 20 { 21 Vector2 move = Vector2.zero; 22 move.x = Input.GetAxis("Horizontal"); 23 24 if (Input.GetButtonDown("Jump") && isGrounded) 25 { 26 velocity.y = jumpTakeOffSpeed; 27 } 28 else if (Input.GetButtonUp("Jump")) 29 { 30 if (velocity.y > 0) velocity.y = velocity.y * 0.5f; 31 } 32 33 bool flipSprite = (spriteRenderer.flipX ? (move.x > 0.01f) : (move.x < -0.01f)); 34 if(flipSprite){ 35 spriteRenderer.flipX = !spriteRenderer.flipX; 36 } 37 38 targetVelocity = move * maxSpeed; 39 40 animator.SetBool ("isGrounded", isGrounded); 41 animator.SetFloat ("velocityX", Mathf.Abs (velocity.x) / maxSpeed); 42 animator.SetFloat ("velocityY", velocity.y); 43 } 44}
わかりにくいコードでしたら申し訳ありません。以上のような現象の原因がコードにあるのかもわからずに困っております。
原因がわかる方がおりましたら回答をよろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/11/17 14:12
2019/11/17 15:03
2019/11/17 17:21
2019/11/18 06:49
2019/11/25 23:43