为什么我的while循环有时对Matlab中的按键不响应?

Why does my while-loop sometimes not respond to a keypress in Matlab?

我已经为一项新研究创建了一个游戏,我将在Matlab R2018a中使用Psychtoolbox(3.0.13,flavor beta)运行该游戏,并提出退出我的while循环的条件(有时是空格键)立即生效,但有时需要几次按键才能退出。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
% 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


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

"我不知道这个Screen类,而且看起来这都是Psychtoolbox特有的,您在这里使用的原生MATLAB很少,所以我无济于事。但是快速浏览一下文档揭示了KbCheck在那一瞬间检查了按键是否被按下。因此,当执行那段代码时,您需要将按键按下。由于您在那里也要等待0.2 s,因此按一下该按键将变得非常困难。在正确的时间键入密钥。尝试将其保持在按下状态,直到程序停止。抱歉,我没有使用此工具箱的改进建议,抱歉。a€" Cris Luengo"