Fix some physics problems between player and grabbed objects

This commit is contained in:
James Lambert 2023-02-12 21:59:30 -07:00
parent 1661eaf914
commit d88499d6ca
8 changed files with 75 additions and 33 deletions

View file

@ -84,6 +84,10 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
## Current TODO list ## Current TODO list
- [ ] fix chell animation problem
- [ ] first portal wall
- [ ] sound effects for ball
--------------------------------------------------------
- [ ] Skips audio sometimes - [ ] Skips audio sometimes
- [ ] Portal not rending recursively sometimes - [ ] Portal not rending recursively sometimes
- [ ] Passing into a ceiling portal can sometimes mess with the player rotation - [ ] Passing into a ceiling portal can sometimes mess with the player rotation
@ -92,7 +96,9 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
- [ ] Presort portal gun polygon order - [ ] Presort portal gun polygon order
- [ ] Signage should not always be on - [ ] Signage should not always be on
- [ ] Camera shake - [ ] Camera shake
- [x] Release grabbed objects when line of sight is cut - [x] the cube bounces the player
- [x] break constraint after large distance
- [x] prevent objects from pushing the player around
- [x] Stop looping sounds betwen levels - [x] Stop looping sounds betwen levels
- [x] red light district - [x] red light district
- [x] burn marks - [x] burn marks

View file

@ -195,7 +195,7 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
struct RigidBody* bodyA = cs->shapeA->body; struct RigidBody* bodyA = cs->shapeA->body;
struct RigidBody* bodyB = cs->shapeB->body; struct RigidBody* bodyB = cs->shapeB->body;
if (bodyA) { if (bodyA && !(bodyA->flags & RigidBodyIsKinematic)) {
vA = &bodyA->velocity; vA = &bodyA->velocity;
wA = &bodyA->angularVelocity; wA = &bodyA->angularVelocity;
} else { } else {
@ -203,7 +203,7 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
wA = NULL; wA = NULL;
} }
if (bodyB) { if (bodyB && !(bodyB->flags & RigidBodyIsKinematic)) {
vB = &bodyB->velocity; vB = &bodyB->velocity;
wB = &bodyB->angularVelocity; wB = &bodyB->angularVelocity;
} else { } else {
@ -222,11 +222,11 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
vector3Cross(&c->contactBWorld, &cs->normal, &rbCn); vector3Cross(&c->contactBWorld, &cs->normal, &rbCn);
float nm = 0; float nm = 0;
if (bodyA) { if (vA) {
nm += bodyA->massInv; nm += bodyA->massInv;
} }
if (bodyB) { if (vB) {
nm += bodyB->massInv; nm += bodyB->massInv;
} }
@ -234,11 +234,11 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
tm[ 0 ] = nm; tm[ 0 ] = nm;
tm[ 1 ] = nm; tm[ 1 ] = nm;
if (bodyA) { if (vA) {
nm += bodyA->momentOfInertiaInv * vector3MagSqrd(&raCn); nm += bodyA->momentOfInertiaInv * vector3MagSqrd(&raCn);
} }
if (bodyB) { if (vB) {
nm += bodyB->momentOfInertiaInv * vector3MagSqrd(&rbCn); nm += bodyB->momentOfInertiaInv * vector3MagSqrd(&rbCn);
} }
@ -251,10 +251,10 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
struct Vector3 rbCt; struct Vector3 rbCt;
vector3Cross(&cs->tangentVectors[ i ], &c->contactBWorld, &rbCt); vector3Cross(&cs->tangentVectors[ i ], &c->contactBWorld, &rbCt);
if (bodyA) { if (vA) {
tm[ i ] += bodyA->momentOfInertiaInv * vector3MagSqrd(&raCt); tm[ i ] += bodyA->momentOfInertiaInv * vector3MagSqrd(&raCt);
} }
if (bodyB) { if (vB) {
tm[ i ] += bodyB->momentOfInertiaInv * vector3MagSqrd(&rbCt); tm[ i ] += bodyB->momentOfInertiaInv * vector3MagSqrd(&rbCt);
} }
@ -276,13 +276,13 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
struct Vector3 w; struct Vector3 w;
if (bodyA) { if (vA) {
vector3AddScaled(vA, &P, -bodyA->massInv, vA); vector3AddScaled(vA, &P, -bodyA->massInv, vA);
vector3Cross(&c->contactAWorld, &P, &w); vector3Cross(&c->contactAWorld, &P, &w);
vector3AddScaled(wA, &w, -bodyA->momentOfInertiaInv, wA); vector3AddScaled(wA, &w, -bodyA->momentOfInertiaInv, wA);
} }
if (bodyB) { if (vB) {
vector3AddScaled(vB, &P, bodyB->massInv, vB); vector3AddScaled(vB, &P, bodyB->massInv, vB);
vector3Cross(&c->contactBWorld, &P, &w); vector3Cross(&c->contactBWorld, &P, &w);
vector3AddScaled(wB, &w, bodyB->momentOfInertiaInv, wB); vector3AddScaled(wB, &w, bodyB->momentOfInertiaInv, wB);
@ -314,11 +314,31 @@ void contactSolverPreSolve(struct ContactSolver* contactSolver) {
} }
} }
#define BREAK_DISTANCE 0.5f
void contactSolverIterateConstraints(struct ContactSolver* contactSolver) { void contactSolverIterateConstraints(struct ContactSolver* contactSolver) {
struct PointConstraint* curr = contactSolver->firstPointConstraint; struct PointConstraint* curr = contactSolver->firstPointConstraint;
struct PointConstraint* prev = NULL;
while (curr) { while (curr) {
pointConstraintMoveToPoint(curr->object, &curr->targetPos, curr->maxPosImpulse); if (!pointConstraintMoveToPoint(curr->object, &curr->targetPos, curr->maxPosImpulse)) {
struct PointConstraint* next = curr->nextConstraint;
if (prev) {
prev->nextConstraint = next;
} else {
contactSolver->firstPointConstraint = next;
}
curr->nextConstraint = NULL;
curr->object = NULL;
curr = next;
continue;
}
pointConstraintRotateTo(curr->object->body, &curr->targetRot, curr->maxRotImpulse); pointConstraintRotateTo(curr->object->body, &curr->targetRot, curr->maxRotImpulse);
curr = curr->nextConstraint; curr = curr->nextConstraint;
@ -343,7 +363,7 @@ void contactSolverIterate(struct ContactSolver* contactSolver) {
struct RigidBody* bodyA = cs->shapeA->body; struct RigidBody* bodyA = cs->shapeA->body;
struct RigidBody* bodyB = cs->shapeB->body; struct RigidBody* bodyB = cs->shapeB->body;
if (bodyA) { if (bodyA && !(bodyA->flags & RigidBodyIsKinematic)) {
vA = &bodyA->velocity; vA = &bodyA->velocity;
wA = &bodyA->angularVelocity; wA = &bodyA->angularVelocity;
} else { } else {
@ -351,7 +371,7 @@ void contactSolverIterate(struct ContactSolver* contactSolver) {
wA = NULL; wA = NULL;
} }
if (bodyB) { if (bodyB && !(bodyB->flags & RigidBodyIsKinematic)) {
vB = &bodyB->velocity; vB = &bodyB->velocity;
wB = &bodyB->angularVelocity; wB = &bodyB->angularVelocity;
} else { } else {

View file

@ -2,12 +2,19 @@
#include "../util/time.h" #include "../util/time.h"
void pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse) { #define BREAK_CONSTRAINT_DISTANCE 2.0f
int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse) {
struct RigidBody* rigidBody = object->body; struct RigidBody* rigidBody = object->body;
vector3Sub(worldPoint, &rigidBody->transform.position, &rigidBody->velocity);
struct Vector3 targetVelocity; struct Vector3 targetVelocity;
vector3Scale(&rigidBody->velocity, &targetVelocity, 1.0f / FIXED_DELTA_TIME); vector3Sub(worldPoint, &rigidBody->transform.position, &targetVelocity);
if (vector3MagSqrd(&targetVelocity) > BREAK_CONSTRAINT_DISTANCE * BREAK_CONSTRAINT_DISTANCE) {
return 0;
}
vector3Scale(&targetVelocity, &targetVelocity, 1.0f / FIXED_DELTA_TIME);
struct ContactManifold* contact = contactSolverNextManifold(&gContactSolver, object, NULL); struct ContactManifold* contact = contactSolverNextManifold(&gContactSolver, object, NULL);
@ -38,6 +45,8 @@ void pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3*
} else { } else {
vector3AddScaled(&rigidBody->velocity, &delta, maxImpulse / sqrtf(deltaSqrd), &rigidBody->velocity); vector3AddScaled(&rigidBody->velocity, &delta, maxImpulse / sqrtf(deltaSqrd), &rigidBody->velocity);
} }
return 1;
} }
void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* worldRotation, float maxImpulse) { void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* worldRotation, float maxImpulse) {

View file

@ -16,7 +16,7 @@ struct PointConstraint {
void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse); void pointConstraintInit(struct PointConstraint* constraint, struct CollisionObject* object, float maxPosImpulse, float maxRotImpulse);
void pointConstraintUpdateTarget(struct PointConstraint* constraint, struct Vector3* worldPoint, struct Quaternion* worldRotation); void pointConstraintUpdateTarget(struct PointConstraint* constraint, struct Vector3* worldPoint, struct Quaternion* worldRotation);
void pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse); int pointConstraintMoveToPoint(struct CollisionObject* object, struct Vector3* worldPoint, float maxImpulse);
void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* worldRotation, float maxImpulse); void pointConstraintRotateTo(struct RigidBody* rigidBody, struct Quaternion* worldRotation, float maxImpulse);
#endif #endif

View file

@ -155,15 +155,21 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve
#define JUMP_IMPULSE 2.7f #define JUMP_IMPULSE 2.7f
void playerHandleCollision(struct Player* player) { void playerHandleCollision(struct Player* player) {
struct ContactManifold* contact = contactSolverNextManifold(&gContactSolver, &player->collisionObject, NULL); for (struct ContactManifold* contact = contactSolverNextManifold(&gContactSolver, &player->collisionObject, NULL);
contact;
while (contact) { contact = contactSolverNextManifold(&gContactSolver, &player->collisionObject, contact)
) {
float offset = 0.0f; float offset = 0.0f;
for (int i = 0; i < contact->contactCount; ++i) { for (int i = 0; i < contact->contactCount; ++i) {
struct ContactPoint* contactPoint = &contact->contacts[i]; struct ContactPoint* contactPoint = &contact->contacts[i];
offset = MIN(offset, contactPoint->penetration); offset = MIN(offset, contactPoint->penetration);
} }
if (contact->shapeA == player->grabConstraint.object || contact->shapeB == player->grabConstraint.object) {
// objects being grabbed by the player shouldn't push the player
continue;
}
if (offset != 0.0f) { if (offset != 0.0f) {
vector3AddScaled( vector3AddScaled(
@ -184,12 +190,6 @@ void playerHandleCollision(struct Player* player) {
if (isColliderForBall(contact->shapeA) || isColliderForBall(contact->shapeB)) { if (isColliderForBall(contact->shapeA) || isColliderForBall(contact->shapeB)) {
playerKill(player, 0); playerKill(player, 0);
} }
if (contact->shapeA == player->grabConstraint.object || contact->shapeB == player->grabConstraint.object) {
playerSetGrabbing(player, NULL);
}
contact = contactSolverNextManifold(&gContactSolver, &player->collisionObject, contact);
} }
} }
@ -213,6 +213,12 @@ void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing)
} }
} }
void playerSignalPortalChanged(struct Player* player) {
if (player->grabbingThroughPortal != PLAYER_GRABBING_THROUGH_NOTHING) {
playerSetGrabbing(player, NULL);
}
}
int playerRaycastGrab(struct Player* player, struct RaycastHit* hit) { int playerRaycastGrab(struct Player* player, struct RaycastHit* hit) {
struct Ray ray; struct Ray ray;
@ -306,11 +312,6 @@ void playerUpdateGrabbedObject(struct Player* player) {
pointConstraintUpdateTarget(&player->grabConstraint, &grabPoint, &grabRotation); pointConstraintUpdateTarget(&player->grabConstraint, &grabPoint, &grabRotation);
} }
struct RaycastHit hit;
if (player->grabConstraint.object && !(playerRaycastGrab(player, &hit) || hit.object != player->grabConstraint.object)) {
playerSetGrabbing(player, NULL);
}
} }
#define DEADZONE_SIZE 5 #define DEADZONE_SIZE 5
@ -500,7 +501,11 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
hit.object->flags |= COLLISION_OBJECT_PLAYER_STANDING; hit.object->flags |= COLLISION_OBJECT_PLAYER_STANDING;
player->flags |= PlayerFlagsGrounded; player->flags |= PlayerFlagsGrounded;
if (hit.object->body) { if (hit.object == player->grabConstraint.object) {
playerSetGrabbing(player, NULL);
}
if (hit.object->body && (hit.object->body->flags & RigidBodyIsKinematic)) {
player->anchoredTo = hit.object->body; player->anchoredTo = hit.object->body;
player->lastAnchorPoint = hit.at; player->lastAnchorPoint = hit.at;
transformPointInverseNoScale(&player->anchoredTo->transform, &hit.at, &player->relativeAnchor); transformPointInverseNoScale(&player->anchoredTo->transform, &hit.at, &player->relativeAnchor);

View file

@ -52,5 +52,6 @@ void playerKill(struct Player* player, int isUnderwater);
int playerIsDead(struct Player* player); int playerIsDead(struct Player* player);
void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing); void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing);
void playerSignalPortalChanged(struct Player* player);
#endif #endif

View file

@ -581,6 +581,7 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int transformInde
contactSolverCheckPortalContacts(&gContactSolver, collisionObject); contactSolverCheckPortalContacts(&gContactSolver, collisionObject);
ballBurnFilterOnPortal(&portal->transform, portalIndex); ballBurnFilterOnPortal(&portal->transform, portalIndex);
playerSignalPortalChanged(&scene->player);
return 1; return 1;
} }
} }