Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add double jump. #3361

Merged
merged 10 commits into from
Jul 26, 2022
Merged
29 changes: 24 additions & 5 deletions avatars/animationHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ let animations;
let animationStepIndices;
// let animationsBaseModel;
let jumpAnimation;
let doubleJumpAnimation;
let fallLoopAnimation;
let floatAnimation;
let useAnimations;
Expand Down Expand Up @@ -306,6 +307,7 @@ export const loadPromise = (async () => {
// swordTopDownSlash = animations.find(a => a.isSwordTopDownSlash)

jumpAnimation = animations.find(a => a.isJump);
doubleJumpAnimation = animations.find(a => a.isDoubleJump);
fallLoopAnimation = animations.index['falling.fbx'];
// sittingAnimation = animations.find(a => a.isSitting);
floatAnimation = animations.find(a => a.isFloat);
Expand Down Expand Up @@ -410,12 +412,12 @@ export const loadPromise = (async () => {
console.log('load avatar animations error', err);
});

export const _applyAnimation = (avatar, now, moveFactors, timeDiffS) => {
export const _applyAnimation = (avatar, now) => {
// const runSpeed = 0.5;
const angle = avatar.getAngle();
const timeSeconds = now / 1000;
const landTimeSeconds = timeSeconds - avatar.lastLandStartTime / 1000 + 0.8; // in order to align landing 2.fbx with walk/run
const {idleWalkFactor, walkRunFactor, crouchFactor} = moveFactors;
const {idleWalkFactor, walkRunFactor, crouchFactor} = avatar;

/* const _getAnimationKey = crouchState => {
if (crouchState) {
Expand Down Expand Up @@ -760,6 +762,23 @@ export const _applyAnimation = (avatar, now, moveFactors, timeDiffS) => {
_getHorizontalBlend(k, lerpFn, isPosition, dst);
};
const _getApplyFn = () => {
if (avatar.doubleJumpState) {
return spec => {
const {
animationTrackName: k,
dst,
isPosition,
} = spec;

const t2 = avatar.doubleJumpTime / 1000;
const src2 = doubleJumpAnimation.interpolants[k];
const v2 = src2.evaluate(t2);

dst.fromArray(v2);

_clearXZ(dst, isPosition);
};
}
if (avatar.jumpState) {
return spec => {
const {
Expand Down Expand Up @@ -1219,7 +1238,7 @@ export const _applyAnimation = (avatar, now, moveFactors, timeDiffS) => {
isPosition,
} = spec;

if (idleWalkFactor === 0) {
if (!avatar.landWithMoving) {
const animationSpeed = 0.75;
const landTimeS = avatar.landTime / 1000;
const landingAnimation = animations.index['landing.fbx'];
Expand Down Expand Up @@ -1414,10 +1433,10 @@ export const _applyAnimation = (avatar, now, moveFactors, timeDiffS) => {

// ignore all animation position except y
if (isPosition) {
if (avatar.swimState || (!avatar.jumpState && !avatar.fallLoopState)) {
if (avatar.swimState) {
// animations position is height-relative
dst.y *= avatar.height; // XXX avatar could be made perfect by measuring from foot to hips instead
} else if (avatar.jumpState) {
} else if (avatar.jumpState || avatar.doubleJumpState || avatar.fallLoopState) {
// force height in the jump case to overide the animation
dst.y = avatar.height * 0.55;
} else {
Expand Down
12 changes: 7 additions & 5 deletions avatars/avatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,9 @@ class Avatar {
this.unuseAnimation = null;
this.unuseTime = -1;

this.idleWalkFactor = NaN;
this.walkRunFactor = NaN;
this.crouchFactor = NaN;
this.sitState = false;
this.sitAnimation = null;
// this.activateState = false;
Expand Down Expand Up @@ -1518,10 +1521,9 @@ class Avatar {

const currentSpeed = localVector.set(this.velocity.x, 0, this.velocity.z).length();

const moveFactors = {};
moveFactors.idleWalkFactor = Math.min(Math.max((currentSpeed - idleFactorSpeed) / (walkFactorSpeed - idleFactorSpeed), 0), 1);
moveFactors.walkRunFactor = Math.min(Math.max((currentSpeed - walkFactorSpeed) / (runFactorSpeed - walkFactorSpeed), 0), 1);
moveFactors.crouchFactor = Math.min(Math.max(1 - (this.crouchTime / crouchMaxTime), 0), 1);
this.idleWalkFactor = Math.min(Math.max((currentSpeed - idleFactorSpeed) / (walkFactorSpeed - idleFactorSpeed), 0), 1);
this.walkRunFactor = Math.min(Math.max((currentSpeed - walkFactorSpeed) / (runFactorSpeed - walkFactorSpeed), 0), 1);
this.crouchFactor = Math.min(Math.max(1 - (this.crouchTime / crouchMaxTime), 0), 1);
// console.log('current speed', currentSpeed, idleWalkFactor, walkRunFactor);
this.aimRightFactor = this.aimRightTransitionTime / aimTransitionMaxTime;
this.aimRightFactorReverse = 1 - this.aimRightFactor;
Expand Down Expand Up @@ -1935,7 +1937,7 @@ class Avatar {
this.inputs.hmd.quaternion
);
}
_applyAnimation(this, now, moveFactors, timeDiffS);
_applyAnimation(this, now);

if (this.poseAnimation) {
_overwritePose(this.poseAnimation);
Expand Down
1 change: 1 addition & 0 deletions avatars/util.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ export const cloneModelBones = modelBones => {
export const decorateAnimation = animation => {
animation.isIdle = /idle/i.test(animation.name);
animation.isJump = /^jump/i.test(animation.name);
animation.isDoubleJump = /^jump_double/i.test(animation.name);
animation.isSitting = /sitting/i.test(animation.name);
animation.isFloat = /treading/i.test(animation.name);
animation.isPistol = /pistol aiming/i.test(animation.name);
Expand Down
1 change: 1 addition & 0 deletions character-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ class UninterpolatedPlayer extends StatePlayer {
fly: new InfiniteActionInterpolant(() => this.hasAction('fly'), 0),
swim: new InfiniteActionInterpolant(() => this.hasAction('swim'), 0),
jump: new InfiniteActionInterpolant(() => this.hasAction('jump'), 0),
doubleJump: new InfiniteActionInterpolant(() => this.hasAction('doubleJump'), 0),
land: new InfiniteActionInterpolant(() => !this.hasAction('jump') && !this.hasAction('fallLoop') && !this.hasAction('fly'), 0),
dance: new BiActionInterpolant(() => this.hasAction('dance'), 0, crouchMaxTime),
emote: new BiActionInterpolant(() => this.hasAction('emote'), 0, crouchMaxTime),
Expand Down
24 changes: 19 additions & 5 deletions character-physics.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,19 @@ class CharacterPhysics {

const jumpAction = this.player.getAction('jump');
if (jumpAction?.trigger === 'jump') {
const jumpTime = this.player.actionInterpolants.jump.get();
localVector3.y = Math.sin(jumpTime * (Math.PI / flatGroundJumpAirTime)) * jumpHeight + jumpAction.startPositionY - this.lastCharacterControllerY;
if (jumpTime >= flatGroundJumpAirTime) {
this.player.setControlAction({type: 'fallLoop', from: 'jump'});
const doubleJumpAction = this.player.getAction('doubleJump');
if (doubleJumpAction) {
const doubleJumpTime = this.player.actionInterpolants.doubleJump.get();
localVector3.y = Math.sin(doubleJumpTime * (Math.PI / flatGroundJumpAirTime)) * jumpHeight + doubleJumpAction.startPositionY - this.lastCharacterControllerY;
if (doubleJumpTime >= flatGroundJumpAirTime) {
this.player.setControlAction({type: 'fallLoop', from: 'jump'});
}
} else {
const jumpTime = this.player.actionInterpolants.jump.get();
localVector3.y = Math.sin(jumpTime * (Math.PI / flatGroundJumpAirTime)) * jumpHeight + jumpAction.startPositionY - this.lastCharacterControllerY;
if (jumpTime >= flatGroundJumpAirTime) {
this.player.setControlAction({type: 'fallLoop', from: 'jump'});
}
}
}

Expand Down Expand Up @@ -161,7 +170,12 @@ class CharacterPhysics {
this.lastGroundedTime = now;
if (!this.lastGrounded) {
if (this.player.hasAction('jump') || this.player.hasAction('fallLoop')) {
this.player.setControlAction({type: 'land', time: now});
this.player.setControlAction({
type: 'land',
time: now,
isMoving: this.player.avatar.idleWalkFactor > 0,
});
this.player.removeAction('doubleJump');
}
};

Expand Down
11 changes: 11 additions & 0 deletions game.js
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,10 @@ class GameManager extends EventTarget {
const localPlayer = getLocalPlayer();
return localPlayer.hasAction('jump');
}
isDoubleJumping() {
const localPlayer = getLocalPlayer();
return localPlayer.hasAction('doubleJump');
}
ensureJump(trigger) {
const localPlayer = getLocalPlayer();

Expand Down Expand Up @@ -1504,6 +1508,13 @@ class GameManager extends EventTarget {
// soundManager.play('jump');

}
doubleJump() {
const localPlayer = getLocalPlayer();
localPlayer.addAction({
type: 'doubleJump',
startPositionY: localPlayer.characterController.position.y,
});
}
isMovingBackward() {
const localPlayer = getLocalPlayer();
// return ioManager.keysDirection.z > 0 && this.isAiming();
Expand Down
2 changes: 2 additions & 0 deletions io-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ ioManager.keydown = e => {
// if (controlsManager.isPossessed()) {
if (!game.isJumping()) {
game.jump('jump');
} else if (!game.isDoubleJumping()) {
game.doubleJump();
}
// }
break;
Expand Down
4 changes: 4 additions & 0 deletions player-avatar-binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export function makeAvatar(app) {
}
export function applyPlayerActionsToAvatar(player, rig) {
const jumpAction = player.getAction('jump');
const doubleJumpAction = player.getAction('doubleJump');
const landAction = player.getAction('land');
const flyAction = player.getAction('fly');
const swimAction = player.getAction('swim');
Expand Down Expand Up @@ -118,8 +119,11 @@ export function applyPlayerActionsToAvatar(player, rig) {

rig.jumpState = !!jumpAction;
rig.jumpTime = player.actionInterpolants.jump.get();
rig.doubleJumpState = !!doubleJumpAction;
rig.doubleJumpTime = player.actionInterpolants.doubleJump.get();
rig.landTime = player.actionInterpolants.land.get();
rig.lastLandStartTime = landAction ? landAction.time : 0;
rig.landWithMoving = landAction?.isMoving;
rig.flyState = !!flyAction;
rig.flyTime = flyAction ? player.actionInterpolants.fly.get() : -1;
rig.activateTime = player.actionInterpolants.activate.get();
Expand Down
Binary file modified public/animations/animations.z
Binary file not shown.
Binary file added public/animations/jump_double.fbx
Binary file not shown.