Forum Discussion

NathanJones-b1f's avatar
NathanJones-b1f
Community Member
2 years ago

Can you show storyline quiz score as a percentage?

We've build a game show quiz with Articulate Storyline with 3 stages, 5 question in each stage with a total of 15 questions. For every correct answer, the user gets 100 point and the aim of the course is to get as much of a high score as possible. We are having issue reporting the course/quiz on the LMS we are using. We  tried to run a report on our LMS to report on percentage using the field 'SCORM 2004 Quiz Data - Quiz score' but its not showing the correct percentage score. For example, one result was 1400 points (14/15) so the percentage score should show 93% but its shows 33%. Below is a screenshot showing this:

 All the relevant quiz setting have been selected to score on, we have a 'submit score' trigger on the final slide when the timeline starts. Is there anything we are missing that is causing the score to show incorrectly.

  • Hi Nathan, 

    Happy to help!

    Can I ask if you've tested the behavior on a different LMS to see if the scoring issue is specific to your LMS? If you haven't yet, here's a helpful article on testing courses in SCORM Cloud

    If you are able to replicate the scoring issue in SCORM Cloud, would you be willing to share a copy of your project file here or in private by opening a support case so we can take a closer look at what's happening? We'll delete it when we're done testing!

  • You can do this using JavaScript and xAPI statements and queries. 

    I'll show you the code I use.

     // Sends the users' answer choices and results */
    function sendAnswered(object, objectId, responseVar, success) {
        const player = GetPlayer();
        const uNamejs = player.GetVar("uName");
        const uEmailjs = player.GetVar("uEmail");
        const userResponse = player.GetVar(responseVar);
        const uScorejs = player.GetVar("uScore");
        const maxScorejs = player.GetVar("maxScore");
        const scaledScore = uScorejs / maxScorejs;
        let finalDuration = convertToIso(slideSeconds);

        const statement = {
            "actor": {  
                "name": uNamejs,
                "mbox": "mailto:" + uEmailjs
            },
            "verb": {
                "id": "http://adlnet.gov/expapi/verbs/answered",
                "display": {"en-us": "answered"}
            },
            "object": {
                "id": objectId,
                "definition": {
                    "name": {"en-us": object},
                    "description": {"en-us": "Question in the Quiz"},
                    "type": "http://adlnet.gov/expapi/activities/question"
                 },
                 "objectType": "Activity"
            },
            "result": {
                "duration": finalDuration,
                "response": userResponse,
                "score": {
                    "min": 0,
                    "max": maxScorejs,
                    "raw": uScorejs,
                    "scaled": scaledScore
                },
                "success": success
            }
        }
        const result = ADL.XAPIWrapper.sendStatement(statement);
    }

    // Function to send passed result and user score to the LRS (Learning Record Store)
    function sendPassed(object, objectId) {

    // Get references to Storyline variables
      const player = GetPlayer();
      const uNamejs = player.GetVar("uName");
      const uEmailjs = player.GetVar("uEmail");
      const uScorejs = player.GetVar("uScore");
      const maxScorejs = player.GetVar("maxScore");
      const scaledScore = uScorejs / maxScorejs;

      // Format the course duration as ISO 8601
      let finalDuration = convertToIso(courseSeconds);

      // Define the xAPI statement to send
      const statement = {
        "actor": {  
          "name": uNamejs,
          "mbox": "mailto:" + uEmailjs
        },
        "verb": {
          "id": "http://adlnet.gov/expapi/verbs/passed",
          "display": {"en-us": "passed"}
        },
        "object": {
          "id": objectId,
          "definition": {
            "name": {"en-us": object},
            "description": {"en-us": "NGTS Network Overview"},
            "type": "http://adlnet.gov/expapi/activities/assessment"
          },
          "objectType": "Activity"
        },
        "result": {
          "duration": finalDuration,
          "score": {
            "min": 0,
            "max": maxScorejs,
            "raw": uScorejs,
            "scaled": scaledScore
          },
          "success": true
        }
      };

    // Converts the time to ISO standard readable in JavaScript 
    function convertToIso(secondsVar) {
        let seconds = secondsVar;
        if (seconds > 60) {
          if (seconds > 3600) {
            const hours = Math.floor(seconds / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            seconds = (seconds % 3600) % 60;
            return `PT${hours}H${minutes}M${seconds}S`;
          } else {
            const minutes = Math.floor(seconds / 60);
            seconds %= 60;
            return `PT${minutes}M${seconds}S`;
          }
        } else {
          return `PT${seconds}S`;
        }
      }  
     
     
    Then you would want some placeholders within your storyline file for the usernames and scores.

    firsUser and firstScore

    These are pretty typically used placeholders after Devlin Peck published how to develop a leaderboard using xAPI.  So, I'll use his example in this reference so you can follow along with his instructions if you get stuck.

    I have added to the code to include debugging to help you find any errors when viewing the console log (F12 when you are viewing the exported html).
    // Function to populate Storyline leaderboard using the project variables for users and scores
    function populateLeaderboard() {
      // Create parameters for querying xAPI statements
      const parameters = ADL.XAPIWrapper.searchParams();
      parameters["verb"] = "http://adlnet.gov/expapi/verbs/passed";
      parameters["activity"] = "http://example.com/NGTSNetworkOverview";
     
      // Query the LRS for xAPI statements
      const queryData = ADL.XAPIWrapper.getStatements(parameters);
     
      // Sort the statements by scaled score in descending order
      const statements = queryData.statements;
      statements.sort(function(a, b) {
        return b.result.score.scaled - a.result.score.scaled;
      });

      // Update Storyline Player Project Variables with sorted user names and scores as percentages
      const player = GetPlayer();
      player.SetVar("firstUser", statements[0].actor.name);
      player.SetVar("secondUser", statements[1].actor.name);
      player.SetVar("thirdUser", statements[2].actor.name);
      player.SetVar("fourthUser", statements[3].actor.name);
      player.SetVar("fifthUser", statements[4].actor.name);

      // Debugging: Log the scaled scores and user scores as percentages
      console.log("Scaled Scores:", statements.map((stmt) => stmt.result.score.scaled));
      console.log("User Scores (Percentages):", statements.map((stmt) => stmt.result.score.scaled * 100 + "%"));

      // Set user scores as percentages in Storyline variables
      player.SetVar("firstScore", statements[0].result.score.scaled * 100 + "%");
      player.SetVar("secondScore", statements[1].result.score.scaled * 100 + "%");
      player.SetVar("thirdScore", statements[2].result.score.scaled * 100 + "%");
      player.SetVar("fourthScore", statements[3].result.score.scaled * 100 + "%");
      player.SetVar("fifthScore", statements[4].result.score.scaled * 100 + "%");
    }
    Please let me know if this helped you or not. Happy to chat about it via LinkedIn when you have time. 

    Scott