API Docs for:
Show:

File: gameplay\movement\jumping\System.js

/**
 System responsible for handling jumping. It handles regular jumping, wall jumping and double jumping. All jumping requires that the
 entity is a valid dynamic physics object, also the GroundedMovement and the Jumping components are required. Other than that,
 wall jumping requires the WallJumping component and double jumping requires the DoubleJumping component. Jumping is executed via the
 input and AI systems triggering the 'jump' event. Jumps can be performed only immediately when the 'jump' event is triggered, so f.e.
 holding the 'jump' button won't make the entity constantly jump. The jump strength is modified by the JumpPowerSpellEffects, if present.
 This system plays animations. The animations played are 'jumpLeft', 'jumpRight' for regular jumps, 'wallJumpLeft' when an entity jumps
 off of a wall on the right, for a wall on the left the 'wallJumpRight' animation is played. Double jumping plays the 'doubleJumpLeft'
 and 'doubleJumpRight' animations.
 @class JumpingSystem
 @constructor
 @param entitySystemManager {Manager} The entity system manager whose entities this system will be working on.
 @param inputSystem {KeyboardInputSystem}
 @param aISystem {AISystem}
 @param physicsSystem {PhysicsSystem}
 @param collisionMasks {Object} An object holding bit masks used for determining collision categories.
 */
function JumpingSystem(entitySystemManager, inputSystem, aISystem, physicsSystem, collisionMasks){
    
    //System variables.
    var JUMP_ANIMATION_PRIORITY = 3,
    
    //Facing directions.
        right = 'right',
        left = 'left',
        
    //Animation names,
        jumpLeft = 'jumpLeft',
        jumpRight = 'jumpRight',
        wallJumpLeft = 'wallJumpLeft',
        wallJumpRight = 'wallJumpRight',
        doubleJumpLeft = 'doubleJumpLeft',
        doubleJumpRight = 'doubleJumpRight';

    //=====Input handling=====
    
    var jumpEventCallback = (function(){
        
        var jumpImpulse = new Vector2D(),
            entityPosition = new Vector2D(),
            entityVelocity = new Vector2D(),
            queryingRay = new Ray();
        
        return function(entity){
            var groundedMovement = entity.get(GroundedMovement),
                jumping = entity.get(Jumping),
                wallJumping = entity.get(WallJumping),
                doubleJumping = entity.get(DoubleJumping),
                position = entity.get(Position),
                movable = entity.get(Movable),
                spellEffects = entity.get(SpellEffects),
                facingDirection = entity.get(FacingDirection),
                animation = entity.get(Animation);
            
            if(!(groundedMovement && jumping && movable)){
                return;
            }
            
            //This piece of code prevents the player from being able to continously jump by holding the jump button.
            jumping._pressedJump = true;        
            if(!jumping._canJump){
                return;
            }
            
            //This value is 1 by default. If this entity is affected by jump power spell effects, the value will get
            //adjusted apropriately and it'll then be used to calculate the final jump impulse applied.
            var jumpPowerMultiplier = 1;
            
            if(spellEffects){
                for(var node=spellEffects.getJumpPowerSpellEffects().getFirst(); node; node=node.next){
                    jumpPowerMultiplier *= node.value.getJumpPowerMultiplier();
                }
            }
            
            //If the entity is on the ground, perform a regular jump.
            if(groundedMovement.isOnGround()){
                //Remove vertical velocity before applying the jump impulse.
                movable.getVelocity(entityVelocity);
                movable.setVelocity(entityVelocity.x, 0);
                    
                jumpImpulse.x = 0;
                jumpImpulse.y = -1;
                jumpImpulse.multiply(jumping._jumpImpulseMagnitude * jumpPowerMultiplier);
                movable.applyImpulse(jumpImpulse);
                
                groundedMovement._onGroundTimeRemaining = 0;
                
                if(facingDirection && animation){
                    switch(facingDirection.getFacingDirection()){
                        case left : animation.play(jumpLeft, JUMP_ANIMATION_PRIORITY);
                            break;
                        case right : animation.play(jumpRight, JUMP_ANIMATION_PRIORITY);
                            break;
                    }
                }
                
                return;
            }
            
            //If the entity is not on the ground, check if it's near a wall, if it is, perform a wall jump.
            if(position && wallJumping && wallJumping._wallDetectorRightRay){
                
                position.getPosition(entityPosition);
                
                //Check for a wall on the left side.
                queryingRay.begin.x = entityPosition.x - wallJumping._wallDetectorRightRay.begin.x;
                queryingRay.begin.y = entityPosition.y + wallJumping._wallDetectorRightRay.begin.y;
                queryingRay.vector.x = -wallJumping._wallDetectorRightRay.vector.x;
                queryingRay.vector.y = wallJumping._wallDetectorRightRay.vector.y;
                
                var rayCastQuery = physicsSystem.world.queryEntitiesWithRay(queryingRay, 0xFFFFFFFF, collisionMasks.wall);
                
                if(rayCastQuery){
                    //Remove velocity before applying the jump impulse.
                    movable.setVelocity(0, 0);
                    
                    wallJumping.getWallJumpRightImpulse(jumpImpulse);
                    jumpImpulse.multiply(jumpPowerMultiplier);
                    movable.applyImpulse(jumpImpulse);
                    //The entity is now facing right since it jumped off of the left wall.
                    if(facingDirection){
                        facingDirection.setFacingDirection(right);
                        
                        if(animation){
                            animation.play(wallJumpRight, JUMP_ANIMATION_PRIORITY);
                        }
                    }
                    //Reset the number of double jump charges if the entity has the component.
                    if(doubleJumping){
                        doubleJumping._numberOfChargesRemaining = doubleJumping._numberOfCharges;
                    }
                    
                    return;
                }
                
                //Check for a wall on the right side.
                entityPosition.added(wallJumping._wallDetectorRightRay.begin, queryingRay.begin);
                queryingRay.vector.x = wallJumping._wallDetectorRightRay.vector.x;
                queryingRay.vector.y = wallJumping._wallDetectorRightRay.vector.y;
                
                rayCastQuery = physicsSystem.world.queryEntitiesWithRay(queryingRay, 0xFFFFFFFF, collisionMasks.wall);
                
                if(rayCastQuery){
                    //Remove velocity before applying the jump impulse.
                    movable.setVelocity(0, 0);
                    
                    wallJumping.getWallJumpRightImpulse(jumpImpulse);
                    jumpImpulse.x = -jumpImpulse.x;
                    jumpImpulse.multiply(jumpPowerMultiplier);
                    movable.applyImpulse(jumpImpulse);
                    //The entity is now facing left since it jumped off of the right wall.
                    if(facingDirection){
                        facingDirection.setFacingDirection(left);
                        
                        if(animation){
                            animation.play(wallJumpLeft, JUMP_ANIMATION_PRIORITY);
                        }
                    }
                    //Reset the number of double jump charges if the entity has the component.
                    if(doubleJumping){
                        doubleJumping._numberOfChargesRemaining = doubleJumping._numberOfCharges;
                    }
                    
                    return;
                }
                
            }
            
            //If the entity is not on the ground and is not near a wall, perform a double jump.
            if(doubleJumping){
                
                if(doubleJumping.canDoubleJump()){
                    //Remove vertical velocity before applying the jump impulse.
                    movable.getVelocity(entityVelocity);
                    movable.setVelocity(entityVelocity.x, 0);
                    
                    jumpImpulse.x = 0;
                    jumpImpulse.y = -1;
                    jumpImpulse.multiply(doubleJumping._doubleJumpImpulseMagnitude * jumpPowerMultiplier);
                    movable.applyImpulse(jumpImpulse);
                    
                    doubleJumping._numberOfChargesRemaining--;
                    
                    if(facingDirection && animation){
                        switch(facingDirection.getFacingDirection()){
                            case left : animation.play(doubleJumpLeft, JUMP_ANIMATION_PRIORITY);
                                break;
                            case right : animation.play(doubleJumpRight, JUMP_ANIMATION_PRIORITY);
                                break;
                        }
                    }
                }
            }
        };
    })();
    
    inputSystem.subscribe('jump', jumpEventCallback);
    aISystem.subscribe('jump', jumpEventCallback);
    
    var jumpingEntities = entitySystemManager.createAspect([Jumping]),
        doubleJumpingEntities = entitySystemManager.createAspect([DoubleJumping, GroundedMovement]);
    
    /**
     @method update
     */
    this.update = (function(){
        
        function updateJumpingEntity(entity){
            var jumping = entity.get(Jumping);
            
            //This piece of code prevents the player from being able to continously jump by holding the jump button.
            if(jumping._pressedJump){
                jumping._canJump = false;
            }else{
                jumping._canJump = true;
            }
            jumping._pressedJump = false;
        }
        
        function updateDoubleJumpingEntity(entity){
            var doubleJumping = entity.get(DoubleJumping),
                groundedMovement = entity.get(GroundedMovement);
            
            //Reset the number of double jump charges if the entity is on the ground.
            if(groundedMovement.isOnGround()){
                doubleJumping._numberOfChargesRemaining = doubleJumping._numberOfCharges;
            }
        }
        
        return function(){
            jumpingEntities.iterate(updateJumpingEntity);
            doubleJumpingEntities.iterate(updateDoubleJumpingEntity);
        };
    })();
    
    /**
     @method destroy
     */
    this.destroy = function(){
        inputSystem.unsubscribe('jump', jumpEventCallback);
        aISystem.unsubscribe('jump', jumpEventCallback);
        
        jumpingEntities.destroy();
        doubleJumpingEntities.destroy();
    }
}