So, ich arbeite wieder daran. Es ist echt unglaublich, man findet keine vernünftige Lösung im Internet. Aber ich mache Fortschritte:
Code: Alles auswählen
// --------------------- Initialisierung: -------------------------------
//the shape
m_CollisionShape.reset(new btCapsuleShapeZ(0.5, 0.5));//height=1.7-2*r
m_CollisionShapeOffset=vec3(0, 0, 1);
//the collision object
m_CollisionObject.reset(new btRigidBody(1, this, m_CollisionShape.get()));
m_CollisionObject->setUserPointer(&m_CollisionObjectData);
m_CollisionObject->setActivationState(DISABLE_DEACTIVATION);
m_CollisionObject->setFriction(1);
m_CollisionObject->setAngularFactor(0);
//------------------Motion State:-----------------------------------
void EgoController::getWorldTransform(btTransform& worldTrans) const
{
//set the initial values
auto Pos=m_Entity->GetPosition()+m_CollisionShapeOffset;
worldTrans.setOrigin(asBtVec(Pos));
worldTrans.setRotation(btQuaternion(0, 0, m_Entity->GetDirection()*PI/180.0f));
}
void EgoController::setWorldTransform(const btTransform& worldTrans)
{
m_Entity->SetPosition(asGlmVec(worldTrans.getOrigin())-m_CollisionShapeOffset);
}
// ------------------------- Controll -------------------------------
void EgoController::Update(float Time)
{
static int x, y;
static int lx, ly;
glfwGetMousePos(&x, &y);
vec3 Movement;
//------ Walk ------
float MoveSpeed=6;
if(glfwGetKey(GLFW_KEY_LSHIFT))
MoveSpeed=12;
if(glfwGetKey('W'))
{
float Dir=(m_Entity->GetDirection()+90)*PI/180.f;
Movement+=vec3(cosf(Dir), sinf(Dir), 0)*MoveSpeed;
}
if(glfwGetKey('S'))
{
float Dir=(m_Entity->GetDirection()+270)*PI/180.f;
Movement+=vec3(cosf(Dir), sinf(Dir), 0)*MoveSpeed;
}
if(glfwGetKey('A'))
{
float Dir=(m_Entity->GetDirection()+180)*PI/180.f;
Movement+=vec3(cosf(Dir), sinf(Dir), 0)*MoveSpeed;
}
if(glfwGetKey('D'))
{
float Dir=(m_Entity->GetDirection()+0)*PI/180.f;
Movement+=vec3(cosf(Dir), sinf(Dir), 0)*MoveSpeed;
}
if(glfwGetKey(GLFW_KEY_SPACE))
{
auto Velocity=m_CollisionObject->getLinearVelocity();
if(abs(Velocity.z())<0.1)
m_CollisionObject->applyCentralImpulse(btVector3(0, 0, 10));
}
if(true)//check if we are on the ground
{
auto Velocity=m_CollisionObject->getLinearVelocity();
m_CollisionObject->setLinearVelocity(btVector3(0, 0, Velocity.z()));
}
//look:
if(glfwGetMouseButton(GLFW_MOUSE_BUTTON_1))
{
const float MouseSensitivity=0.8f;
m_Entity->SetDirection(m_Entity->GetDirection()+(lx-x)*MouseSensitivity);
m_PitchAngle+=(ly-y)*MouseSensitivity;
if(m_PitchAngle< -89)
m_PitchAngle=-89;
if(m_PitchAngle> 89)
m_PitchAngle=89;
}
m_CollisionObject->applyCentralImpulse(asBtVec(Movement));
glfwGetMousePos(&lx, &ly);
}
Hier mal, was ich tue:
Der Grundkörper des Spielers ist eine Kapsel. Da sie unten rund ist, gleitet sie leichter über Unebenheiten.
Mit
setAngularFactor(0) verhindert man, dass sie umfällt. (Man war das bescheuert, als ich das erste mal das Spiel startete, und mein Charakter einfach umkippte...).
setActivationState(DISABLE_DEACTIVATION) ist wichtig, da Bullet sonst das Objekt beim ersten Stillstand deaktiviert. Danach kannst du Kräfte anwenden wie du willst, das Objekt wird sich nicht mehr bewegen.
Die Masse setze ich auf 1, damit sämtliche "applyImpulse" Aufrufe direkt die Nette-Geschwindigkeit angeben. Aber man muss darauf achten, dass man mit einem 1kg schweren Menschen keine 50kg schwere Objekte mehr schieben kann.
Die Steuerung ansich soll sehr direkt sein, also keine Beschleunigung oder dergleichen haben. Mein Ansatz ist der, am Anfang jeder Bewegung die Geschwindigkeit auf 0 zu setzen (außer die Z-Achse, das ist meine Hoch-Achse und Objekte sollen ja ganz normal runter fallen können). Ist dann eine Taste gedrückt, erzeuge ich den entsprechenden Impuls (und keine Kraft, es soll ja direkt wirken). Dieser würde natürlich in jedem Frame auf die aktuelle Geschwindigkeit addiert werden, aber davor wird sie ja immer auf 0 gesetzt. Effektiv laufe ich also genau dann, wenn die Taste gedrückt ist.
Das Springen ist sehr provisorisch. Eigentlich bräuchte ich eine komplette "Objekt steht auf Boden" Prüfung, aber die Abfrage der Z Geschwindigkeit funktioniert auch so halbwegs.
Weitere Dinge die ich unbedingt einbauen möchte: Die gesamte Steuerung wirkt nur, solange der Spieler am Boden ist. Das hieße. dass man sich in der Luft nicht mehr bewegen könnte. Dafür könnte man den Spieler aber auch wirklich physikalisch simuliert durch die Luft fliegen lassen.
Ich habe auch mit der Reibung experimentiert, und sie sehr hoch gesetzt, damit der Spieler bei einer normal beschleunigten Bewegung auf dem Boden schnell stehen bleibt. Aber das hat sich nie gut angefühlt.
Insgesamt ist die Steuerung so jetzt schon fast gut. Sie ist sehr direkt (eine leichte Dämpfung wäre hier und da sicherlich gut, mal sehen, wie ich das noch hinbekomme), aber man gleitet auch schön an Objekten wie Wänden entlang. Außerdem kommt man über Bodenunebenheiten und Treppenlaufen klappt sogar auch.
Das zweiteilige Modell mit der Feder klingt auch interessant, und man könnte sicherlich auch mit anderen Kollisionsformen experimentieren, um zu sehen, wie man damit über Bodenunebenheiten kommt. Aber zumindest habe ich jetzt etwas, mit dem ich so halbwegs vernünftig durch mein Level laufen kann.
Achja: Ducken, Leiter, Vorsprünge hochziehen - das wären alles so Dinge über die man sich auch noch Gedanken machen sollte.