P5

2AFC課題(画像版)

課題内容

左右に提示される画像のうち、好きな方の画像をキーボードの矢印キー(左キー or 右キー)で回答する課題です。回答には制限時間があり、4秒以内に回答しないと次の試行に進みます。回答をするとその時点ですぐ次の試行が始まります。全試行が終わると、反応キーと反応時間が記録されたテキストファイルが保存されます。

実行例

エンター(リターン)キーを押すとブラウザ上でのデモ実験が始まります。
注意:ブラウザがIEだと実験画面が表示されない可能性があります。なるべく新しいバージョンのChromeやFirefoxをお使いください。なお、このブラウザ上のデモではデータの保存処理は省略されています。

コード

// Experimental settings
boolean isDebug;
int numTrial;
int fixationDuration;
int judgementDuration;

// Variables
int currentState; // variable for controling state
int currentTrial; // current trial id
int baseTime; // variable for controlling state duration
int[][] imgOrder; // presentation order of stimuli
int[] response; // variable for storing participant's response
int[] RT; // variable for storing RT (reaction time)
PImage[] img;


void setup(){
  size( 800, 600 );
  frameRate( 60 );
  
  // Define experimental settings
  isDebug = false; // if true, debug information is displayed
  numTrial = 3;
  fixationDuration = 1000; // [milliseconds]
  judgementDuration = 4000; // [milliseconds]
  
  // initialize valuables
  currentState = 0;
  currentTrial = 0;
  baseTime = 0;
  imgOrder = new int[][]{ { 0, 1, 2 }, { 3, 4, 5} };
  response = new int[ numTrial ];
  RT = new int[ numTrial ];
  img = loadImagesOfFile( sketchPath + "/data/img" );
  textFont( createFont( "Georgia", 24 ));
}


void draw() {
  background( 80 );
  
  if( currentState == 0 ){
    titlePhase();
  } else if( currentState == 1 ){
    fixationPhase();
  } else if( currentState == 2 ){
    responsePhase();
  } else if( currentState == 3 ){
    endPhase();
  }
  
  if( isDebug ){ drawDebugInfo(); }
}


void titlePhase(){
  // draw message
  fill( 255 );
  text( "Press Enter button to start experiment.", 100, height * 0.8 );
}


void fixationPhase(){
  // draw fixation cross
  stroke( 200 ); // define gray scale color (0 to 255) of lines
  strokeWeight( 3 );
  line( width/2 - 10, height/2, width/2 + 10, height/2 ); //horizontal line
  line( width/2, height/2 - 10, width/2, height/2 + 10 ); //vertical line
  
  // check elapsed time to transit state
  int elapsedTime = millis() - baseTime;
  if( elapsedTime > fixationDuration ){
    transitState();
  }
}


void responsePhase(){
  // draw stimuli
  image( img[ imgOrder[ 0 ][ currentTrial ] ],  30, 185, 350, 231 );
  image( img[ imgOrder[ 1 ][ currentTrial ] ], 420, 185, 350, 231 );
  
  // check elapsed time to transit state
  int elapsedTime = millis() - baseTime;
  if( elapsedTime > judgementDuration ){
    transitState();
  }
}


void endPhase(){
  fill( 255 );
  text( "Thank you for your time!", 200, height * 0.8 );
}


void transitState(){
  if( currentState == 1 ){
    currentState = 2;
    baseTime = millis();
  } else {
    if( currentTrial == numTrial - 1 ){
      // if all the trials have done, save data and transit to state 3.
      saveData();
      currentState = 3;
    } else {
      // move on to next trial
      currentTrial++;
      currentState = 1;
      baseTime = millis();
    }
  }
}


void keyPressed() {
  if ( key == ENTER || key == RETURN ){
    if( currentState == 0 ){
      currentState = 1;
      baseTime = millis();
    }
  } else if ( keyCode == LEFT ) {
    if( currentState == 2 ){
      // record performance
      response[ currentTrial ] = 1;
      RT[ currentTrial ] = millis() - baseTime;
      // transit state
      transitState();
    }
  } else if ( keyCode == RIGHT ) {
    if( currentState == 2 ){
      // record performance
      response[ currentTrial ] = 2;
      RT[ currentTrial ] = millis() - baseTime;
      // transit state
      transitState();
    }
  }
}


void saveData(){
  String fileName = "data/result.txt";
  String[] dataStrings = new String[ numTrial ];
  for( int i=0; i < numTrial; i++ ){
    dataStrings[ i ] = nf( response[i], 1 ) + "\t" + nf( RT[i], 4 );
  }
  saveStrings( fileName, dataStrings );
}


void drawDebugInfo(){
  fill( 255 ); // set font color
  text("currentState: " + currentState, 20, 30 );
  text("currentTrial: " + currentTrial, 20, 60 );
  //float elapsedTime = (millis() - baseTime) / 1000.0;
  //text("elapsedTime: " + nf( elapsedTime, 1, 2 ), 20, 90 );
}


PImage[] loadImagesOfFile( String dir ){
  String[] fileNames = listFileNames( sketchPath + "/data/img" );
  PImage[] img = new PImage[ fileNames.length ];
  for( int i = 0; i < img.length; i++ ){
    img[ i ] = loadImage( dir + "/" + fileNames[ i ] );
  }
  return img;
}


String[] listFileNames(String dir) {
  File file = new File(dir);
  if (file.isDirectory()) {
    String names[] = file.list();
    return names;
  } else { // If it's not a directory
    return null;
  }
}

ダウンロード

このプログラムファイルは下記のリンクからダウンロードできます。
p5_2afc.zip [306kb]

コメント

Copied title and URL