platjs
Version:
Simple engine for platformer physics and rendering
205 lines (194 loc) • 4.88 kB
text/typescript
import GameObject, { emptyRenderFunction } from "./object";
import PhysicalBody from "./physicalBody";
export default class ControlledBody extends PhysicalBody {
maxXSpeed: number;
jumpVel: number;
keys: {
w: boolean;
a: boolean;
s: boolean;
d: boolean;
top: boolean;
bottom: boolean;
right: boolean;
left: boolean;
};
xAcceleration: number;
jumps: number;
maxJumps: number;
wallJumps: boolean;
wallPushOffSpeed: number;
/**
* 0 for left, 1 for center, 2 for right
*/
wallSide: 0 | 1 | 2;
constructor({
x = 0,
y = 0,
rotation = 0,
width = 0,
height = 0,
image = null,
color = null,
layer = 0,
mass = 1,
render = null,
update = () => {},
maxXSpeed = 5,
jumpVel = 13,
maxJumps = 1,
wallJump = false,
wallPushOffSpeed = 3,
onCollide = () => {},
}: {
x?: number;
y?: number;
rotation?: number;
width?: number;
height?: number;
image?: HTMLImageElement | null;
color?: string | null;
layer?: number;
mass?: number;
render?: emptyRenderFunction | null;
update?: (self: ControlledBody) => void;
maxXSpeed?: number;
jumpVel?: number;
maxJumps?: number;
wallJump?: boolean;
wallPushOffSpeed?: number;
onCollide?: (object: GameObject) => void;
} = {}) {
super({
x,
y,
rotation,
width,
height,
image,
color,
layer,
mass,
render,
update: (mulitplier: number) => {
update(this);
this.updateHorizontalMovement(mulitplier);
},
onCollide,
});
this.maxXSpeed = maxXSpeed;
this.jumpVel = jumpVel;
this.maxJumps = maxJumps;
this.jumps = 0;
this.wallJumps = wallJump;
this.wallPushOffSpeed = wallPushOffSpeed;
this.wallSide = 1;
this.keys = {
w: false,
a: false,
s: false,
d: false,
top: false,
bottom: false,
right: false,
left: false,
};
this.xAcceleration = 0.3;
}
getPreventFriction() {
let val = 0;
if (this.keys.right) val++;
if (this.keys.left) val--;
if (this.keys.d) val++;
if (this.keys.a) val--;
return val !== 0;
}
jump() {
if (this.jumps < this.maxJumps) {
this.v.y = -this.jumpVel;
this.jumps++;
if (this.wallSide === 0) {
this.v.x = -this.wallPushOffSpeed;
} else if (this.wallSide === 2) {
this.v.x = this.wallPushOffSpeed;
}
}
}
bindKeyboardControls({
wasd = true,
arrowKeys = true,
spaceJump = true,
} = {}) {
if (wasd) {
window.addEventListener("keydown", this.wasdKeyListener.bind(this), true);
window.addEventListener("keyup", this.wasdKeyListener.bind(this), true);
}
if (arrowKeys) {
window.addEventListener(
"keydown",
this.arrowKeyListener.bind(this),
true
);
window.addEventListener("keyup", this.arrowKeyListener.bind(this), true);
}
if (spaceJump) {
window.addEventListener(
"keydown",
this.spaceKeyListener.bind(this),
true
);
window.addEventListener("keyup", this.spaceKeyListener.bind(this), true);
}
}
private wasdKeyListener({ key, repeat, type }: KeyboardEvent) {
if (repeat) return;
const val = type === "keydown";
if (val && key.toLowerCase() === "w") {
this.jump();
}
if (key.toLowerCase() === "d") {
this.keys.d = val;
}
if (key.toLowerCase() === "s") {
// maybe do something?
this.keys.left = val;
}
if (key.toLowerCase() === "a") {
this.keys.a = val;
}
}
private arrowKeyListener({ key, type, repeat }: KeyboardEvent) {
if (repeat) return;
const val = type === "keydown";
if (val && key === "ArrowUp") {
this.jump();
}
if (key === "ArrowRight") {
this.keys.right = val;
}
if (key === "ArrowDown") {
this.keys.bottom = val;
}
if (key === "ArrowLeft") {
this.keys.left = val;
}
}
private spaceKeyListener({ key, repeat, type }: KeyboardEvent) {
const val = type === "keydown";
if (repeat) return;
if (val && key === " ") {
this.jump();
}
}
private updateHorizontalMovement(mulitplier: number) {
if (this.keys.a || this.keys.left) {
if (this.v.x > -this.maxXSpeed)
this.v.x -= this.xAcceleration * mulitplier;
}
if (this.keys.d || this.keys.right) {
if (this.v.x < this.maxXSpeed)
this.v.x += this.xAcceleration * mulitplier;
}
// this.v.x = Math.max(-this.maxXSpeed, Math.min(this.maxXSpeed, this.v.x));
}
}