Advertisement
nrzmalik

WordSnap Game JavaScript Code

Mar 21st, 2025
505
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 13.19 KB | Source Code | 0 0
  1. function intapi(){
  2.   var player = GetPlayer();
  3.   var object = player.object;
  4.   var addToTimeline = player.addToTimeline;
  5.   var setVar = player.SetVar;
  6.   var getVar = player.GetVar;
  7.  
  8.   var Score = getVar('Score') || 0;
  9.   var WordCount = getVar('WordCount') || 0;
  10.   var Word = getVar('Word') || '';
  11.  
  12.   // WordPuzzle Game Module
  13.   const WordPuzzle = (function() {
  14.       // Configuration
  15.       const config = {
  16.           words: ['oil', 'oven', 'pour', 'pan', 'spoon', 'knife'],
  17.           colors: {
  18.               default: '#767EFA',
  19.               selected: '#E85C0D',
  20.               matched: '#387F39'
  21.           },
  22.           lineWidth: 5,
  23.           lineTolerance: 20
  24.       };
  25.  
  26.       // State
  27.       let state = {
  28.           isDrawing: false,
  29.           line: null,
  30.           startX: 0,
  31.           startY: 0,
  32.           selectedLetters: [],
  33.           currentWord: '',
  34.           matchedWords: new Set()
  35.       };
  36.  
  37.       // DOM Elements
  38.       const svg = createSVGElement();
  39.  
  40.       // Helper Functions
  41.       function createSVGElement() {
  42.           const svgElem = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  43.           svgElem.style.position = 'absolute';
  44.           svgElem.style.top = '0';
  45.           svgElem.style.left = '0';
  46.           svgElem.style.width = '100%';
  47.           svgElem.style.height = '100%';
  48.           svgElem.style.pointerEvents = 'none';
  49.           document.body.appendChild(svgElem);
  50.           return svgElem;
  51.       }
  52.  
  53.       function getLetterPath(letterElement) {
  54.           if (letterElement.classList.contains('slide-object-vectorshape') &&
  55.               letterElement.getAttribute('data-acc-text') &&
  56.               letterElement.getAttribute('data-acc-text').length === 1) {
  57.               const svg = letterElement.querySelector('svg[data-commandset-id]');
  58.               return svg ? svg.querySelector('g > g > path') : null;
  59.           }
  60.           return null;
  61.       }
  62.  
  63.       function isPointNearLine(px, py, x1, y1, x2, y2, tolerance) {
  64.           const lineLength = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  65.           if (lineLength === 0) return Math.sqrt((px - x1) ** 2 + (py - y1) ** 2) <= tolerance;
  66.  
  67.           const t = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / (lineLength * lineLength);
  68.           const clampedT = Math.max(0, Math.min(1, t));
  69.  
  70.           const closestX = x1 + clampedT * (x2 - x1);
  71.           const closestY = y1 + clampedT * (y2 - y1);
  72.  
  73.           return Math.sqrt((px - closestX) ** 2 + (py - closestY) ** 2) <= tolerance;
  74.       }
  75.  
  76.       function distanceAlongLine(px, py, x1, y1, x2, y2) {
  77.           const lineLength = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  78.           if (lineLength === 0) return 0;
  79.  
  80.           const t = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / (lineLength * lineLength);
  81.           const clampedT = Math.max(0, Math.min(1, t));
  82.  
  83.           return clampedT * lineLength;
  84.       }
  85.  
  86.       // Core Game Functions
  87.       function normalizeEvent(e) {
  88.           // Normalize touch and mouse events to always return clientX, clientY
  89.           if (e.touches && e.touches.length > 0) {
  90.               return {
  91.                   clientX: e.touches[0].clientX,
  92.                   clientY: e.touches[0].clientY
  93.               };
  94.           } else {
  95.               return {
  96.                   clientX: e.clientX,
  97.                   clientY: e.clientY
  98.               };
  99.           }
  100.       }
  101.  
  102.       function startDrawing(e) {
  103.           if (e.target.classList.contains('disabled')) return;
  104.  
  105.           state.isDrawing = true;
  106.           const rect = svg.getBoundingClientRect();
  107.           const { clientX, clientY } = normalizeEvent(e);
  108.           state.startX = clientX - rect.left;
  109.           state.startY = clientY - rect.top;
  110.  
  111.           state.line = document.createElementNS("http://www.w3.org/2000/svg", "line");
  112.           state.line.setAttribute("x1", state.startX);
  113.           state.line.setAttribute("y1", state.startY);
  114.           state.line.setAttribute("x2", state.startX);
  115.           state.line.setAttribute("y2", state.startY);
  116.           state.line.setAttribute("stroke", "rgba(0, 123, 255, 0.5)");
  117.           state.line.setAttribute("stroke-width", config.lineWidth);
  118.           state.line.setAttribute("stroke-linecap", "round");
  119.           svg.appendChild(state.line);
  120.       }
  121.  
  122.       function draw(e) {
  123.           if (!state.isDrawing) return;
  124.  
  125.           const rect = svg.getBoundingClientRect();
  126.           const { clientX, clientY } = normalizeEvent(e);
  127.           const endX = clientX - rect.left;
  128.           const endY = clientY - rect.top;
  129.  
  130.           state.line.setAttribute("x2", endX);
  131.           state.line.setAttribute("y2", endY);
  132.  
  133.           selectLetters(state.startX, state.startY, endX, endY);
  134.       }
  135.  
  136.       function endDrawing() {
  137.           state.isDrawing = false;
  138.           if (state.line) {
  139.               svg.removeChild(state.line);
  140.               state.line = null;
  141.           }
  142.           checkWord();
  143.           resetSelection();
  144.       }
  145.  
  146.       function selectLetters(x1, y1, x2, y2) {
  147.           state.selectedLetters = [];
  148.           state.currentWord = '';
  149.  
  150.           const letters = document.querySelectorAll('.slide-object-vectorshape[data-acc-text]');
  151.           let lettersCrossed = [];
  152.  
  153.           letters.forEach(letter => {
  154.               const rect = letter.getBoundingClientRect();
  155.               const svgRect = svg.getBoundingClientRect();
  156.               const centerX = rect.left + rect.width / 2 - svgRect.left;
  157.               const centerY = rect.top + rect.height / 2 - svgRect.top;
  158.  
  159.               if (isPointNearLine(centerX, centerY, x1, y1, x2, y2, config.lineTolerance)) {
  160.                   lettersCrossed.push({
  161.                       element: letter,
  162.                       distance: distanceAlongLine(centerX, centerY, x1, y1, x2, y2),
  163.                       x: centerX,
  164.                       y: centerY
  165.                   });
  166.               } else if (!letter.classList.contains('disabled')) {
  167.                   resetLetterStyle(letter);
  168.               }
  169.           });
  170.  
  171.           lettersCrossed.sort((a, b) => a.distance - b.distance);
  172.  
  173.           lettersCrossed.forEach(letter => {
  174.               state.selectedLetters.push(letter.element);
  175.               state.currentWord += letter.element.getAttribute('data-acc-text').toLowerCase();
  176.               if (!letter.element.classList.contains('disabled')) {
  177.                   setLetterSelected(letter.element);
  178.               }
  179.           });
  180.  
  181.          
  182.           setVar("Word", state.currentWord);
  183.       }
  184.  
  185.       function checkWord() {
  186.           if (config.words.includes(state.currentWord) && !state.matchedWords.has(state.currentWord)) {
  187.              
  188.               try {
  189.                   Score = Score + 10;
  190.                   setVar("Score", Score);
  191.                   setVar("WordCount", ++WordCount);
  192.                   setVar(state.currentWord, true);
  193.                   setVar("Word", "");
  194.                  
  195.  
  196.                   state.matchedWords.add(state.currentWord);
  197.  
  198.               } catch (error) {
  199.                   console.error('Error updating Storyline variable:', error);
  200.               }
  201.  
  202.               state.selectedLetters.forEach(letter => {
  203.                   if (!letter.classList.contains('disabled')) {
  204.                       setLetterMatched(letter);
  205.                   }
  206.               });
  207.               showMatchedWordFeedback(state.currentWord);
  208.           }
  209.       }
  210.  
  211.       // UI Functions
  212.       function setLetterSelected(letterElement) {
  213.           const path = getLetterPath(letterElement);
  214.           if (path) {
  215.               path.setAttribute('fill', 'url(#selectedGradient)');
  216.           }
  217.       }
  218.  
  219.       function setLetterMatched(letterElement) {
  220.           const path = getLetterPath(letterElement);
  221.           if (path) {
  222.               path.setAttribute('fill', 'url(#matchedGradient)');
  223.           }
  224.           letterElement.classList.add('disabled');
  225.       }
  226.  
  227.       function resetLetterStyle(letterElement) {
  228.           const path = getLetterPath(letterElement);
  229.           if (path) {
  230.               path.setAttribute('fill', 'url(#defaultGradient)');
  231.           }
  232.       }
  233.  
  234.       function resetSelection() {
  235.           state.selectedLetters.forEach(letter => {
  236.               if (!letter.classList.contains('disabled')) {
  237.                   resetLetterStyle(letter);
  238.               }
  239.           });
  240.           state.selectedLetters = [];
  241.           state.currentWord = '';
  242.           setVar("Word", "");
  243.       }
  244.  
  245.       function showMatchedWordFeedback(word) {
  246.           const feedback = document.createElement('div');
  247.           feedback.textContent = word.toUpperCase();
  248.           feedback.className = 'matched-word-feedback';
  249.           document.body.appendChild(feedback);
  250.  
  251.           // Trigger reflow to ensure the animation starts from the beginning
  252.           void feedback.offsetWidth;
  253.  
  254.           feedback.classList.add('show');
  255.  
  256.           setTimeout(() => {
  257.               feedback.classList.add('hide');
  258.               feedback.addEventListener('animationend', () => {
  259.                   document.body.removeChild(feedback);
  260.               }, { once: true });
  261.           }, 1500);
  262.       }
  263.  
  264.       // Initialize
  265.       function init() {
  266.           // Add event listeners for both mouse and touch
  267.           document.addEventListener('mousedown', startDrawing);
  268.           document.addEventListener('mousemove', draw);
  269.           document.addEventListener('mouseup', endDrawing);
  270.           document.addEventListener('mouseleave', endDrawing);
  271.  
  272.           document.addEventListener('touchstart', startDrawing);
  273.           document.addEventListener('touchmove', draw);
  274.           document.addEventListener('touchend', endDrawing);
  275.           document.addEventListener('touchcancel', endDrawing);
  276.  
  277.           const styles = `
  278.               @keyframes pop-in {
  279.                 0% { transform: translate(-50%, -50%) scale(0.5); opacity: 0; filter: blur(10px); }
  280.                 70% { transform: translate(-50%, -50%) scale(1.2); opacity: 1; filter: blur(0px); }
  281.                 100% { transform: translate(-50%, -50%) scale(1); opacity: 1; filter: blur(0px); }
  282.               }
  283.              
  284.               @keyframes pop-out {
  285.                 0% { transform: translate(-50%, -50%) scale(1); opacity: 1; filter: blur(0px); }
  286.                 100% { transform: translate(-50%, -50%) scale(1.5); opacity: 0; filter: blur(10px); }
  287.               }
  288.              
  289.               .disabled {
  290.                 opacity: 0.5;
  291.                 pointer-events: none;
  292.               }
  293.              
  294.               .matched-word-feedback {
  295.                 position: fixed;
  296.                 top: 50%;
  297.                 left: 50%;
  298.                 transform: translate(-50%, -50%);
  299.                 font-size: 58px;
  300.                 font-weight: bold;
  301.                 opacity: 0;
  302.                 font-family: "Arial", sans-serif;
  303.                 color: #ffffff;
  304.                 padding: 25px 60px;
  305.                 background: linear-gradient(135deg, #FF7F00, #E85C0D);
  306.                 border-radius: 30px;
  307.                 box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5), 0 0 20px rgba(255, 126, 95, 0.7);
  308.                 animation: pop-in 0.4s ease-out, fade-out 1s 2.5s ease-in forwards;
  309.                 text-align: center;
  310.                 z-index: 1000;
  311.                 transform-style: preserve-3d;
  312.               }
  313.              
  314.               .matched-word-feedback.show {
  315.                 animation: pop-in 0.5s ease forwards;
  316.               }
  317.              
  318.               .matched-word-feedback.hide {
  319.                 animation: pop-out 0.5s ease forwards;
  320.               }
  321.           `;
  322.  
  323.           const styleElement = document.createElement('style');
  324.           styleElement.textContent = styles;
  325.           document.head.appendChild(styleElement);
  326.  
  327.           // Add SVG gradients
  328.           const gradientsSvg = `
  329.            <svg width="0" height="0" style="position: absolute;">
  330.               <defs>
  331.                 <linearGradient id="defaultGradient" x1="0%" y1="0%" x2="100%" y2="100%">
  332.                   <stop offset="0%" style="stop-color:#408419;stop-opacity:1" />
  333.                   <stop offset="100%" style="stop-color:#89CF0B;stop-opacity:1" />
  334.                 </linearGradient>
  335.                 <linearGradient id="selectedGradient" x1="0%" y1="0%" x2="100%" y2="100%">
  336.                   <stop offset="0%" style="stop-color:#FF7F00;stop-opacity:1" />
  337.                   <stop offset="100%" style="stop-color:#E85C0D;stop-opacity:1" />
  338.                 </linearGradient>
  339.                 <linearGradient id="matchedGradient" x1="0%" y1="0%" x2="100%" y2="100%">
  340.                     <stop offset="0%" style="stop-color:#FF7E5F;stop-opacity:1" />
  341.                     <stop offset="100%" style="stop-color:#8E44AD;stop-opacity:1" />
  342.                     </linearGradient>
  343.               </defs>
  344.             </svg>
  345.           `;
  346.           document.body.insertAdjacentHTML('beforeend', gradientsSvg);
  347.  
  348.           // Reset the matchedWords set when initializing
  349.           state.matchedWords.clear();
  350.  
  351.          
  352.       }
  353.  
  354.       // Public API
  355.       return {
  356.           init: init
  357.       };
  358.   })();
  359.  
  360.   // Initialize the game
  361.   WordPuzzle.init();
  362.   }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement