首页 > 解决方案 > 为什么我的 while 循环有时不响应 Matlab 中的按键?

问题描述

我为一项新研究创建了一个游戏,我将在 Matlab R2018a 中使用 Psychtoolbox(3.0.13,风味测试版)运行,并且在试用中退出我的 while 循环的条件是空格键,有时可以立即工作,但有时需要多次按键才能退出。

我已经尝试通过删除任何不必要的代码并在显示刺激之前放置等待时间来提高我的代码效率,以防万一这可以解决问题。我有一个while循环,需要通过鼠标点击输入空格键来满足退出条件。代码最终确实运行了,但我只是不明白为什么有时按一次空格键就足够了,而其他时候我需要按 3 次才能退出。我在另一个任务中遇到了同样的问题,我也使用鼠标点击和空格键按下(没有声音,所以我不认为是声音引起的)作为退出 while 循环的条件。我想知道这是否与我使用 RECS 结构的方式有关,以及是否可以使用更有效的方式。如果有人对如何在任务中改进这一点有任何想法,那就太棒了。

% 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

标签: matlabwhile-loop

解决方案


只是想在下面发布答案,这是评论者给我的。问题实际上只是在我输入的 200 毫秒的延迟时间内,这也意味着 KbCheck 并不总是能及时注册空格键。所以这是一个简单的问题,但这个答案让我解决了这个烦恼任务以及另一个任务,所以谢谢!评论下面复制的答案:

“我不知道这个 Screen 类,而且看起来这都是 Psychtoolbox 特有的,你在这里使用的原生 MATLAB 很少,所以我帮不上忙。但是快速浏览一下文档就会发现 KbCheck检查那一刻是否按下键。因此,当执行那段代码时,您需要按下键。由于您在那里也有 0.2 秒的等待时间,因此在按下键时会变得很有挑战性正确的时间。试着按住键直到程序停止。我没有关于如何使用这个工具箱改进它的建议,抱歉。——Cris Luengo"


推荐阅读