209 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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);
 | 
