Jump to content

Camera jumping with gravity


The Snow Irbix
 Share

Recommended Posts

Hi guys !

I did a playground with my FreeCamera jumping when pressing the spacebar, here it is : https://playground.babylonjs.com/#JRHZ1B

To get a good result, I was forced to set the gravity to -0.2, and I want to know why setting the gravity to -0.9 doesn't give a realistic result.

I already read the older topics on the forum on how to create a jumping animation, but they don't use gravity and causes the player's camera to go through the box (http://www.babylonjs-playground.com/#XN87O#41)

Any idea to improve my jump animation with a gravity set to -0.9 ?

Or can I set a different gravity for the camera and for the other objects ?

 

Thanks

Link to comment
Share on other sites

  • 2 weeks later...

I managed to get a better gravity implementation by modifying the FreeCamera code directly.

I share it with the forum if someone wanna make a realistic jump animation.

Feel free to improve the code and share it with us.

var BABYLON;
(function (BABYLON) {
    var FreeCamera = (function (_super) {
        __extends(FreeCamera, _super);
        function FreeCamera(name, position, scene) {
            var _this = _super.call(this, name, position, scene) || this;
            _this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
            _this.checkCollisions = false;
            _this.applyGravity = false;
            _this._impulsion = BABYLON.Vector3.Zero();
            _this._jumpingFlag = false;
            _this._inertia = BABYLON.Vector3.Zero();
            _this._needMoveForGravity = false;
            _this._oldPosition = BABYLON.Vector3.Zero();
            _this._diffPosition = BABYLON.Vector3.Zero();
            _this._newPosition = BABYLON.Vector3.Zero();
            // Collisions
            _this._collisionMask = -1;
            _this._onCollisionPositionChange = function (collisionId, newPosition, collidedMesh) {
                if (collidedMesh === void 0) { collidedMesh = null; }
                //TODO move this to the collision coordinator!
                if (_this.getScene().workerCollisions)
                    newPosition.multiplyInPlace(_this._collider.radius);
                var updatePosition = function (newPos) {
                    _this._newPosition.copyFrom(newPos);
                    _this._newPosition.subtractToRef(_this._oldPosition, _this._diffPosition);
                    var oldPosition = _this.position.clone();
                    if (_this._diffPosition.length() > BABYLON.Engine.CollisionsEpsilon) {
                        _this.position.addInPlace(_this._diffPosition);
                        if(collidedMesh)
                        {
                            // when moving but collision with ground
                            _this._inertia = BABYLON.Vector3.Zero();
                            _this._jumpingFlag = false;
                        }
                        if (_this.onCollide && collidedMesh) {
                            _this.onCollide(collidedMesh);
                        }
                    }
                    else
                    {
                        // when not moving but still near the ground
                        _this._inertia = BABYLON.Vector3.Zero();
                        _this._jumpingFlag = false;
                    }
                };
                updatePosition(newPosition);
            };
            _this.inputs = new BABYLON.FreeCameraInputsManager(_this);
            _this.inputs.addKeyboard().addMouse();
            return _this;
        }
        Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
            //-- begin properties for backward compatibility for inputs
            get: function () {
                var mouse = this.inputs.attached["mouse"];
                if (mouse)
                    return mouse.angularSensibility;
            },
            set: function (value) {
                var mouse = this.inputs.attached["mouse"];
                if (mouse)
                    mouse.angularSensibility = value;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(FreeCamera.prototype, "keysUp", {
            get: function () {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    return keyboard.keysUp;
            },
            set: function (value) {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    keyboard.keysUp = value;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(FreeCamera.prototype, "keysDown", {
            get: function () {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    return keyboard.keysDown;
            },
            set: function (value) {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    keyboard.keysDown = value;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(FreeCamera.prototype, "keysLeft", {
            get: function () {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    return keyboard.keysLeft;
            },
            set: function (value) {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    keyboard.keysLeft = value;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(FreeCamera.prototype, "keysRight", {
            get: function () {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    return keyboard.keysRight;
            },
            set: function (value) {
                var keyboard = this.inputs.attached["keyboard"];
                if (keyboard)
                    keyboard.keysRight = value;
            },
            enumerable: true,
            configurable: true
        });
        // Controls
        FreeCamera.prototype.attachControl = function (element, noPreventDefault) {
            this.inputs.attachElement(element, noPreventDefault);
        };
        FreeCamera.prototype.detachControl = function (element) {
            this.inputs.detachElement(element);
            this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
            this.cameraRotation = new BABYLON.Vector2(0, 0);
        };
        Object.defineProperty(FreeCamera.prototype, "collisionMask", {
            get: function () {
                return this._collisionMask;
            },
            set: function (mask) {
                this._collisionMask = !isNaN(mask) ? mask : -1;
            },
            enumerable: true,
            configurable: true
        });
        FreeCamera.prototype._collideWithWorld = function (velocity) {
            var globalPosition;
            if (this.parent) {
                globalPosition = BABYLON.Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
            }
            else {
                globalPosition = this.position;
            }
            globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
            if (!this._collider) {
                this._collider = new BABYLON.Collider();
            }
            this._collider.radius = this.ellipsoid;
            this._collider.collisionMask = this._collisionMask;
            //no need for clone, as long as gravity is not on.
            var actualVelocity = velocity;
            //add gravity to the velocity to prevent the dual-collision checking
            if(this.applyGravity)
            {
                if(!this._impulsion.equals(BABYLON.Vector3.Zero())) // impulsion != 0
                {
                    if(this._jumpingFlag === false) // not already jumping
                    {
                        this._jumpingFlag = true;
                        this._inertia.addInPlace(this._impulsion);
                    }
                    this._impulsion = BABYLON.Vector3.Zero();
                }
                this._inertia.addInPlace(this.getScene().gravity.scale(1/60)); // 1/60 if we assume the 60 fps
                actualVelocity = velocity.add(this._inertia);
            }
            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
        };
        FreeCamera.prototype._checkInputs = function () {
            if (!this._localDirection) {
                this._localDirection = BABYLON.Vector3.Zero();
                this._transformedDirection = BABYLON.Vector3.Zero();
            }
            this.inputs.checkInputs();
            _super.prototype._checkInputs.call(this);
        };
        FreeCamera.prototype._decideIfNeedsToMove = function () {
            return this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
        };
        FreeCamera.prototype._updatePosition = function () {
            if (this.checkCollisions && this.getScene().collisionsEnabled) {
                this._collideWithWorld(this.cameraDirection);
            }
            else {
                _super.prototype._updatePosition.call(this);
            }
        };
        FreeCamera.prototype.dispose = function () {
            this.inputs.clear();
            _super.prototype.dispose.call(this);
        };
        FreeCamera.prototype.getClassName = function () {
            return "FreeCamera";
        };
        return FreeCamera;
    }(BABYLON.TargetCamera));
    __decorate([
        BABYLON.serializeAsVector3()
    ], FreeCamera.prototype, "ellipsoid", void 0);
    __decorate([
        BABYLON.serialize()
    ], FreeCamera.prototype, "checkCollisions", void 0);
    __decorate([
        BABYLON.serialize()
    ], FreeCamera.prototype, "applyGravity", void 0);
    BABYLON.FreeCamera = FreeCamera;
})(BABYLON || (BABYLON = {}));

The "inertia" variable is used to store the current velocity of the camera

The "jumpingFlag" is used to prevent the player to jump several times without hitting the ground.

And the "impulsion" is a velocity vector added to the current velocity of the camera.

So now, jump is as easy as that :

window.addEventListener('keydown', function(e)
{
	if(e.key === ' ')
	{
		camera._impulsion.set(0, 0.25, 0);
	}
});

 

Sadly I couldn't make a good implementation of the gravity with the camera's "onCollide" callback only,

so I can't make a demo on the playground cause I modified the internal BABYLON code.

 

Hope it will help another one !

 

EDIT : This works only if the "needMoveForGravity" flag is set to 'true'.

camera._needMoveForGravity = true;

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...