Player can hold objects through portals recursively

- fixed a bug where security camera was not updating its PLAYER_STANDING flag
- added a new parameter numPortalsPassed to collisionSceneRaycast to indicate how many portals the raycast went through, if any
- altered all player code involving the grabbingThroughPortal variable
- grabbingThroughPortal is now: 0 if not grabbing through portal, >0 if grabbing through portal 0, <0 if grabbing through portal 1.
- objects are dropped when they are being held through a portal and the player no longer has line of sight to them.
This commit is contained in:
westonCoder 2023-10-31 13:21:49 -05:00
parent 02237dcfb3
commit 4bacaa9607
7 changed files with 54 additions and 28 deletions

View file

@ -423,7 +423,7 @@ int collisionSceneRaycastOnlyDynamic(struct CollisionScene* scene, struct Ray* r
return hit->distance != maxDistance;
}
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit) {
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit, short* numPortalsPassed) {
hit->distance = maxDistance;
hit->throughPortal = NULL;
hit->roomIndex = roomIndex;
@ -458,6 +458,12 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra
collisionSceneIsPortalOpen()) {
for (int i = 0; i < 2; ++i) {
if (collisionSceneIsTouchingSinglePortal(&hit->at, &hit->normal, gCollisionScene.portalTransforms[i], i)) {
if (i == 0){
*numPortalsPassed += 1;
}else{
*numPortalsPassed -= 1;
}
struct Transform portalTransform;
collisionSceneGetPortalTransform(i, &portalTransform);
@ -468,7 +474,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra
struct RaycastHit newHit;
int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, collisionLayers, maxDistance - hit->distance, 0, &newHit);
int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, collisionLayers, maxDistance - hit->distance, passThroughPortals, &newHit, numPortalsPassed);
if (result) {
newHit.distance += hit->distance;

View file

@ -44,7 +44,7 @@ struct Transform* collisionSceneTransformToPortal(int fromPortal);
void collisionScenePushObjectsOutOfPortal(int portalIndex);
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit);
int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit, short* numPortalsPassed);
int collisionSceneRaycastOnlyDynamic(struct CollisionScene* scene, struct Ray* ray, int collisionLayers, float maxDistance, struct RaycastHit* hit);
void collisionSceneGetPortalTransform(int fromPortal, struct Transform* out);

View file

@ -234,16 +234,18 @@ void playerHandleCollision(struct Player* player) {
}
void playerApplyPortalGrab(struct Player* player, int portalIndex) {
if (player->grabbingThroughPortal == PLAYER_GRABBING_THROUGH_NOTHING) {
player->grabbingThroughPortal = portalIndex;
} else if (player->grabbingThroughPortal != portalIndex) {
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
if (portalIndex){
player->grabbingThroughPortal -= 1;
}else{
player->grabbingThroughPortal += 1;
}
}
void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing) {
if (grabbing && grabbing->flags & COLLISION_OBJECT_PLAYER_STANDING){
player->grabConstraint.object = NULL;
contactSolverRemovePointConstraint(&gContactSolver, &player->grabConstraint);
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
}
else if (grabbing && !player->grabConstraint.object) {
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 1.0f);
@ -253,6 +255,7 @@ void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing)
player->grabConstraint.object = NULL;
contactSolverRemovePointConstraint(&gContactSolver, &player->grabConstraint);
hudResolvePrompt(&gScene.hud, CutscenePromptTypeDrop);
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
} else if (grabbing != player->grabConstraint.object) {
pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 1.0f);
}
@ -290,7 +293,7 @@ int playerIsGrabbing(struct Player* player) {
return player->grabConstraint.object != NULL;
}
int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPastObject) {
int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPastObject, short* numPortalsPassed) {
struct Ray ray;
ray.origin = player->lookTransform.position;
@ -303,11 +306,11 @@ int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPa
if (checkPastObject){
short prevCollisionLayers = player->grabConstraint.object->collisionLayers;
player->grabConstraint.object->collisionLayers = 0;
result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit);
result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit, numPortalsPassed);
player->grabConstraint.object->collisionLayers = prevCollisionLayers;
}
else{
result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit);
result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit, numPortalsPassed);
}
player->collisionObject.collisionLayers = PLAYER_COLLISION_LAYERS;
@ -325,19 +328,15 @@ void playerUpdateGrabbedObject(struct Player* player) {
playerSetGrabbing(player, NULL);
} else {
struct RaycastHit hit;
short numPortalsPassed = 0;
if (playerRaycastGrab(player, &hit, 0)) {
if (playerRaycastGrab(player, &hit, 0, &numPortalsPassed)) {
hit.object->flags |= COLLISION_OBJECT_INTERACTED;
if (hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) {
if (hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable) && !(hit.object->flags & COLLISION_OBJECT_PLAYER_STANDING)) {
playerSetGrabbing(player, hit.object);
player->flags |= PlayerJustSelect;
if (hit.throughPortal) {
player->grabbingThroughPortal = hit.throughPortal == gCollisionScene.portalTransforms[0] ? 0 : 1;
} else {
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
}
player->grabbingThroughPortal = numPortalsPassed;
}
else if ((hit.object->body)){
player->flags |= PlayerJustSelect;
@ -357,6 +356,18 @@ void playerUpdateGrabbedObject(struct Player* player) {
playerSetGrabbing(player, NULL);
}
// if the object is being held through a portal and can no longer be seen, drop it.
if (player->grabConstraint.object && player->grabbingThroughPortal){
struct RaycastHit testhit;
short testnumPortalsPassed = 0;
if (playerRaycastGrab(player, &testhit, 0, &testnumPortalsPassed)){
if ((testnumPortalsPassed != player->grabbingThroughPortal) && (testhit.object != player->grabConstraint.object)){
playerSetGrabbing(player, NULL);
return;
}
}
}
if (player->grabConstraint.object) {
if (player->body.flags & RigidBodyFlagsCrossedPortal0) {
playerApplyPortalGrab(player, 1);
@ -380,7 +391,8 @@ void playerUpdateGrabbedObject(struct Player* player) {
// try to determine how far away to set the grab dist
struct RaycastHit hit;
struct Vector3 temp_grab_dist = gGrabDistance;
if (playerRaycastGrab(player, &hit, 1)){
short unused = 0;
if (playerRaycastGrab(player, &hit, 1, &unused)){
float dist = hit.distance;
temp_grab_dist.z = maxf(((-1.0f*fabsf(dist))+0.2f), gGrabDistance.z);
temp_grab_dist.z = minf(temp_grab_dist.z, -0.2f);
@ -401,12 +413,14 @@ void playerUpdateGrabbedObject(struct Player* player) {
}
struct Transform pointTransform;
collisionSceneGetPortalTransform(player->grabbingThroughPortal, &pointTransform);
collisionSceneGetPortalTransform(player->grabbingThroughPortal > 0 ? 0 : 1, &pointTransform);
transformPoint(&pointTransform, &grabPoint, &grabPoint);
struct Quaternion finalRotation;
quatMultiply(&pointTransform.rotation, &grabRotation, &finalRotation);
grabRotation = finalRotation;
for (int i = 0; i < abs(player->grabbingThroughPortal); ++i) {
transformPoint(&pointTransform, &grabPoint, &grabPoint);
struct Quaternion finalRotation;
quatMultiply(&pointTransform.rotation, &grabRotation, &finalRotation);
grabRotation = finalRotation;
}
}
pointConstraintUpdateTarget(&player->grabConstraint, &grabPoint, &grabRotation);

View file

@ -11,7 +11,7 @@
#include "../sk64/skelatool_armature.h"
#include "../physics/point_constraint.h"
#define PLAYER_GRABBING_THROUGH_NOTHING -1
#define PLAYER_GRABBING_THROUGH_NOTHING 0
#define PLAYER_HEAD_HEIGHT 1.0f

View file

@ -212,8 +212,9 @@ void portalGunUpdate(struct PortalGun* portalGun, struct Player* player) {
}
struct RaycastHit hit;
short numPortalsPassed;
if (collisionSceneRaycast(&gCollisionScene, projectile->roomIndex, &projectile->positionDirection, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, PORTAL_PROJECTILE_SPEED * FIXED_DELTA_TIME + 0.1f, 0, &hit)) {
if (collisionSceneRaycast(&gCollisionScene, projectile->roomIndex, &projectile->positionDirection, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, PORTAL_PROJECTILE_SPEED * FIXED_DELTA_TIME + 0.1f, 0, &hit, &numPortalsPassed)) {
if (!sceneOpenPortalFromHit(
&gScene,
&projectile->positionDirection,
@ -247,8 +248,9 @@ void portalGunFire(struct PortalGun* portalGun, int portalIndex, struct Ray* ray
struct PortalGunProjectile* projectile = &portalGun->projectiles[portalIndex];
struct RaycastHit hit;
short numPortalsPassed;
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit)) {
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit, &numPortalsPassed)) {
vector3AddScaled(&ray->origin, &ray->dir, NO_HIT_DISTANCE, &hit.at);
hit.distance = NO_HIT_DISTANCE;
hit.normal = gZeroVec;

View file

@ -939,8 +939,9 @@ int sceneOpenPortalFromHit(struct Scene* scene, struct Ray* ray, struct RaycastH
int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex, int roomIndex, int fromPlayer, int just_checking) {
struct RaycastHit hit;
short numPortalsPassed;
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit)) {
if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit, &numPortalsPassed)) {
return 0;
}

View file

@ -140,6 +140,9 @@ void securityCameraInit(struct SecurityCamera* securityCamera, struct SecurityCa
}
void securityCameraUpdate(struct SecurityCamera* securityCamera) {
if (securityCamera->collisionObject.flags & COLLISION_OBJECT_PLAYER_STANDING) {
securityCamera->collisionObject.flags &= ~COLLISION_OBJECT_PLAYER_STANDING;
}
if (decorObjectUpdateFizzler(&securityCamera->collisionObject, &securityCamera->fizzleTime) == FizzleCheckResultEnd) {
dynamicSceneRemove(securityCamera->dynamicId);
collisionSceneRemoveDynamicObject(&securityCamera->collisionObject);