2017-04-03 4 views
0

Ich bin jetzt irgendwie mit meiner grundlegenden Voxel-Physik fest. Es ist sehr, sehr abgehackt und ich bin ziemlich sicher, dass meine Mathe irgendwo gebrochen ist, aber mal sehen, was Sie zu sagen haben:Kollisionserkennung in Voxel-Welt

// SOMEWHERE AT CLASS LEVEL (so not being reinstantiated every frame, but persisted instead!) 
glm::vec3 oldPos; 

// ACTUAL IMPL 
glm::vec3 distanceToGravityCenter = 
     this->entity->getPosition() - 
     ((this->entity->getPosition() - gravityCenter) * 0.005d); // TODO multiply by time 

if (!entity->grounded) { 
    glm::vec3 entityPosition = entity->getPosition(); 

    if (getBlock(floorf(entityPosition.x), floorf(entityPosition.y), floorf(entityPosition.z))) { 
     glm::vec3 dir = entityPosition - oldPos; // Actually no need to normalize as we check for lesser, bigger or equal to 0 

     std::cout << "falling dir: " << glm::to_string(dir) << std::endl; 

     // Calculate offset (where to put after hit) 
     int x = dir.x; 
     int y = dir.y; 
     int z = dir.z; 

     if (dir.x >= 0) { 
      x = -1; 
     } else if (dir.x < 0) { 
      x = 1; 
     } 

     if (dir.y >= 0) { 
      y = -1; 
     } else if (dir.y < 0) { 
      y = 1; 
     } 

     if (dir.z >= 0) { 
      z = -1; 
     } else if (dir.z < 0) { 
      z = 1; 
     } 

     glm::vec3 newPos = oldPos + glm::vec3(x, y, z); 
     this->entity->setPosition(newPos); 
     entity->grounded = true; // If some update happens, grounded needs to be changed 
    } else { 
     oldPos = entity->getPosition(); 
     this->entity->setPosition(distanceToGravityCenter); 
    } 
} 

Grundidee von entityt welcher Richtung zu bestimmen war, würde die Oberfläche treffen und dann einfach positionieren eine "Einheit" zurück in diese Richtung. Aber offensichtlich mache ich etwas falsch, denn das wird die Entity immer wieder dorthin zurückbringen, wo sie herkam, und sie effektiv am Spawn-Punkt halten.

Auch das könnte wahrscheinlich viel einfacher sein und ich überlege es.

+1

'if (dir.x> = 0) {x = -1; } if (dir.x <0) {x = 1; } '- das scheint mir ziemlich nutzlos zu sein ...' x 'wird immer' 1 '. Meintest du "else if"? [Bearbeiten] Dies würde das Verhalten verursachen, das du beschrieben hast, also werde ich eine Antwort geben. – CompuChip

+0

@CompuChip Natürlich ist ein idiotischer Fehler weg, wie viele andere lauern da drin? Es ist nicht das einzige Problem, es ist immer noch sehr, sehr abgehackt. – Sorona

Antwort

1

Wie @CompuChip bereits darauf hingewiesen, Ihre ifs könnte weiter vereinfacht werden.

Aber was noch wichtiger ist ein logisches Problem, das die „choppiness“ erklären würden Sie beschreiben (leider Sie alle Aufnahmen nicht vorsah, so ist dies meine beste Vermutung)

Aus dem Code, den Sie geschrieben:

Zuerst prüfen Sie, ob das Objekt geerdet ist. Wenn dies der Fall ist, prüfen Sie weiter, ob es eine Kollision gibt, und zuletzt, falls nicht, legen Sie die Position fest.

Sie müssen das ein wenig invertieren.

  1. Speichern alte Position
  2. Überprüfen Sie, ob geerdet
  3. die Position bereits auf das neue Set!
  4. Kollisionserkennung durchführen
  5. Auf alte Position zurücksetzen WENN Sie eine Kollision registriert haben!

Also im Grunde:

glm::vec3 distanceToGravityCenter = 
     this->entity->getPosition() - 
     ((this->entity->getPosition() - gravityCenter) * 0.005d); // TODO multiply by time 

oldPos = entity->getPosition(); // 1. 

if (!entity->grounded) { // 2. 
    this->fallingStar->setPosition(distanceToGravityPoint); // 3 

    glm::vec3 entityPosition = entity->getPosition(); 

    if (getBlock(floorf(entityPosition.x), floorf(entityPosition.y), floorf(entityPosition.z))) { // 4, 5 
     this->entity->setPosition(oldPos); 
     entity->grounded = true; // If some update happens, grounded needs to be changed 
    } 
} 

Dies sollten Sie :)

Ich möchte erarbeiten ein bisschen mehr erhalten begonnen:

Wenn Sie Kollision zunächst prüfen und dann setzen Sie Position Erstellen Sie eine "Endlosschleife" bei der ersten Kollision/dem ersten Treffer, wenn Sie kollidieren, und wenn es eine Kollision gibt (die es gibt), kehren Sie zur alten Position zurück. Im Grunde werden Sie nur durch mathematische Ungenauigkeiten bewegt, da Sie bei jedem Check auf die alte Position zurückgesetzt werden.

1

Betrachten Sie die if -Aussagen für einen Ihrer Koordinaten:

if (dir.x >= 0) { 
    x = -1; 
} 

if (dir.x < 0) { 
    x = 1; 
} 

dass dir.x < 0 Angenommen. Dann wird überspringen Sie den ersten if, geben Sie das zweite und x wird auf 1 Wenn dir.x >= 0 eingestellt werden, wird geben Sie die erste if und x wird -1 eingestellt werden. Jetzt ist x < 0 wahr, also werden Sie auch die zweite if eingeben, und x wird wieder auf 1 gesetzt.

Wahrscheinlich möchten Sie entweder x auf 1 oder -1 setzen, abhängig von dir.x. Sie sollten nur die zweite if ausgeführt wird, wenn der erste nicht eingegeben wurde, so müssen Sie ein else if:

if (dir.x >= 0) { 
    x = -1; 
} else if (dir.x < 0) { 
    x = 1; 
} 

die kondensiert werden können, wenn Sie also bitte, in

x = (dir.x >= 0) ? -1 : 1; 
+0

Danke, sehr guter Fang! Immer noch sehr, sehr abgehackt! – Sorona

+0

Vielleicht ist mein "Bodenbelag" auch falsch? – Sorona