You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

259 lines
5.7 KiB

class Command {
execute() { }
toNetwork() {
return null;
}
}
class PunchCmd extends Command {
execute(p) {
p.punch();
}
toNetwork(p) {
return {
Id: p.id,
Action: ' ',
ActionType: "keyDown"
};
}
}
class JumpCmd extends Command {
execute(p) {
p.jump();
}
toNetwork(p) {
return {
Id: p.id,
Action: 'w',
ActionType: 'keyDown'
};
}
}
class CrouchPressCmd extends Command {
execute(p) {
p.crouching = true;
}
toNetwork(p) {
return {
Id: p.id,
Action: 's',
ActionType: 'keyDown'
};
}
}
class CrouchUnpressCmd extends Command {
execute(p) {
p.crouching = false;
}
toNetwork(p) {
return {
Id: p.id,
Action: 's',
ActionType: 'keyUp'
};
}
}
class MoveLeftPressCmd extends Command {
execute(p) {
p.keys.a = true;
}
toNetwork(p) {
return {
Id: p.id,
Action: 'a',
ActionType: 'keyDown'
};
}
}
class MoveLeftUnpressCmd extends Command {
execute(p) {
p.keys.a = false;
}
toNetwork(p) {
return {
Id: p.id,
Action: 'a',
ActionType: 'keyUp'
};
}
}
class MoveRightPressCmd extends Command {
execute(p) {
p.keys.d = true;
}
toNetwork(p) {
return {
Id: p.id,
Action: 'd',
ActionType: 'keyDown'
};
}
}
class MoveRightUnpressCmd extends Command {
execute(p) {
p.keys.d = false;
}
toNetwork(p) {
return {
Id: p.id,
Action: 'd',
ActionType: 'keyUp'
};
}
}
class TalkCmd extends Command {
constructor(message) {
super();
this.message = message;
}
execute(p) {
p.talk(this.message);
}
toNetwork(p) {
return {
Id: p.id,
Action: 't',
ActionType: '',
Message: this.message
}
}
}
class DisconnectedCmd extends Command {
execute() { }
toNetwork(p) {
return {
Id: p.id,
Action: "disconnected",
ActionType: ""
};
}
}
export class InputHandler {
constructor(game) {
this.game = game;
this.downMap = new Map([
[' ', () => new PunchCmd()],
['w', () => new JumpCmd()],
['s', () => new CrouchPressCmd()],
['a', () => new MoveLeftPressCmd()],
['d', () => new MoveRightPressCmd()],
]);
this.upMap = new Map([
['s', () => new CrouchUnpressCmd()],
['a', () => new MoveLeftUnpressCmd()],
['d', () => new MoveRightUnpressCmd()],
]);
}
handleKeyDown(e, player) {
const key = e.code === 'Space' ? ' ' : (e.key || '').toLowerCase();
const k = this.downMap.get(key);
if (!k) {
return;
}
e.preventDefault();
e.stopPropagation();
this.dispatch(k(), player)
}
handleKeyUp(e, player) {
const key = e.code === "Space" ? ' ' : e.key;
const k = this.upMap.get(key);
if (!k) {
return;
}
e.preventDefault();
e.stopPropagation();
this.dispatch(k(), player)
}
dispatch(cmd, player) {
if (!player) return;
cmd.execute(player, this.game);
if (player.isLocal) {
const msg = cmd.toNetwork(player);
if (msg) {
this.game._send({
...msg,
PosX: Math.floor(player.x),
PosY: Math.floor(player.y),
Facing: player.facing,
Ts: Date.now(),
});
}
}
}
handleNetworkMessage(data) {
this.game._ensurePlayer(data.Id);
const p = this.game.players?.[data.Id];
if (!p) {
return;
}
if (typeof data.PosX === "number") {
p._lastTx = p._tx ?? data.PosX;
p._tx = data.PosX;
}
if (typeof data.PosY === "number") {
p._lastTy = p._ty ?? data.PosY;
p._ty = data.PosY;
}
if (typeof data.Facing === "number") {
p._tFacing = data.Facing;
}
p._lastUpdateTime = Date.now();
const action = data.Action;
const actionType = data.ActionType;
const apply = (cmd) => cmd && cmd.execute(p, this.game);
switch (action) {
case 'disconnected':
delete this.game.players[data.Id];
break;
case 't':
apply(new TalkCmd(data.Message ?? ""));
break;
case ' ':
apply(new PunchCmd());
break;
case 'w':
apply(new JumpCmd());
break;
case 's':
apply(actionType === 'keyDown' ? new CrouchPressCmd() : new CrouchUnpressCmd());
break;
case 'a':
apply(actionType === 'keyDown' ? new MoveLeftPressCmd() : new MoveLeftUnpressCmd());
break;
case 'd':
apply(actionType === 'keyDown' ? new MoveRightPressCmd() : new MoveRightUnpressCmd());
break;
}
}
releaseAll(player) {
const cmds = [];
if (player.keys?.a) cmds.push(new MoveLeftUnpressCmd());
if (player.keys?.d) cmds.push(new MoveRightUnpressCmd());
if (player.crouching) cmds.push(new CrouchUnpressCmd());
for (const c of cmds) this.dispatch(c, player);
}
}