|
6 | 6 | % |
7 | 7 | % Input: |
8 | 8 | % - cfg: PTB/machine configurations returned by setParameters and initPTB |
9 | | - % - expParameters: parameters returned by setParameters |
10 | | - % - logFile: structure that stores the experiment logfile to be saved |
11 | 9 | % |
12 | 10 | % Output: |
13 | 11 | % - |
14 | 12 | % |
15 | | - % The dots are drawn on a square that contains the round aperture, then any |
16 | | - % dots outside of the aperture is turned into a NaN so effectively the |
17 | | - % actual number of dots on the screen at any given time is not the one that you input but a |
18 | | - % smaller number (nDots / Area of aperture) on average. |
| 13 | + % The dots are drawn on a square with a width equals to the width of the |
| 14 | + % screen |
| 15 | + % We then draw an aperture on top to hide the certain dots. |
19 | 16 |
|
20 | 17 | %% Get parameters |
21 | | - direction = thisEvent.direction(1); |
22 | | - isTarget = thisEvent.target(1); |
23 | 18 |
|
24 | | - |
25 | | - dotLifeTime = cfg.dot.lifeTime; |
26 | | - |
27 | | - targetDuration = cfg.target.duration; |
28 | | - |
29 | | - % thisEvent = deg2Pix('speed', thisEvent, cfg); |
30 | | - % dotSpeedPix = logFile.iEventSpeedPix; |
31 | | - |
32 | | - coh = cfg.dot.coh; |
33 | | - speed = thisEvent.speed(1); |
34 | | - % Check if it is a static or motion block |
35 | | - if direction == -1 |
36 | | - |
37 | | - speed = 0; |
38 | | - coh = 1; |
39 | | - |
40 | | - dotLifeTime = cfg.eventDuration; |
41 | | - end |
42 | | - |
43 | | - %% initialize variables |
44 | | - |
45 | | - % Set an array of dot positions [xposition, yposition] |
46 | | - % These can never be bigger than 1 or lower than 0 |
47 | | - % [0,0] is the top / left of the square |
48 | | - % [1,1] is the bottom / right of the square |
49 | | - dotPositions = rand(cfg.dot.number, 2); |
50 | | - |
51 | | - % Set a N x 2 matrix that gives jump size in pixels |
52 | | - % pix/sec * sec/frame = pix / frame |
53 | | - dxdy = repmat( ... |
54 | | - speed * 10 / (cfg.aperture.width * 10) * (3 / cfg.screen.monitorRefresh) * ... |
55 | | - [cos(pi * direction / 180.0) -sin(pi * direction / 180.0)], cfg.dot.number, 1); |
56 | | - |
57 | | - % dxdy = repmat(... |
58 | | - % dotSpeedPix / Cfg.ifi ... |
59 | | - % * (cos(pi*direction/180) - sin(pi*direction/180)), ... |
60 | | - % ndots, 1); |
61 | | - |
62 | | - % Create a ones vector to update to dotlife time of each dot |
63 | | - dotTime = ones(size(dotPositions, 1), 1); |
64 | | - |
65 | | - % Covert the dotLifeTime from seconds to frames |
66 | | - dotLifeTime = ceil(dotLifeTime / cfg.screen.ifi); |
| 19 | + dots = initializeDots(cfg, thisEvent); |
67 | 20 |
|
68 | 21 | % Set for how many frames this event will last |
69 | 22 | framesLeft = floor(cfg.eventDuration / cfg.screen.ifi); |
70 | | - |
| 23 | + |
71 | 24 | %% Start the dots presentation |
72 | 25 | vbl = Screen('Flip', cfg.screen.win); |
73 | 26 | onset = vbl; |
74 | 27 |
|
75 | 28 | while framesLeft |
76 | 29 |
|
77 | | - % L are the dots that will be moved |
78 | | - L = rand(cfg.dot.number, 1) < coh; |
79 | | - |
80 | | - % Move the selected dots |
81 | | - dotPositions(L, :) = dotPositions(L, :) + dxdy(L, :); |
82 | | - |
83 | | - % If not 100% coherence, we get new random locations for the other dots |
84 | | - if sum(~L) > 0 |
85 | | - dotPositions(~L, :) = rand(sum(~L), 2); |
86 | | - end |
87 | | - |
88 | | - % Create a logical vector to detect any dot that has: |
89 | | - % - an xy position inferior to 0 |
90 | | - % - an xy position superior to 1 |
91 | | - % - has exceeded its liftime |
92 | | - N = any([dotPositions > 1, dotPositions < 0, dotTime > dotLifeTime], 2) ; |
| 30 | + [dots] = updateDots(dots, cfg); |
93 | 31 |
|
94 | | - % If there is any such dot we relocate it to a new random position |
95 | | - % and change its lifetime to 1 |
96 | | - if any(N) |
97 | | - dotPositions(N, :) = rand(sum(N), 2); |
98 | | - dotTime(N, 1) = 1; |
99 | | - end |
100 | | - |
101 | | - %% Convert the dot position to pixels |
102 | | - % We expand that square so that its side is equal to the whole |
103 | | - % screen width. |
104 | | - % With no aperture the whole screen is filled with dots. |
105 | | - dotPositionsPix = floor(dotPositions * cfg.screen.winRect(3)); |
106 | | - |
107 | | - % This assumes that zero is at the top left, but we want it to be |
| 32 | + %% Center the dots |
| 33 | + % We assumed that zero is at the top left, but we want it to be |
108 | 34 | % in the center, so shift the dots up and left, which just means |
109 | | - % adding half of the aperture size to both the x and y direction. |
110 | | - dotPositionsPix = (dotPositionsPix - cfg.screen.winRect(3) / 2)'; |
111 | | - |
112 | | - thisEvent.dot.positions = dotPositionsPix; |
| 35 | + % adding half of the screen width in pixel to both the x and y direction. |
| 36 | + thisEvent.dot.positions = (dots.positions - cfg.screen.winWidth / 2)'; |
113 | 37 |
|
114 | 38 | %% make textures |
115 | 39 | dotTexture('make', cfg, thisEvent); |
|
125 | 49 | % If this frame shows a target we change the color |
126 | 50 | thisFixation.fixation = cfg.fixation; |
127 | 51 | thisFixation.screen = cfg.screen; |
128 | | - if GetSecs < (onset + targetDuration) && isTarget == 1 |
| 52 | + if thisEvent.target(1) && GetSecs < (onset + cfg.target.duration) |
129 | 53 | thisFixation.fixation.color = cfg.fixation.colorTarget; |
130 | 54 | end |
131 | 55 | drawFixation(thisFixation); |
|
139 | 63 | % Check for end of loop |
140 | 64 | framesLeft = framesLeft - 1; |
141 | 65 |
|
142 | | - % Add one frame to the dot lifetime to each dot |
143 | | - dotTime = dotTime + 1; |
144 | | - |
145 | 66 | end |
146 | 67 |
|
147 | 68 | %% Erase last dots |
|
155 | 76 | duration = vbl - onset; |
156 | 77 |
|
157 | 78 | end |
158 | | - |
0 commit comments