1
0
Fork 0
forked from Simnation/Main
Main/resources/[qb]/qb-minigames/html/js/skillbar.js
2025-06-07 08:51:21 +02:00

209 lines
5.7 KiB
JavaScript

const canvas = document.getElementById("skillbar");
const context = canvas.getContext("2d");
const W = canvas.width;
const H = canvas.height;
const config = {
indicatorColor: "#FF0000",
backgroundArcColor: "#FFFFFF",
greenZoneColor: "#FFFFFF",
validKeys: [],
backgroundArcWidth: 2,
greenZoneWidth: 20,
indicatorLineWidth: 50,
keyPressColor: "#FFFFFF",
keyPressFontSize: "100px Arial", // adjust line 130 for centering if you change this
};
const difficultySettings = {
easy: {
greenZoneSize: 10, // adjust this in small increments
speed: 15,
streaksRequired: 3,
},
medium: {
greenZoneSize: 8,
speed: 25,
streaksRequired: 4,
},
hard: {
greenZoneSize: 6,
speed: 35,
streaksRequired: 5,
},
};
let lastTime = 0;
let currentDifficulty;
let needed = 1;
let streak = 0;
let time;
let degrees = 0;
let newDegrees = 0;
let gStart;
let gEnd;
let keyToPress;
let animationFrame;
// Util
const getRandomInteger = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
const degreesToRadians = (degrees) => {
return (degrees * Math.PI) / 180;
};
const radiansToDegrees = (radians) => {
return radians * (180 / Math.PI);
};
// Main Functions
const startSkillbar = (difficulty, validKeys) => {
canvas.style.display = "block";
config.validKeys = validKeys.split("");
currentDifficulty = difficulty;
const settings = difficultySettings[currentDifficulty];
needed = settings.streaksRequired;
newDegrees = 360;
keyToPress = config.validKeys[getRandomInteger(0, config.validKeys.length - 1)];
gStart = getRandomInteger(20, 40) / 10;
gEnd = gStart + settings.greenZoneSize / 10;
degrees = 0;
animateSkillbar();
};
const animateSkillbar = (timestamp) => {
if (timestamp !== undefined) {
if (lastTime === 0) {
lastTime = timestamp;
}
const deltaTime = timestamp - lastTime;
const speedPerSecond = difficultySettings[currentDifficulty].speed;
const increment = (deltaTime / 1000) * speedPerSecond * 10;
degrees += increment;
if (degrees >= newDegrees) {
handleResult(false);
} else {
renderSkillbar();
lastTime = timestamp;
animationFrame = requestAnimationFrame(animateSkillbar);
}
} else {
animationFrame = requestAnimationFrame(animateSkillbar);
}
};
const drawArc = (x, y, radius, startAngle, endAngle, strokeColor, lineWidth) => {
context.beginPath();
context.strokeStyle = strokeColor;
context.lineWidth = lineWidth;
context.arc(x, y, radius, startAngle, endAngle, false);
context.stroke();
};
const renderSkillbar = () => {
context.clearRect(0, 0, W, H);
// Draw the background arc - would like to move this so it's not redrawn but meh
drawArc(W / 2, H / 2, 100, 0, Math.PI * 2, config.backgroundArcColor, config.backgroundArcWidth);
// Draw the green zone
drawArc(W / 2, H / 2, 100, gStart - Math.PI / 2, gEnd - Math.PI / 2, config.greenZoneColor, config.greenZoneWidth);
// Draw the moving indicator
const radians = degreesToRadians(degrees);
drawArc(W / 2, H / 2, 100 - 10, radians - 0.1 - Math.PI / 2, radians - Math.PI / 2, config.indicatorColor, config.indicatorLineWidth);
// Display the key to press
const text = keyToPress.toUpperCase();
context.fillStyle = config.keyPressColor;
context.font = config.keyPressFontSize;
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(text, W / 2, H / 2 + 5);
};
const reanimateSkillbar = () => {
if (animationFrame) cancelAnimationFrame(animationFrame);
const settings = difficultySettings[currentDifficulty];
gStart = getRandomInteger(20, 40) / 10;
gEnd = gStart + settings.greenZoneSize / 10;
needed = settings.streaksRequired;
lastTime = 0;
degrees = 0;
newDegrees = 360;
keyToPress = config.validKeys[getRandomInteger(0, config.validKeys.length - 1)];
animateSkillbar();
};
// Handlers
const handleResult = (isCorrect) => {
if (animationFrame) cancelAnimationFrame(animationFrame);
if (isCorrect) {
streak++;
if (streak === needed) {
endGame(true);
} else {
reanimateSkillbar();
}
} else {
endGame(false);
}
};
const resetSkillbar = () => {
canvas.style.display = "none";
cancelAnimationFrame(animationFrame);
streak = 0;
needed = 1;
lastTime = 0;
};
const endGame = (status) => {
document.removeEventListener("keydown", handleKeyDown);
fetch(`https://${GetParentResourceName()}/skillbarFinish`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
body: JSON.stringify({ success: status }),
});
resetSkillbar();
};
const handleKeyDown = (ev) => {
const keyPressed = ev.key;
if (config.validKeys.includes(keyPressed)) {
const d_start = radiansToDegrees(gStart);
const d_end = radiansToDegrees(gEnd);
if (keyPressed === keyToPress && degrees >= d_start && degrees <= d_end) {
streak += 1;
if (streak === needed) {
endGame(true);
} else {
reanimateSkillbar();
}
} else {
endGame(false);
}
}
};
const handleWindowMessage = (event) => {
if (event.data.action === "openSkillbar") {
const difficulty = event.data.difficulty;
const validKeys = event.data.validKeys;
document.addEventListener("keydown", handleKeyDown);
startSkillbar(difficulty, validKeys);
}
};
window.addEventListener("message", handleWindowMessage);