2015-11-20 7 views
6

Obecnie pracuję nad grą Air Hockey w Unity3d. Problem, który mam, polega na tym, że kiedy gracz próbuje zbyt szybko trafić krążek, gracz kończy przechodzenie przez krążek i dlatego nie ma kolizji. Gra działa idealnie zgodnie z oczekiwaniami, jeśli gracz pozostaje nieruchomy, a krążek uderza w gracza lub gracz uderza w krążek w wolnym tempie.Gra w cymbergaja - gracz nietoperz przechodzi przez krążek, jeśli porusza się zbyt szybko.

Odtwarzacz ma sztywną bryłę za pomocą ciągłej detekcji kolizji przy użyciu zderzacza kapsułkowego. Krążek ma również sztywny korpus z ciągłą dynamiczną detekcją kolizji i zderzaczem siatkowym z wypukłym.

Próbowałem ustawić ustalony czas na 0.01, ale to nie miało żadnego efektu. Oto scenariusz dla ruchu gracza:

void ObjectFollowCursor() 
{ 
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 
    Vector3 point = ray.origin + (ray.direction * distance); 

    Vector3 temp = point; 
    temp.y = 0.2f; // limits player on y axis 

    cursorObject.position = temp; 
} 

i tutaj jest kod na krążek, gdy zderza się z odtwarzacza:

// If puck hits player 
if(collision.gameObject.tag == "Player") 
{ 
    Vector3 forceVec = this.GetComponent<Rigidbody>().velocity.normalized * hitForce; 
    rb.AddForce(forceVec, ForceMode.Impulse); 
    Debug.Log ("Player Hit"); 
} 

Każda pomoc będzie mile widziane. Dzięki.

+0

Skąd czerpiesz zmienną odległości? –

+0

po prostu służy do ograniczenia dystansu, jaki gracz może przenieść na stole. – GraMas

Odpowiedz

2

Miałeś rację spróbować ciągłego wykrywania kolizji (CCD). Istnieją pewne ograniczenia (szczególnie w tym przypadku, gdy chcemy używać CCD z dwoma ruchomymi obiektami, a nie z jednym ruchomym obiektem i jednym statycznym obiektem), ale jest on przeznaczony do tego rodzaju scenariusza. The Rigidbody documentation idzie do tych ograniczeń:

Ustaw tryb wykrywania kolizji ciągłemu aby zapobiec bryła sztywna z przejazdem dowolnym statyczne (czyli non-bryła sztywna) MeshColliders. Ustaw go na Ciągły dynamiczny, aby zapobiec przechodzeniu przez sztywne nadwozie przez inne obsługiwane mechanizmy sztywne z trybem wykrywania kolizji ustawionym na Ciągły lub Ciągły dynamiczny. Ciągłe wykrywanie kolizji jest obsługiwane dla Box-, Sphere- i CapsuleColliders.

Podsumowując, zarówno krążek i wiosła muszą być ustawione na ciągły dynamiczny i oba muszą być skrzynkowym, Sphere- lub kapsułka collidery. Jeśli możesz sprawić, by te ograniczenia działały w twojej grze, powinieneś być w stanie uzyskać ciągłe wykrywanie kolizji bez samodzielnego pisania.


Wzmiankę o CCD Jedności, która nosi powtarzając:

Należy pamiętać, że ciągłe wykrywanie kolizji ma służyć jako zabezpieczenie złapać kolizji w przypadkach, gdy obiekty w przeciwnym wypadku przechodzą przez siebie, ale nie przyniesie wyników dokładnych pod względem fizycznym, więc możesz rozważyć obniżenie ustalonej wartości kroku kroku o czas w inspektorze TimeManager, aby dokładniej symulować symulację, jeśli napotkasz problemy z szybko poruszającymi się obiektami.

Ale ponieważ ręcznie określasz reakcję kolizji, może to nie być problem.

+0

No dobra, nie zdawałem sobie sprawy, że ciągłe wykrywanie kolizji nie obsługuje siatki zderzacza. Gracz jest zderzaczem kuli i próbowałem sprawić, by krążek działał dobrze jako zderzacz kuli, ale po prostu nie działa tak, jak powinien. Będę się ciągle rozmyślać i zobaczę, czy uda mi się sprawić, by działał tak, jak tego chcę. Dzięki za pomoc. – GraMas

+0

W końcu udało mi się przekonać zderzacz kuli do pracy tak, jakbym chciała to zrobić z krążkiem. Następnie zmieniłem ustalony czas na 0,01 z 0,02, a wyniki były znacznie lepsze, ale nadal nie były doskonałe. Nie używam już skryptu "DontGoThroughThings". – GraMas

+0

@gramarcgt Cool! Jedną rzeczą, którą możesz spróbować zdobyć na to, co robi CCD, jest podniesienie czasu o * lot * i obniżenie prędkości krążka proporcjonalnie. Możesz także spróbować usunąć niestandardowy impuls, aby zobaczyć, jak wpływa to na wyniki kolizji. – 31eee384

5

Problem, który masz nazywane "tunelowaniem".

Dzieje się tak, ponieważ obiekt porusza się z dużą prędkością iw tej konkretnej ramie kolizja nie jest wykrywana. W ramce n piłka znajduje się tuż przed nietoperzem, ale gdy obliczana jest ramka n+1, piłka przesunęła się za nietoperzem, co "całkowicie" spowodowało "brak" kolizji.

Jest to powszechny problem, ale istnieją rozwiązania.

Polecam zapoznać się z tym skryptem i spróbować zaimplementować w swojej grze.

To nie jest mój kod: ŹRÓDŁO: http://wiki.unity3d.com/index.php?title=DontGoThroughThings

using UnityEngine; 
using System.Collections; 

public class DontGoThroughThings : MonoBehaviour 
{ 
     // Careful when setting this to true - it might cause double 
     // events to be fired - but it won't pass through the trigger 
     public bool sendTriggerMessage = false; 

    public LayerMask layerMask = -1; //make sure we aren't in this layer 
    public float skinWidth = 0.1f; //probably doesn't need to be changed 

    private float minimumExtent; 
    private float partialExtent; 
    private float sqrMinimumExtent; 
    private Vector3 previousPosition; 
    private Rigidbody myRigidbody; 
    private Collider myCollider; 

    //initialize values 
    void Start() 
    { 
     myRigidbody = GetComponent<Rigidbody>(); 
     myCollider = GetComponent<Collider>(); 
     previousPosition = myRigidbody.position; 
     minimumExtent = Mathf.Min(Mathf.Min(myCollider.bounds.extents.x, myCollider.bounds.extents.y), myCollider.bounds.extents.z); 
     partialExtent = minimumExtent * (1.0f - skinWidth); 
     sqrMinimumExtent = minimumExtent * minimumExtent; 
    } 

    void FixedUpdate() 
    { 
     //have we moved more than our minimum extent? 
     Vector3 movementThisStep = myRigidbody.position - previousPosition; 
     float movementSqrMagnitude = movementThisStep.sqrMagnitude; 

     if (movementSqrMagnitude > sqrMinimumExtent) 
     { 
      float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude); 
      RaycastHit hitInfo; 

      //check for obstructions we might have missed 
      if (Physics.Raycast(previousPosition, movementThisStep, out hitInfo, movementMagnitude, layerMask.value)) 
       { 
       if (!hitInfo.collider) 
        return; 

       if (hitInfo.collider.isTrigger) 
        hitInfo.collider.SendMessage("OnTriggerEnter", myCollider); 

       if (!hitInfo.collider.isTrigger) 
        myRigidbody.position = hitInfo.point - (movementThisStep/movementMagnitude) * partialExtent; 

       } 
     } 

     previousPosition = myRigidbody.position; 
    } 
} 
+0

Dziękuję za to, używam go teraz, zdecydowanie nie jest doskonały, ale znacznie zmniejszył problem. – GraMas