| 1 | #include "Player/PlayerCeilingCheck.h" |
| 2 | |
| 3 | #include "Library/Base/StringUtil.h" |
| 4 | #include "Library/Collision/Collider.h" |
| 5 | |
| 6 | #include "Player/PlayerCollisionCheckSphereMove.h" |
| 7 | |
| 8 | PlayerCeilingCheck::PlayerCeilingCheck(al::CollisionDirector* director) { |
| 9 | mCollisionCheckSphereMove = new PlayerCollisionCheckSphereMove(director, 16); |
| 10 | setupCeilingCheckNormal(); |
| 11 | } |
| 12 | |
| 13 | void PlayerCeilingCheck::setupCeilingCheckNormal() { |
| 14 | mIsCeilingCheckNormal = true; |
| 15 | mIsCeilingCheckGrab = false; |
| 16 | } |
| 17 | |
| 18 | void PlayerCeilingCheck::update(const sead::Vector3f& trans, const sead::Vector3f& up, f32 tall, |
| 19 | f32 collisionRadiusSquat, f32 headClearance, f32 holdHeight) { |
| 20 | sead::Vector3f checkStart; |
| 21 | checkStart.set(trans); |
| 22 | |
| 23 | f32 playerHeight; |
| 24 | sead::Vector3f newCheckStart; |
| 25 | if (mIsCeilingCheckGrab) { |
| 26 | newCheckStart = trans - (collisionRadiusSquat + headClearance) * up; |
| 27 | playerHeight = 2 * tall; |
| 28 | } else { |
| 29 | newCheckStart = trans + (collisionRadiusSquat - headClearance) * up; |
| 30 | playerHeight = (2 * tall) - (2 * collisionRadiusSquat); |
| 31 | tall -= 2 * collisionRadiusSquat; |
| 32 | } |
| 33 | checkStart = newCheckStart; |
| 34 | |
| 35 | f32 checkHeight = playerHeight + headClearance + holdHeight; |
| 36 | f32 minTStandUp = (tall + headClearance) / checkHeight; |
| 37 | mCollisionCheckSphereMove->checkSphereMove(checkStart, checkHeight * up, collisionRadiusSquat); |
| 38 | |
| 39 | sead::Vector3f down = -up; |
| 40 | f32 minTValue2 = 1.0f; |
| 41 | f32 minTValue = 1.0f; |
| 42 | s32 minIndex = -1; |
| 43 | for (u32 i = 0; i < mCollisionCheckSphereMove->getNum(); i++) { |
| 44 | if (!al::isCeilingPolygon(mCollisionCheckSphereMove->getNormal(i), down)) |
| 45 | continue; |
| 46 | |
| 47 | f32 tValue = mCollisionCheckSphereMove->getTValue(i); |
| 48 | if (minTValue > tValue) |
| 49 | minTValue = tValue; |
| 50 | |
| 51 | if (mIsCeilingCheckNormal && |
| 52 | al::isEqualString(str1: mCollisionCheckSphereMove->getMapCodeName(i), str2: "Press" )) |
| 53 | continue; |
| 54 | |
| 55 | if (al::isEqualString(str1: mCollisionCheckSphereMove->getWallCodeName(i), str2: "NoCeilSquat" )) |
| 56 | continue; |
| 57 | |
| 58 | minIndex = minTValue2 > tValue ? i : minIndex; |
| 59 | minTValue2 = sead::Mathf::clampMax(val: minTValue2, max_: tValue); |
| 60 | } |
| 61 | |
| 62 | f32 minTHoldUp = (0.99f * (checkHeight - holdHeight)); |
| 63 | f32 maxTPressedCeil = (0.01f * (checkHeight - holdHeight)); |
| 64 | |
| 65 | mIsEnableStandUp = minTValue2 >= minTStandUp; |
| 66 | mIsEnableHoldUp = minTValue >= minTHoldUp / checkHeight; |
| 67 | mIsPressedCeil = minTValue2 < maxTPressedCeil / checkHeight; |
| 68 | mCeilCheckHeight = checkHeight + (checkStart - trans).dot(t: up); |
| 69 | mSafetyCeilSpace = mCeilCheckHeight; |
| 70 | if (minIndex >= 0) |
| 71 | mSafetyCeilSpace = (mCollisionCheckSphereMove->getPos(minIndex) - trans).dot(t: up); |
| 72 | } |
| 73 | |
| 74 | void PlayerCeilingCheck::setupCeilingCheckGrab() { |
| 75 | mIsCeilingCheckNormal = false; |
| 76 | mIsCeilingCheckGrab = true; |
| 77 | } |
| 78 | |
| 79 | void PlayerCeilingCheck::setCollisionPartsFilter(const al::CollisionPartsFilterBase* filter) { |
| 80 | mCollisionCheckSphereMove->setCollisionPartsFilter(filter); |
| 81 | } |
| 82 | |