Millisecond Forums

Using survey page with branching animated trials

https://forums.millisecond.com/Topic33523.aspx

By Cowdice - 11/26/2021

Hello!

I'm working on a version of the Cyberball task in which I'd like participants to rate their experience every five ball tosses. There are about 30 trials total. Part of what I'm struggling with is how to pose these ratings every five trials. Specifically, I'd like to ask a simple Likert-scale question (labelled "fairness question") and then two slider-based questions (labelled "affective slider") before the participant gets put back into the task. A further complication is that the trials are designed such that the multiples of 5 tosses are sometimes in the middle of a trial because passes between the computer players occur automatically. Given the code (which uses branching between the trials), do you have any suggestions about how to make this work? I've tried using a surveypage without much success, so I look forward to your response! Please let me know if you need any additional details.
By Dave - 11/29/2021

Cowdice - 11/27/2021
Hello!

I'm working on a version of the Cyberball task in which I'd like participants to rate their experience every five ball tosses. There are about 30 trials total. Part of what I'm struggling with is how to pose these ratings every five trials. Specifically, I'd like to ask a simple Likert-scale question (labelled "fairness question") and then two slider-based questions (labelled "affective slider") before the participant gets put back into the task. A further complication is that the trials are designed such that the multiples of 5 tosses are sometimes in the middle of a trial because passes between the computer players occur automatically. Given the code (which uses branching between the trials), do you have any suggestions about how to make this work? I've tried using a surveypage without much success, so I look forward to your response! Please let me know if you need any additional details.

> Given the code (which uses branching between the trials)

Well, you need to adjust the /branch logic accordingly. I.e. after each set of 5 game trials, /branch to your question trials. From there, /branch back to where things left off in the game.
By Cowdice - 11/29/2021

Thanks for the prompt reply, Dave. 

For folks interested in how I tackled this, see some scraps of code below :) the branching for trial RCDP is bloated, but I opted to keep it built out as a check for other conditions that have a less rigid structure!

<trial RC12>
/ ontrialbegin = [
trial.RC12.insertstimulustime(video.AtoB, expressions.cyberdecisiontime);
values.gamestate = "RC12"
]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, AtoB_static]
/ timeout = 0
/ branch = [
    if(values.trialcounterRC == 5) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 10) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 15) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 20) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 25) {surveypage.RCsurvey}
    else{trial.RC2P}
]
/ ontrialend = [values.trialcounterRC += 1]
</trial>

<trial RCDP>
/inputdevice = mouse
/ ontrialbegin = [
    values.DPcountRC += 1
]
/ validresponse = (picture.Bear, picture.Wildebeest)
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, PtoB_static]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 2) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 2) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 5) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 5) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 8) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 8) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 11) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 11) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 14) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 14) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 17) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 17) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 20) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 20) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 23) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 23) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 26) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 26) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 29) {trial.RCP1final}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 29) {trial.RCP2final}]
</trial>

<surveypage RCsurvey>
/ ontrialbegin = [values.RCsurvey +=1]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, box, box1]
/ fontstyle = ("Arial",25)
/ questions = [1= slider.fair; 2= AffectiveSlider1; 3=sleepy_face; 4=awake_face; 5=gradient1; 6=AffectiveSlider2; 7=unhappy_face; 8=happy_face; 9=gradient2]
/ showpagenumbers = false
/ nextbuttonposition = (70%, 68%)
/ branch = [
    if(values.gamestate == "RC12") {trial.RC2P}
    else if(values.gamestate == "RC21") {trial.RC1P}
    else if(values.gamestate == "RC2P") {trial.RCDP}
    else if(values.gamestate == "RC1P") {trial.RCDP}    
    else if(values.gamestate == "RCP1") {trial.RC12}
    else if(values.gamestate == "RCP2") {trial.RC21}    
]
</surveypage>
By Dave - 11/29/2021

Cowdice - 11/29/2021
Thanks for the prompt reply, Dave. 

For folks interested in how I tackled this, see some scraps of code below :) the branching for trial RCDP is bloated, but I opted to keep it built out as a check for other conditions that have a less rigid structure!

<trial RC12>
/ ontrialbegin = [
trial.RC12.insertstimulustime(video.AtoB, expressions.cyberdecisiontime);
values.gamestate = "RC12"
]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, AtoB_static]
/ timeout = 0
/ branch = [
    if(values.trialcounterRC == 5) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 10) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 15) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 20) {surveypage.RCsurvey}
    else if(values.trialcounterRC == 25) {surveypage.RCsurvey}
    else{trial.RC2P}
]
/ ontrialend = [values.trialcounterRC += 1]
</trial>

<trial RCDP>
/inputdevice = mouse
/ ontrialbegin = [
    values.DPcountRC += 1
]
/ validresponse = (picture.Bear, picture.Wildebeest)
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, PtoB_static]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 2) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 2) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 5) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 5) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 8) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 8) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 11) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 11) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 14) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 14) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 17) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 17) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 20) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 20) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 23) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 23) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 26) {trial.RCP1}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 26) {trial.RCP2}]
/ branch = [if(trial.RCDP.response == "Bear" && values.trialcounterRC == 29) {trial.RCP1final}]
/ branch = [if(trial.RCDP.response == "Wildebeest" && values.trialcounterRC == 29) {trial.RCP2final}]
</trial>

<surveypage RCsurvey>
/ ontrialbegin = [values.RCsurvey +=1]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, box, box1]
/ fontstyle = ("Arial",25)
/ questions = [1= slider.fair; 2= AffectiveSlider1; 3=sleepy_face; 4=awake_face; 5=gradient1; 6=AffectiveSlider2; 7=unhappy_face; 8=happy_face; 9=gradient2]
/ showpagenumbers = false
/ nextbuttonposition = (70%, 68%)
/ branch = [
    if(values.gamestate == "RC12") {trial.RC2P}
    else if(values.gamestate == "RC21") {trial.RC1P}
    else if(values.gamestate == "RC2P") {trial.RCDP}
    else if(values.gamestate == "RC1P") {trial.RCDP}    
    else if(values.gamestate == "RCP1") {trial.RC12}
    else if(values.gamestate == "RCP2") {trial.RC21}    
]
</surveypage>

That's a perfectly fine solution. A few remarks.

- You can get rid of lots ot else-if logic if you reset values.trialcounterRC to zero every five trials (or you could check mod(values.trialcounterRC, 5) == 0).

<values>
/ trialcounterRC = 0
...
</values>

<trial RC12>
/ ontrialbegin = [
trial.RC12.insertstimulustime(video.AtoB, expressions.cyberdecisiontime);
values.gamestate = "RC12"
]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, AtoB_static]
/ timeout = 0
/ branch = [
  if (values.trialcounterRC == 5) {
   // reset trial counter to zero
   values.trialcounterRC = 0;

   return surveypage.RCsurvey;
  } else {
   return trial.RC2P;
  };
]
/ ontrialend = [values.trialcounterRC += 1]
</trial>

- Similarly, you should be able to get rid of much of the gamestate-related if-else-if logic if you use a list to hold the trial object the game should return to. I.e. something like

<list nexttrial>
</list>

<trial RC12>
/ ontrialbegin = [
trial.RC12.insertstimulustime(video.AtoB, expressions.cyberdecisiontime);
values.gamestate = "RC12"
]
/ stimulustimes = [0= Bear, Wildebeest, YOU, picture.chosenavatar, AtoB_static]
/ timeout = 0
/ branch = [
  if (values.trialcounterRC == 5) {
   // reset trial counter to zero
   values.trialcounterRC = 0;
   // reset the list
   list.nexttrial.reset();
   // populate it with trial object to resume at
   list.nexttrial.appenditem(trial.RC2P);
   return surveypage.RCsurvey;
  } else {
   return trial.RC2P;
  };
]
/ ontrialend = [values.trialcounterRC += 1]
</trial>

with

<surveypage RCsurvey>
...
/ branch = [
  return list.nexttrial.nextvalue;
]
</surveypage>
By Cowdice - 11/29/2021

Really appreciate the additional comments! As I work through the other conditions, I'll try to implement both suggestions to slim the code.