2017-09-10 15 views
2

私はユニティでシンプルな2Dのゲームを開発していて、衝突を扱うとき、私はこの問題に遭遇してきました。私は木とプレイヤーという2つのオブジェクトを持っています。ツリーは動かず、いくつかのスプライトとポリゴンコライダーによって表現されます。プレイヤーはカスタムスクリプト(キャラクターコントローラーではない)を使用して移動し、キネマティックリッジドボディとポリゴンコライダーが接続されています。2Dオブジェクトコリソンユニティ

私の意図した動作では、ツリーで「衝突」にプレーヤーのためになると、それによってブロックされ、そのオブジェクトのどれも移動することはできませんでした。しかし、これを行う簡単な方法ではないようです。 「静的」または検出されない衝突で「動的」結果とツリーのRidgidBodyコンポーネントを設定

。私はプレーヤーを「ダイナミック」リジッドボディにすることを検討しましたが、unity docsは、ダイナミック剛体をトランスフォームコンポーネントで移動しないようにしてください。これは現在のシステムの仕組みです。さらに、ダイナミックに設定すると、理由なくプレーヤがフリーズしたり、プレーヤーオブジェクトに物理が適用されないため意図しない振る舞いになります。これは、ダイナミックの悪い使用例のようです。私はこれについて間違っているかもしれません。

コライダーのイベントがトリガされたとき、私はおそらく何とかプレーヤーの位置をロックするためのスクリプトを使用することができますが、これは非常にハックようです。誰もこれを処理する方法についていくつかの洞察を提供することはできますか?

+1

あなたは、私がダイナミックにボディタイプを設定することで、この問題を解決して、剛体を使用しているプレイヤー –

答えて

0

まあ、明らかに2D colissionsは少しバギーです。この問題を回避するためのアプローチがいくつかあります。

using UnityEngine; 
using System.Collections; 

public abstract class MovingObjects : MonoBehaviour { 

    public float moveTime = 0.1f; 
    public LayerMask blockingLayer; 

    private BoxCollider2D boxCollider; 
    private Rigidbody2D rb2D; 
    private float inverseMoveTime; 

    protected virtual void Start() 
    { 
     boxCollider = GetComponent<BoxCollider2D>(); 
     rb2D = GetComponent <Rigidbody2D>(); 
     inverseMoveTime = 1f/moveTime; 

    } 


    protected IEnumerator SmoothMovement(Vector3 end) 
    { 
     float sqrRemaininDistance = (transform.position - end).sqrMagnitude; 

     while (sqrRemaininDistance > float.Epsilon) { 

      Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime*Time.deltaTime); 

      rb2D.MovePosition(newPosition); 
      sqrRemaininDistance = (transform.position - end).sqrMagnitude; 

      yield return null; 
     } 
    } 

    protected bool Move(int xDir, int yDir, out RaycastHit2D hit) 
    { 
     Vector2 start = transform.position; 
     Vector2 end = start + new Vector2 (xDir, yDir); 

     boxCollider.enabled = false; 

     hit = Physics2D.Linecast (start, end, blockingLayer); 

     boxCollider.enabled = true; 

     if (hit.transform == null) { 

      StartCoroutine(SmoothMovement(end)); 
      return true; 
     } 

     return false; 
    } 

    protected virtual void AttemptMove<T>(int xDir, int yDir) 
          where T : Component 
    { 

     RaycastHit2D hit; 
     bool canMove = Move (xDir, yDir, out hit); 

     if (hit.transform == null) 
      return; 


     Debug.Log ("Something hit", gameObject); 

     T hitComponent = hit.transform.GetComponent<T>(); 

     if (!canMove && hitComponent != null) 
      onCantMove (hitComponent); 


    } 

    protected abstract void onCantMove<T>(T component) 
         where T: Component; 

} 

このスクリプトは、のチュートリアルに属し:代わりにコライダーに頼るので基本的には、プレイヤーから継承

using UnityEngine; 
using System.Collections; 
using UnityEngine.UI; 

public class Player : MovingObjects { 

    protected override void AttemptMove<T> (int xDir, int yDir) 
    { 
     base.AttemptMove<T> (xDir, yDir); 
     RaycastHit2D hit;  
    } 
    protected override void onCantMove<T>(T component) 
    { 
     Wall hitwall = component as Wall; 
     hitwall.DamageWall (wallDamage);   
    } 

    // Update is called once per frame 
    void Update() { 

     int horizontal = 0; 
     int vertical = 0; 

     horizontal = (int)Input.GetAxisRaw ("Horizontal"); 
     vertical = (int)Input.GetAxisRaw ("Vertical"); 

     if (horizontal != 0) 
      vertical = 0; 

     if (horizontal != 0 || vertical != 0) 
      AttemptMove<Wall> (horizontal, vertical); 
    } 
} 

を移動しようとしている障害物があるかどうかを確認するためにレイキャストを使用していますoficial UnityウェブサイトRogueと呼ばれる2Dゲーム。ここでは、ちょうどあなたが似た何かをすることを計画している場合、リンクされています

https://unity3d.com/es/learn/tutorials/projects/2d-roguelike-tutorial

+1

を移動するために使用しているスクリプトを追加します。 .MovePositionをVector2と組み合わせて、プレーヤーの動きを処理します。あなたの答えをありがとう。 – Jeremy

+0

お受け取りいただきありがとうございます –