151 lines
4.6 KiB
JavaScript
151 lines
4.6 KiB
JavaScript
class RulesSystem {
|
|
constructor(gameState) {
|
|
this.gameState = gameState;
|
|
this.lastOffsideCheck = 0;
|
|
this.lastIcingCheck = 0;
|
|
}
|
|
|
|
update(players, puck, deltaTime) {
|
|
this.checkOffside(players, puck);
|
|
this.checkIcing(players, puck);
|
|
}
|
|
|
|
checkOffside(players, puck) {
|
|
const currentTime = Date.now();
|
|
if (currentTime - this.lastOffsideCheck < 500) return;
|
|
|
|
const puckOwner = players.find(p => p.state.hasPuck);
|
|
if (!puckOwner) return;
|
|
|
|
const centerLine = this.gameState.rink.centerX;
|
|
const offensiveZoneLine = puckOwner.team === 'home' ?
|
|
this.gameState.rink.width * 0.67 : this.gameState.rink.width * 0.33;
|
|
|
|
const puckInOffensiveZone = puckOwner.team === 'home' ?
|
|
puck.position.x > offensiveZoneLine :
|
|
puck.position.x < offensiveZoneLine;
|
|
|
|
if (puckInOffensiveZone) {
|
|
const teammates = players.filter(p =>
|
|
p.team === puckOwner.team &&
|
|
p.id !== puckOwner.id &&
|
|
p.role !== 'G'
|
|
);
|
|
|
|
const offsidePlayers = teammates.filter(teammate => {
|
|
const isAhead = puckOwner.team === 'home' ?
|
|
teammate.position.x > puck.position.x :
|
|
teammate.position.x < puck.position.x;
|
|
|
|
const inOffensiveZone = puckOwner.team === 'home' ?
|
|
teammate.position.x > offensiveZoneLine :
|
|
teammate.position.x < offensiveZoneLine;
|
|
|
|
return isAhead && inOffensiveZone;
|
|
});
|
|
|
|
if (offsidePlayers.length > 0) {
|
|
this.callOffside(puckOwner.team, offsidePlayers);
|
|
this.lastOffsideCheck = currentTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
callOffside(team, players) {
|
|
this.gameState.addEvent(`OFFSIDE - ${team.toUpperCase()}`);
|
|
|
|
const faceoffPosition = this.gameState.rink.faceoffDots[
|
|
team === 'home' ? 1 : 3
|
|
];
|
|
|
|
this.gameState.emit('offside', {
|
|
team,
|
|
players: players.map(p => p.name),
|
|
faceoffPosition
|
|
});
|
|
|
|
this.scheduleFaceoff(faceoffPosition);
|
|
}
|
|
|
|
checkIcing(players, puck) {
|
|
const currentTime = Date.now();
|
|
if (currentTime - this.lastIcingCheck < 1000) return;
|
|
|
|
if (!puck.lastTeamTouch) return;
|
|
|
|
const shootingTeam = puck.lastTeamTouch;
|
|
const shootingZoneLine = shootingTeam === 'home' ?
|
|
this.gameState.rink.width * 0.33 : this.gameState.rink.width * 0.67;
|
|
|
|
const puckCrossedOwnZone = shootingTeam === 'home' ?
|
|
puck.position.x < shootingZoneLine :
|
|
puck.position.x > shootingZoneLine;
|
|
|
|
if (!puckCrossedOwnZone) return;
|
|
|
|
const goalLine = shootingTeam === 'home' ?
|
|
this.gameState.rink.width - 50 : 50;
|
|
|
|
const puckPastGoalLine = shootingTeam === 'home' ?
|
|
puck.position.x > goalLine :
|
|
puck.position.x < goalLine;
|
|
|
|
if (puckPastGoalLine) {
|
|
const shootingPlayers = players.filter(p => p.team === shootingTeam);
|
|
const opposingPlayers = players.filter(p => p.team !== shootingTeam);
|
|
|
|
const nearestShootingPlayer = this.findNearestPlayer(puck.position, shootingPlayers);
|
|
const nearestOpposingPlayer = this.findNearestPlayer(puck.position, opposingPlayers);
|
|
|
|
if (nearestOpposingPlayer &&
|
|
nearestOpposingPlayer.position.distance(puck.position) <
|
|
nearestShootingPlayer.position.distance(puck.position)) {
|
|
|
|
this.callIcing(shootingTeam);
|
|
this.lastIcingCheck = currentTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
callIcing(team) {
|
|
this.gameState.addEvent(`ICING - ${team.toUpperCase()}`);
|
|
|
|
const faceoffPosition = this.gameState.rink.faceoffDots[
|
|
team === 'home' ? 0 : 4
|
|
];
|
|
|
|
this.gameState.emit('icing', {
|
|
team,
|
|
faceoffPosition
|
|
});
|
|
|
|
this.scheduleFaceoff(faceoffPosition);
|
|
}
|
|
|
|
|
|
scheduleFaceoff(position) {
|
|
setTimeout(() => {
|
|
this.gameState.emit('faceoff', { position });
|
|
}, 2000);
|
|
}
|
|
|
|
findNearestPlayer(position, players) {
|
|
let nearest = null;
|
|
let minDistance = Infinity;
|
|
|
|
players.forEach(player => {
|
|
const distance = player.position.distance(position);
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
nearest = player;
|
|
}
|
|
});
|
|
|
|
return nearest;
|
|
}
|
|
|
|
reset() {
|
|
this.lastOffsideCheck = 0;
|
|
this.lastIcingCheck = 0;
|
|
}
|
|
} |