EDITED: I think the title explains itself, but while I have a really smooth (double jump) that responds to how long the player presses the jump button, there is a problem if the space-bar stays down because the double jump will automatically happen. What I would like to see is that even if the space-bar stays down, the single jump is executed. Only when the player presses the space-bar twice, should the double jump occur.
I think this has to do more with JavaScript’s/TypeScript’s auto-repeat functionality on Events rather than the jump itself, but can anyone tell me why the jump continues when the space-bar stays down?
Here is a link to the project, since it is larger than the forum will for uploading: Dropbox - jumptests.zip - Simplify your life
The code, for reference:
@ccclass('JumpTests')
export class JumpTests extends Component {
@property({type:Vec2, tooltip: "The up velocity of the jump"})
public jumpVelocity:Vec2 = new Vec2();
@property({type:CCFloat, tooltip: "Adds latency to button push to add forgiveness if player presses jump again but has not yet hit the floor"})
public jumpDelay:number = 0.25;
@property({type:CCInteger, tooltip: "Maximum number of jumps"})
public maxJumps:number = 2;
@property({type:CCFloat, tooltip: "Added to RigidBody2D linear damping when player is stopping or changing directions"})
public linearDrag:number = 4;
@property({type:CCFloat, tooltip: "Scales gravity. Used bring the player down faster when falling"})
public gravity: number = 1;
@property({type:CCFloat, tooltip: "This is used to adjust the rate that the player falls back to the ground"})
public fallMultiplier: number = 5;
@property({type: EventHandler})
public eventHandler:EventHandler|null = null;
private _keys:Map<number, boolean> = new Map();
private _isGrounded:boolean = false;
private _jumpTimer:number = 0;
private _numOfJumps:number = 0;
private _rb:RigidBody2D| null = null;
private _bodyCollider:Collider2D|null = null;
private _footCollider:Collider2D|null = null;
private _initColliders() {
let colliders = this.getComponents(BoxCollider2D);
colliders.forEach(collider=> {
if (collider.tag === 0) {
this._bodyCollider = collider;
}
if (collider.tag === 1) {
this._footCollider = collider;
}
});
}
private _registerListeners() {
systemEvent.on(SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
systemEvent.on(SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
private _unregisterListeners() {
systemEvent.off(SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
systemEvent.off(SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
isKeyPressed(key:number) {
return this._keys.get(key);
}
isGrounded() {
let result = false;
if (this._footCollider) {
const colliderList = PhysicsSystem2D.instance.testAABB(this._footCollider.worldAABB);
colliderList.forEach(collider => {
if (collider.group === (2 << 1)) {
result = true;
}
});
}
return result;
}
// EVENT FUNCTIONS
start () {
this._rb = this.getComponent(RigidBody2D);
this._keys.set(macro.KEY.space, false);
this._initColliders();
this._registerListeners();
}
onKeyDown(event:EventKeyboard) {
this._keys.set(event.keyCode, event.isPressed);
}
onKeyUp(event:EventKeyboard) {
this._keys.set(event.keyCode, event.isPressed);
}
update(deltaTime:number) {
this._isGrounded = this.isGrounded();
if (this.isKeyPressed(macro.KEY.space)) {
this._jumpTimer = Date.now() + this.jumpDelay;
}
}
lateUpdate(deltaTime:number) {
/* What I would like to happen is that even if the space bar is down, the jump is only executed once.
* Currently, when the spacebar stays down, is the double jump is performed once, then it just bounces up and down.
* This might currently be because of JavaScript's/TS auto-repeat functionality on Events more than the jump itself.
* How do i make sure that even if the space bar is stays down, this is only executed once?
*/
if ( this.isKeyPressed(macro.KEY.space) && (this._jumpTimer > Date.now()) ) {
this.doJump(deltaTime);
}
this.modifyPhysics();
}
doJump(dt:number) {
if (this._rb) {
if (this._isGrounded) {
this._numOfJumps = 0;
}
if ( this._isGrounded || this._numOfJumps < this.maxJumps ) {
this._rb.linearVelocity = new Vec2(this._rb.linearVelocity.x, 0);
this._rb.applyForceToCenter(this.jumpVelocity, true);
this._jumpTimer = 0;
++this._numOfJumps;
this._isGrounded = false;
}
this._keys.set(macro.KEY.space, false);
}
}
modifyPhysics() {
if (this._rb) {
if (this._isGrounded) {
this._rb.linearDamping = 0
this._rb.gravityScale = 0;
} else {
// Is up in air
this._rb.gravityScale = this.gravity;
this._rb.linearDamping = 0;
if (this._rb.linearVelocity.y < 0) {
// if falling
this._rb.gravityScale = this.gravity * this.fallMultiplier;
}
else if(this._rb.linearVelocity.y > 0 && !this.isKeyPressed(macro.KEY.space)) {
// if moving upwards, but released the jump key, change jump height
this._rb.gravityScale = this.gravity * (this.fallMultiplier / 2);
}
}
}
}
}