[SOLVED] Simultaneous movement of the player and jump


#1

Hi! I am doing a project in which a player moves around the scene using WASD. He can also jump on the space button. When a player stands still and makes a jump, everything works as it should. But when a player starts moving during a jump, he doesn’t fall. Can you please tell how you can solved the problem? I think that need to somehow add the force vector to the impulse vector, but I don’t know how to do it.

// Create PlayerMovement script.
var PlayerMovement = pc.createScript('playerMovement');

// Add attributes to the script.
PlayerMovement.attributes.add('movementSpeed', {
    type: 'number',
    default: 0.025
});

PlayerMovement.attributes.add('jumpPower', {
    type: 'number',
    default: 200.0
});

PlayerMovement.attributes.add('raycastPlayerBase', {
    type: 'entity'
});

PlayerMovement.attributes.add('cameraEntity', {
    type: 'entity'
});

// initialize code called once per entity
PlayerMovement.prototype.initialize = function() {
    this.eulers = new pc.Vec3();
    this.force = new pc.Vec3();
    this.jumping = {
        state: false
    };
};

// Обновление кода каждый кадр позицию игрока
PlayerMovement.prototype.update = function(dt) {
    // Get application reference.
    var app = this.app;
    
    // Get players force vector.
    var force = this.force;
    
    // Get camera direction vectors.
    var forward = this.cameraEntity.forward;
    var right = this.cameraEntity.right;
    
    // Movement logic. Listen for key presses and apply changes to directional vector components.
    var x = 0;
    var z = 0;
    
    if (app.keyboard.isPressed(pc.KEY_W)) {
        x += forward.x;
        z += forward.z;
    }
    
    if (app.keyboard.isPressed(pc.KEY_A)) {
        x -= right.x;
        z -= right.z;
    }
    
    if (app.keyboard.isPressed(pc.KEY_S)) {
        x -= forward.x;
        z -= forward.z;
    }

    if (app.keyboard.isPressed(pc.KEY_D)) {
        x += right.x;
        z += right.z;
    }
    
    // Jump code, checking if the space key was pressed instead of is pressed. This is important as we don't want to call the jump code multiple times.
    // We set a jump state to ensure that we can't jump whilst already jumping.
    // The jump power is passed in from the script attributes. This should be a high number.
    if (app.keyboard.wasPressed(pc.KEY_SPACE)) {
        if (this.jumping.state === false) {
            this.entity.rigidbody.applyImpulse(0, this.jumpPower, 0);
            this.jumping.state = true;
        }
    } else if (this.jumping.state === true) {
        // If the raycast finds a collision, we assume it is an obect we can land on, we therefor reset our jump state so we can jump again.
        if (this._checkBelow() !== null) {
            this.jumping.state = false;
        }
    }
    
    // Convert x and z directional vector components to a force vector, normalise and then scale to the movement speed.
    if (x !== 0 || z !== 0) {
        x *= dt;
        z *= dt;
        
        force.set(x, 0, z).normalize().scale(this.movementSpeed);
        
        this.entity.translate(force);
        this.entity.rigidbody.applyForce(force);
        this.entity.rigidbody.syncEntityToBody();
    }
    
    // Если была нажата клавиша R, то нужно вызвать функцию reset()
    if (app.keyboard.wasPressed(pc.KEY_R)) {
        this.reset();
    }
};

// Обновляем позицию камеры (postUpdate) после отработки Game Loop (update) для расчета позиции игрока
// Rotate the player to face the same direction as the camera angle
PlayerMovement.prototype.postUpdate = function(dt) {
    // Установка координат для дижения модели перпендикулярно Plain (в противном случае - физика не работает)
    var targetY = this.cameraEntity.script.playerCameraMovement.eulers.x;
    var targetAngle = new pc.Vec3(0, targetY, 0);
    this.entity.setEulerAngles(targetAngle);
};

// Raycast for checking if there is an entity below with collision and rigid body components. Returns null if no collision.
// Make sure the scene has a entity to use as a raycast point at the base of your character.
PlayerMovement.prototype._checkBelow = function() {
    return this.app.systems.rigidbody.raycastFirst(this.entity.getPosition(), this.raycastPlayerBase.getPosition());
};

PlayerMovement.prototype.reset = function () {
    this.entity.rigidbody.teleport(0, 0.5, 0);
    this.entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
    this.entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
};

#2

The problem was solved. I changed the code this way:

// Create PlayerMovement script.
var PlayerMovement = pc.createScript('playerMovement');

// Add attributes to the script.
PlayerMovement.attributes.add('movementSpeed', {
    type: 'number',
    default: 0.025
});

PlayerMovement.attributes.add('jumpPower', {
    type: 'number',
    default: 200.0
});

PlayerMovement.attributes.add('raycastPlayerBase', {
    type: 'entity'
});

PlayerMovement.attributes.add('cameraEntity', {
    type: 'entity'
});

// initialize code called once per entity
PlayerMovement.prototype.initialize = function() {
    this.eulers = new pc.Vec3();
    this.force = new pc.Vec3();
    this.jumping = {
        state: false
    };
};

// Обновление кода каждый кадр позицию игрока
PlayerMovement.prototype.update = function(dt) {
    // Get application reference.
    var app = this.app;
    
    // Get players force vector.
    var force = this.force;
    
    // Get camera direction vectors.
    var forward = this.cameraEntity.forward;
    var right = this.cameraEntity.right;
    
    // Movement logic. Listen for key presses and apply changes to directional vector components.
    var x = 0;
    var z = 0;
    
    if (app.keyboard.isPressed(pc.KEY_W)) {
        x += forward.x;
        z += forward.z;
    }
    
    if (app.keyboard.isPressed(pc.KEY_A)) {
        x -= right.x;
        z -= right.z;
    }
    
    if (app.keyboard.isPressed(pc.KEY_S)) {
        x -= forward.x;
        z -= forward.z;
    }

    if (app.keyboard.isPressed(pc.KEY_D)) {
        x += right.x;
        z += right.z;
    }
    
    // Jump code, checking if the space key was pressed instead of is pressed. This is important as we don't want to call the jump code multiple times.
    // We set a jump state to ensure that we can't jump whilst already jumping.
    // The jump power is passed in from the script attributes. This should be a high number.
    if (app.keyboard.wasPressed(pc.KEY_SPACE)) {
        if (this.jumping.state === false) {
            this.entity.rigidbody.applyImpulse(0, this.jumpPower, 0);
            this.jumping.state = true;
        }
    } else if (this.jumping.state === true) {
        // If the raycast finds a collision, we assume it is an obect we can land on, we therefor reset our jump state so we can jump again.
        if (this._checkBelow() !== null) {
            this.jumping.state = false;
        }
    }
    
    // Convert x and z directional vector components to a force vector, normalise and then scale to the movement speed.
    if (x !== 0 || z !== 0) {
        x *= dt;
        z *= dt;
        
        force.set(x, 0, z).normalize().scale(this.movementSpeed);
        this.entity.rigidbody.applyForce(force);
    }
    
    // Если была нажата клавиша R, то нужно вызвать функцию reset()
    if (app.keyboard.wasPressed(pc.KEY_R)) {
        this.reset();
    }
};

// Обновляем позицию камеры (postUpdate) после отработки Game Loop (update) для расчета позиции игрока
// Rotate the player to face the same direction as the camera angle
PlayerMovement.prototype.postUpdate = function(dt) {
    // Установка координат для дижения модели перпендикулярно Plain (в противном случае - физика не работает)
    var targetY = this.cameraEntity.script.playerCameraMovement.eulers.x;
    var targetAngle = new pc.Vec3(0, targetY, 0);
    this.entity.setEulerAngles(targetAngle);
};

// Raycast for checking if there is an entity below with collision and rigid body components. Returns null if no collision.
// Make sure the scene has a entity to use as a raycast point at the base of your character.
PlayerMovement.prototype._checkBelow = function() {
    return this.app.systems.rigidbody.raycastFirst(this.entity.getPosition(), this.raycastPlayerBase.getPosition());
};

PlayerMovement.prototype.reset = function () {
    this.entity.rigidbody.teleport(0, 0.5, 0);
    this.entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
    this.entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
};