AS3 - Navigating through array elements

2019-01-29 11:55发布

问题:

Hello and thank you for your time. I have an as3 code which randomly picks 5 frames out of 7, no repeats.

var mygroup1:RadioButtonGroup = new RadioButtonGroup("group1");
q1a1.group = q1a2.group = q1a3.group = q1a4.group = q1a5.group = mygroup1;

var number_array:Array = [8158,8159,8160,8161,8162,8163,8164];
var final_array:Array = [];
var count_selected:int = 5;
var i:int;

for(i = 0; i < count_selected; i++)
   {
      if(number_array.length == 0)
         break;
      else
         final_array.push(number_array.splice(Math.floor(Math.random() * number_array.length), 1)[0]);
   }

var index = 0;
var currentQuestion:int = final_array[index];
var answers:Object = {
    8158: 'B) 12',
    8159: 'F) All of the above',
    8160: 'A) True',
    8161: 'B) False',
    8162: 'C) 4',
    8163: 'F) D and E',
    8164: 'B) B'
};

var getAnswer = mygroup1.selection.label;  //Getting the selection from RadioButtonGroup

submitBtn.addEventListener(MouseEvent.CLICK, onSubmitClicked);

function onSubmitClicked(e:MouseEvent):void {
var answer:String = getAnswer();
   if (answer === answers[currentQuestion]) 
      awardScore(currentQuestion);
      ++index;
      currentQuestion = final_array[index];
      gotoAndStop(final_array[index]);
   }

and when you click on the "startBtn", it takes you to the first randomly generated frame(final_array[0]) and it's all great to start the process randomly.

Each of the next 7 frames has a submit button(b1,b2...b7) which keeps track of the score and submits the answer and also should go to the next randomly picked frame but only 5 times, following the remaining generated frames....gotoAndStop(final_array[1])...(final_array[2])....(final_array[3])....(final_array[4]).

    b1.addEventListener(MouseEvent.CLICK, quizHandler1)
    function  quizHandler1(event:MouseEvent):void{
    if(mygroup1.selection.label=="B) 12") {
        count = count + 20;
        scoreresult.text = (count).toString();
        gotoAndStop(final_array[1]);    
    }
    else{
        gotoAndStop(final_array[1]);
        }
    }

My problem is...Since the user will only go to 5 randomly picked frames out of 7, how can I make sure all the buttons in all 7 frames will listen and follow the gotoAndStop(final_array[]); statement in the order of 5? Because at the end, 2 frames will be left out, and those two frames will change randomly in every roll. I hope I could explain my dilemma. Thank you again.

回答1:

To do a quiz like yours, I think that you don't need to duplicate all content on every frame. You can put your questions in MovieClips ( or one MovieClip with many frames ) and then you can add it to your stage, and for your check box you can create it once and every time you can change just their values and labels. For buttons, you need only one button which will validate and check the current question and the go to the next one.

Take a look on this example :

var score:int;
var max_score:int;
const default_score:int = 20;

// create our questions list (7 questions) : 
var questions_list:Object = {
    // index        : to identify our question
    // movie_clip   : the class name used for AS linkage    
    1: { index : 1, movie_clip : Question1, good_answer : 'css3', first_answer : 'html5', second_answer : 'jquery', third_answer : 'css3', score : default_score }, 
    2: { index : 2, movie_clip : Question2, good_answer : 'html5', first_answer : 'html5',  second_answer : 'less', third_answer : 'ruby', score : 50 }, 
    3: { index : 3, movie_clip : Question3, good_answer : 'jquery', first_answer : 'ruby',  second_answer : 'jquery', third_answer : 'css3', score : default_score }, 
    4: { index : 4, movie_clip : Question4, good_answer : 'less', first_answer : 'less', second_answer : 'html5', third_answer : 'css3', score : 15 }, 
    5: { index : 5, movie_clip : Question5, good_answer : 'nodejs', first_answer : 'python', second_answer : 'nodejs', third_answer : 'jquery', score : 10 }, 
    6: { index : 6, movie_clip : Question6, good_answer : 'python', first_answer : 'css3', second_answer : 'html5', third_answer : 'python', score : default_score }, 
    7: { index : 7, movie_clip : Question7, good_answer : 'ruby', first_answer : 'ruby', second_answer : 'html5', third_answer : 'less', score : default_score }
};

var enabled_questions:Array = [1, 2, 3, 4, 5, 6, 7];    
var current_question:int = 0;

//----------------------------------------------------------------------------------------------------

// sprite that shows our questions 
var questions_container:Sprite = new Sprite();
    questions_container.x = questions_container.y = 20;
    questions_container.visible = false;
    addChild(questions_container);

var checks_group:RadioButtonGroup = new RadioButtonGroup('checks_group');

// sprite that contains our 3 check box 
var checks_container:Sprite = new Sprite();
    checks_container.visible = false;
    checks_container.x = int(stage.stageWidth / 2);
    checks_container.y = 50;
    addChild(checks_container);

// create our check box, 3 buttons in my case
// the 4th one is used only to uncheck every time all check box
for(var i:int = 0; i < 4; i++)
{
    var btn_check:RadioButton = new RadioButton();
        if(i != 3){
            btn_check.y = i * 30;       
        } else {

            // our 4th check box is hidden
            btn_check.visible = false;
        }
        btn_check.group = checks_group; 
        btn_check.name = 'btn_check' + i;
        checks_container.addChild(btn_check);
}

// start button
var btn_start:Button = new Button();
    btn_start.label = 'Start ! ';
    btn_start.width = 180;
    btn_start.height = 60;
    btn_start.x = int((stage.stageWidth - btn_start.width)/2);
    btn_start.y = int((stage.stageHeight - btn_start.height)/2) - 20;
    btn_start.addEventListener(MouseEvent.CLICK, startQuiz);
    addChild(btn_start);

// next button, to go to the next question
var btn_next:Button = new Button()
    btn_next.label = 'Next  >> ';
    btn_next.width = 90;
    btn_next.height = 30;
    btn_next.visible = false;
    btn_next.x = stage.stageWidth - btn_next.width - 10;
    btn_next.y = stage.stageHeight - btn_next.height - 10;
    btn_next.addEventListener(MouseEvent.CLICK, checkAnswer);
    addChild(btn_next); 

// a text field which will show the score and the current question number
var txt_score:TextField = new TextField();
    txt_score.width = 200;
    txt_score.height = 30;
    txt_score.x = stage.stageWidth - txt_score.width;
    txt_score.y = 10;
    txt_score.visible = false;
    txt_score.selectable = false;
    addChild(txt_score);

//----------------------------------------------------------------------------------------------------

function startQuiz(e:MouseEvent):void
{   
    // here we will get only 5 questions
    // I used a method from http://stackoverflow.com/questions/11980657/as3-random-array-randomize-array-actionscript-3 to shuffle the array
    // and then I remove the last 2 elements from the array
    enabled_questions = enabled_questions.sort(function(i:*,j:*){return(Math.random()<.5)?-1:1;}).slice(0,enabled_questions.length-2);

    for(var i:int = 0; i < enabled_questions.length; i++){
        var q_i:int = enabled_questions[i];
        var q:Object = questions_list[q_i];
        max_score += q.score;

        // create our questions instance and hide it
        // every question is an instance of a movieclip in our library
        // we can alse use only one movieclip and then we can use its timeline to go from a question to another
        var question = new (q.movie_clip);
            question.index = q_i;
            question.visible = false;
            questions_container.addChild(question);
    }       

    // hide the start button
    e.target.visible = false;

    // show other elements 
    questions_container.visible = checks_container.visible = btn_next.visible = txt_score.visible = true    

    // load the first question
    loadQuestion(current_question);

}

// check the answer and update score
function checkAnswer(e:MouseEvent):void 
{   
    var question:Object = questions_list[enabled_questions[current_question]];

    if(question.good_answer == checks_group.selectedData){

        // update the score
        setScore(question.score);       
    }

    if(current_question < enabled_questions.length - 1){        

        current_question ++;
        loadQuestion(current_question);

    } else {

        e.target.x = e.target.y = 0;
        e.target.enabled = false;
        e.target.width = stage.stageWidth;
        e.target.height = stage.stageHeight;
        e.target.label = 'You have finished the quiz, your score is : ' + score;

        checks_container.visible = questions_container.visible = txt_score.visible = false;

    }
}

// load question (show it) and update our check box
function loadQuestion(index:int):void 
{   
    var question:Object = questions_list[enabled_questions[index]];

    for(var i:int = 0; i < checks_container.numChildren; i++){      
        if(checks_container.getChildAt(i) is RadioButton){
            var btn:RadioButton = RadioButton(checks_container.getChildAt(i));          
            switch (btn.name){              
                case 'btn_check0' : btn.value = btn.label = question.first_answer; break;
                case 'btn_check1' : btn.value = btn.label = question.second_answer; break;
                case 'btn_check2' : btn.value = btn.label = question.third_answer; break;   
                case 'btn_check3' : btn.selected = true; break; 
            }               
        }       
    }

    for( i=0; i < questions_container.numChildren; i++){            
        if(questions_container.getChildAt(i) is MovieClip){
            var mc:MovieClip = MovieClip(questions_container.getChildAt(i));
                mc.visible = mc.index == question.index;    
        }       
    }

    // setScore is used here just to update the question number in the score text field
    setScore();

}

// show the score and current question
function setScore(new_score:int = 0){
    score += new_score;
    txt_score.text = 'Score : ' + score.toString() + ' / ' + max_score.toString() + ', Question : ' + (current_question+1) + ' / ' + enabled_questions.length;
}

// icons used in this example by Jozef Krajčovič : https://www.iconfinder.com/Jozef89

This code gives you something like this :

You can also see it working here.

Of course this is just a simple example, you can improve and adapt it to your needs.

Hope that can help.



回答2:

Sounds like you just need a single submit button that goes to the next frame. That way you don't have to worry about the order.

Some sample code to give you an idea how it might work

var index = 0;
var currentQuestion:int = final_array[index];
var answers:Object = {
  8158: '12',
  8159: '13'
  //...etc.
};

submitBtn.addEventListener(MouseEvent.CLICK, onSubmitClicked);

function onSubmitClicked(e:MouseEvent):void {
   var answer:String = getAnswer(); //get the user's answer
   if (answer === answers[currentQuestion]) {
      awardScore(currentQuestion);
      ++index;
      currentQuestion = final_array[index];
      gotoAndStop(final_array[index]);
   }
}

The idea is to have all that logic in a single click handler, once clicked it will grab the users answer and check if it is correct, if it is then it goes on to the next question.