1#include "Player/PlayerActionSlopeSlideControl.h"
2
3#include "Library/LiveActor/ActorMovementFunction.h"
4#include "Library/LiveActor/ActorPoseKeeper.h"
5#include "Library/LiveActor/ActorPoseUtil.h"
6#include "Library/Math/MathUtil.h"
7
8#include "Player/PlayerConst.h"
9#include "Player/PlayerInput.h"
10#include "Util/ObjUtil.h"
11#include "Util/PlayerCollisionUtil.h"
12
13PlayerActionSlopeSlideControl::PlayerActionSlopeSlideControl(al::LiveActor* player,
14 const PlayerConst* pConst,
15 const PlayerInput* input,
16 const IUsePlayerCollision* collider)
17 : mPlayer(player), mConst(pConst), mInput(input), mCollision(collider) {}
18
19void PlayerActionSlopeSlideControl::setup() {
20 mGroundNormal = -al::getGravity(actor: mPlayer);
21 mDirSlide = {0.0f, 0.0f, 0.0f};
22
23 if (rs::isCollidedGround(mCollision)) {
24 al::calcDirSlide(&mDirSlide, al::getGravity(actor: mPlayer),
25 rs::getCollidedGroundNormal(mCollision));
26 if (!rs::isJustLand(mCollision))
27 mGroundNormal = rs::getCollidedGroundNormal(mCollision);
28 }
29
30 mHorizontalVelocity = {0.0f, 0.0f, 0.0f};
31}
32
33void PlayerActionSlopeSlideControl::setupCutSlideOppositeDir() {
34 setup();
35
36 sead::Vector3f groundNormal = {0.0f, 0.0f, 0.0f};
37 rs::calcGroundNormalOrGravityDir(&groundNormal, mPlayer, mCollision);
38
39 sead::Vector3f slideDir = {0.0f, 0.0f, 0.0f};
40 sead::Vector3f* velocityPtr = al::getVelocityPtr(actor: mPlayer);
41 al::alongVectorNormalH(velocityPtr, *velocityPtr, mGroundNormal, groundNormal);
42 if (rs::calcSlideDir(&slideDir, al::getGravity(actor: mPlayer), groundNormal))
43 al::limitVectorOppositeDir(outVec: velocityPtr, inVec: slideDir, dir: *velocityPtr, scale: velocityPtr->length());
44
45 *velocityPtr -= mConst->getGravityMove() * groundNormal;
46 mGroundNormal = groundNormal;
47}
48
49f32 PlayerActionSlopeSlideControl::update(f32 accel, f32 brake, f32 against, f32 anglePowerMax,
50 f32 maxSpeed, f32 sideAccel, f32 sideBrake,
51 f32 sideMaxSpeed, f32 turnDegree, f32 gravity,
52 bool isRolling) {
53 sead::Vector3f prevGroundNormal = mGroundNormal;
54 sead::Vector3f up = -al::getGravity(actor: mPlayer);
55 sead::Vector3f velocity = al::getVelocity(actor: mPlayer);
56 bool isOnGroundSlopeSlideEnd = rs::isOnGroundSlopeSlideEnd(mPlayer, mCollision, mConst);
57 if (rs::isOnGround(mPlayer, mCollision)) {
58 mGroundNormal = rs::getCollidedGroundNormal(mCollision);
59 up = mGroundNormal;
60 al::calcDirSlide(&mDirSlide, al::getGravity(actor: mPlayer), up);
61 al::alongVectorNormalH(&velocity, velocity, prevGroundNormal, up);
62
63 sead::Vector3f velDirSlide = {0.0f, 0.0f, 0.0f};
64 sead::Vector3f velSide = {0.0f, 0.0f, 0.0f};
65 if (isOnGroundSlopeSlideEnd) {
66 al::separateVectorParallelVertical(&velSide, &velDirSlide, up, velocity);
67 velDirSlide *= brake;
68 velSide *= sideBrake;
69 if (isRolling) {
70 sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f};
71 mInput->calcMoveInput(&moveInput, up);
72
73 sead::Vector3f normDirSlide = {0.0f, 0.0f, 0.0f};
74 al::tryNormalizeOrZero(out: &normDirSlide, vec: velDirSlide);
75
76 sead::Vector3f side;
77 side.setCross(a: up, b: normDirSlide);
78 al::tryNormalizeOrZero(out: &side);
79
80 f32 sideInput = side.dot(t: moveInput);
81 sead::Vector3f moveSideVec = side * sideInput * sideAccel;
82 al::addVectorLimit(&velDirSlide, moveSideVec, maxSpeed);
83 }
84 } else {
85 al::separateVectorParallelVertical(&velDirSlide, &velSide, mDirSlide, velocity);
86 sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f};
87 mInput->calcMoveInput(&moveInput, up);
88 f32 speedDirSlide = velDirSlide.dot(t: mDirSlide);
89 if (speedDirSlide < 0.0)
90 velDirSlide *= brake;
91
92 f32 moveInputAgainst = sead::Mathf::clamp(value: -mDirSlide.dot(t: moveInput), low: 0.0f, high: 1.0f);
93 f32 minSpeedNorm = sead::Mathf::clamp(value: 1.0f - (moveInputAgainst * against), low: 0.0, high: 1.0);
94 f32 speedNorm = sead::Mathf::clamp(value: speedDirSlide + 1.0f, low: minSpeedNorm, high: 1.0f);
95
96 f32 anglePower = sead::Mathf::clamp(
97 value: 90.0f - al::calcAngleDegree(a: mDirSlide, b: al::getGravity(actor: mPlayer)), low: 0.0f, high: 90.0f);
98
99 f32 anglePowerNorm = 1.0f;
100 if (anglePowerMax > 0.0)
101 anglePowerNorm = sead::Mathf::clampMax(val: anglePower / anglePowerMax, max_: 1.0f);
102
103 al::addVectorLimit(&velDirSlide, mDirSlide * accel * anglePowerNorm * speedNorm,
104 maxSpeed);
105 velSide *= sideBrake;
106 sead::Vector3f inputDir = {0.0f, 0.0f, 0.0f};
107 if (al::tryNormalizeOrZero(out: &inputDir, vec: moveInput)) {
108 sead::Vector3f sideDir;
109 sideDir.setCross(a: up, b: mDirSlide);
110 al::addVectorLimit(&velSide,
111 sideDir * sideDir.dot(t: inputDir) * moveInput.length() * sideAccel,
112 sideMaxSpeed);
113 }
114 }
115
116 sead::Vector3f vel;
117 vel.x = velDirSlide.x + velSide.x;
118 vel.y = velDirSlide.y + velSide.y;
119 vel.z = velDirSlide.z + velSide.z;
120 al::limitLength(out: &vel, vec: vel, limit: maxSpeed);
121 al::setVelocity(actor: mPlayer, vel: vel - (mConst->getGravityMove() * up));
122 } else {
123 mGroundNormal = up;
124 f32 prevUpVel = prevGroundNormal.dot(t: al::getVelocity(actor: mPlayer));
125 al::alongVectorNormalH(al::getVelocityPtr(actor: mPlayer), al::getVelocity(actor: mPlayer),
126 prevGroundNormal, mGroundNormal);
127 sead::Vector3f* velPtr = al::getVelocityPtr(actor: mPlayer);
128 velPtr->x = (prevUpVel * mGroundNormal.x) + velPtr->x;
129 velPtr->y = (prevUpVel * mGroundNormal.y) + velPtr->y;
130 velPtr->z = (prevUpVel * mGroundNormal.z) + velPtr->z;
131 al::addVectorLimit(al::getVelocityPtr(actor: mPlayer), up * -gravity, mConst->getFallSpeedMax());
132 }
133
134 sead::Vector3f hVel = {0.0f, 0.0f, 0.0f};
135 al::verticalizeVec(out: &hVel, vertical: up, vec: al::getVelocity(actor: mPlayer));
136 sead::Vector3f hVelDir = {0.0f, 0.0f, 0.0f};
137
138 f32 rumbleStrength;
139 if (al::tryNormalizeOrZero(out: &hVelDir, vec: hVel)) {
140 sead::Vector3f front = {0.0f, 0.0f, 0.0f};
141 al::calcFrontDir(front: &front, actor: mPlayer);
142 al::verticalizeVec(out: &front, vertical: up, vec: front);
143 al::tryNormalizeOrZero(out: &front);
144 if (turnDegree > 0.0) {
145 f32 angleFrontVel = 2 * al::calcAngleDegree(a: front, b: hVelDir);
146 f32 turn = sead::Mathf::clamp(value: angleFrontVel / turnDegree, low: 0.0f, high: 1.0f);
147 sead::Vector3f upFrontVel;
148 upFrontVel.setCross(a: front, b: hVelDir);
149 rumbleStrength = -al::sign(x: up.dot(t: upFrontVel)) * turn;
150 } else {
151 rumbleStrength = 0.0;
152 }
153
154 al::turnVecToVecCosOnPlane(&front, hVelDir, up,
155 sead::Mathf::cos(t: sead::Mathf::deg2rad(deg: turnDegree)));
156 rs::slerpUpFront(mPlayer, up, front, mConst->getSlerpQuatRate(),
157 mConst->getHillPoseDegreeMax());
158 } else {
159 rumbleStrength = 0.0;
160 }
161
162 mHorizontalVelocity = hVel;
163 return rumbleStrength;
164}
165