Reputation: 93
I have created a game for a new study I will be running using Psychtoolbox (3.0.13, flavor beta) in Matlab R2018a, and the condition to exit my while-loop in a trial, which is a spacebar press, sometimes works immediately but sometimes needs several key presses in order to exit.
I have tried making my code more efficient, by removing any unnecessary code and putting in wait times before showing the stimuli in case this would solve the issue. I have a while loop that needs input from mouse clicks alongside a spacebar press to satisfy the exit conditions. The code does run in the end, but I just do not understand why sometimes a single spacebar press is enough, and other times I need to press it 3 times to exit. I have the same problem in another task where I also use mouse clicks and a spacebar press (and no sound, so I don't think the sound is causing it) as conditions to exit a while loop. I wonder if this has anything to do with the way I use the RECS structure, and if I could maybe use a more efficient way. It would be amazing if anyone has any idea as to how to improve this in the task.
% Start game: They play a total of 5 games. A game finishes when
% they have selected at least 1 card and pressed spacebar.
for Game = 1:5
% If ESC is pressed, quit game.
if OM.ESC == 0
% Draw wooden background
Screen('DrawTexture', OM.wid, OM.greywoodTexture);
% Show score and game counter
Screen('TextSize', OM.wid, OM.textSize);
DrawFormattedText(OM.wid, ['Score: ', num2str(OM.Score)], ...
OM.origin(1)+750, OM.origin(2)-400);
DrawFormattedText(OM.wid, ['Game: ', num2str(Game)], ...
OM.origin(1), OM.origin(2)-425);
% create sequence for where Randy wil be and randomise it
sequence = [1 0 0 0 0 0 0 0 0 0];
sequence = sequence(randperm(length(sequence)));
% Draw the cards upside down
for i = 1:length(RECS)
Screen('DrawTexture', OM.wid, OM.cardsTexture, [], RECS(i).rectangles);
end
% Show the cards and get the time. If it's the first game, use 0.5
% seconds before showing to make sure the game is up to speed. (Thought
% this might help with speed later on, not sure if it does.)
if Game == 1
WaitSecs(0.5);
end
timage = GetSecs;
Screen('Flip', OM.wid);
% set screenpress and loss to 0
Screenpress = 0;
loss = 0;
% wait for screenpress (space bar press)
while Screenpress == 0 && OM.ESC == 0 % checks for completion
[keyIsDown, keyTime, keyCode] = KbCheck;
if keyIsDown
keyStroke = KbName(keyCode);
% check if space was pressed and atleast one card was
% selected
if any(strcmpi(keyStroke,OM.screenKey)) && sum([RECS(:).pressed]) ~= 0
Screenpress = 1;
RT = round((keyTime - timage)*1000);
elseif any(strcmpi(keyStroke,OM.exitKey))
OM.ESC = 1;
RT = 0;
break;
end
end
% check if the mouse was pressed inside any of the rectangles
% (cards)
[mx,my,buttons] = GetMouse(); %waits for a key-press
for i = 1:length(RECS)
if IsInRect(mx, my, RECS(i).rectangles) == 1 && sum(buttons) > 0 && RECS(i).pressed == 0
RECS(i).pressed = 1;
elseif IsInRect(mx, my, RECS(i).rectangles) == 1 && sum(buttons) > 0 && RECS(i).pressed == 1
% This is to enable de-selecting a card by double
% clicking on it.
RECS(i).pressed = 0;
end
end
% Draw wooden background
Screen('DrawTexture', OM.wid, OM.greywoodTexture);
% Draw score counter
Screen('TextSize', OM.wid, OM.textSize);
DrawFormattedText(OM.wid, ['Score: ', num2str(OM.Score)], ...
OM.origin(1)+750, OM.origin(2)-400);
DrawFormattedText(OM.wid, ['Game: ', num2str(Game)], ...
OM.origin(1), OM.origin(2)-425);
% Draw cards with a frame around it if selected.
for i = 1:length(RECS)
Screen('DrawTexture', OM.wid, OM.cardsTexture, [], RECS(i).rectangles);
if RECS(i).pressed == 1
Screen('FrameRect', OM.wid, OM.selRecColour, RECS(i).rectangles, OM.selRecSize);
end
end
% Show the selected card borders and delay against flicker
WaitSecs(0.2); % need this delay to stop flicker
Screen('Flip', OM.wid);
end % space was pressed, after the cards were selected. Now we need to flip the cards and show what they chose.
% if space was pressed,
% Draw wooden background
Screen('DrawTexture', OM.wid, OM.greywoodTexture);
% Draw score counter
Screen('TextSize', OM.wid, OM.textSize);
DrawFormattedText(OM.wid, ['Score: ', num2str(OM.Score)], ...
OM.origin(1)+750, OM.origin(2)-400);
DrawFormattedText(OM.wid, ['Game: ', num2str(Game)], ...
OM.origin(1), OM.origin(2)-425);
% randomly select the 9 animals to show. Replace is set to false so
% each animal can only be shown once in one game. It needs to be 10,
% else the game won't run if they select 10 cards (just in case they
% do).
animals = datasample(1:26, 10, 'Replace', false);
% Set card count to 0
card_count = 0;
% display animations
for i = 1:length(RECS)
if RECS(i).pressed == 1
% add to card_count if a card was selected
card_count = card_count + 1;
Screen('FrameRect', OM.wid, OM.selRecColour, RECS(i).rectangles, OM.selRecSize);
if sequence(i) == 0 % normal animal
t = animals(i);
Screen('FillRect', OM.wid, OM.turnedCardColour, RECS(i).rectangles)
Screen('DrawTexture', OM.wid, ANIMAL(t).AniTexture, [], RECS(i).animals);
elseif sequence(i) == 1 % troll face
Screen('FillRect', OM.wid, OM.redColour, RECS(i).rectangles)
Screen('DrawTexture', OM.wid, OM.trollTexture, [], RECS(i).animals);
% play giggle if Randy was selected
PsychPortAudio('Start', OM.giggle, 1);
loss = 1;
end
else
% Show the cards upside down for the ones that weren't
% selected.
Screen('DrawTexture', OM.wid, OM.cardsTexture, [], RECS(i).rectangles);
end
end
Screen('Flip', OM.wid);
WaitSecs(2);
% Draw wooden background
Screen('DrawTexture', OM.wid, OM.greywoodTexture);
Screen('TextSize', OM.wid, OM.feedbackSize);
% Show text after game round, and determine Score for game
if loss == 1
message = 'Oh no! You lost all your cards for this round...';
DrawFormattedText(OM.wid, message, 'center', 'center', OM.textColor);
Score = 0;
elseif loss == 0
message = sprintf('Well done! You''ve won %d cards this round!', card_count);
DrawFormattedText(OM.wid, message, 'center', 'center', OM.textColor);
Score = card_count;
end
% calculate the total score in the game
OM.Score = OM.Score + Score ;
% Draw score counter
Screen('TextSize', OM.wid, OM.textSize);
DrawFormattedText(OM.wid, ['Score: ', num2str(OM.Score)], ...
OM.origin(1)+750, OM.origin(2)-400);
DrawFormattedText(OM.wid, ['Game: ', num2str(Game)], ...
OM.origin(1), OM.origin(2)-425);
Screen('Flip',OM.wid);
WaitSecs(2); %change back to 1 second. % put to 2 seconds because is delay of showing text?
%% Save the data file
OM.dataFile = fopen(OM.dataFileName, 'a');
fprintf(OM.dataFile, OM.formatString, OM.SJNB, OM.Test_session, OM.Age, OM.Date, Game, RT, card_count, loss, OM.Score);
fclose(OM.dataFile);
% Cleaning this.
for i = 1:10
RECS(i).pressed = 0;
RECS(i).pressedCount = 0;
end
end
end
Upvotes: 0
Views: 349
Reputation: 93
Just wanted to post the answer below here, which was given to me by a commenter. The problem was actually just in the delay period of 200 ms I put in, which also meant that KbCheck did not always manage to register the spacebar press in time.. so it was a simple problem but this answer made me fix this annoyance in my task as well as in another one, so thank you! Comment with answer copied below:
"I don't know this Screen class, and it looks like this is all specific to Psychtoolbox, there is little native MATLAB that you use here, so I can't be of help. But a quick look in the docs reveals that KbCheck checks for the key to be down at that instant. So you need to have the key down when that bit of code is being executed. Since you have an 0.2 s wait in there too, it'll become challenging to press the key at the right time. Try to keep the key down until the program stops. I don't have suggestions for how to improve this using this toolbox, sorry. – Cris Luengo"
Upvotes: 1