Thank you for the reply Michael. My program is working as you say, the only difference is that it works line by line. I create the text stimuli only once and then I just update its content. I have found out that when I use pyglet it takes approximately 20 ms to update text stimuli of 40 characters, but when I switch to pygame it takes 1ms or less. My computer is i7, geforce gtx 960m.
This is the part of code that does the text animation:
#-*- coding: utf-8 -*-
from __future__ import division
from psychopy import visual
from psychopy import core, event, monitors
import textwrap
class Param:
pass
params = Param()
params.FONT = 'Georgia'
params.ROW_HEIGHT = 0.4 # cm
params.ROW_WIDTH = 10 # cm
params.FG_COLOR = '#FF0000'
params.BG_COLOR = '#000000'
params.NUM_CHARS_ROW = 40
params.NUM_ROWS = 5
params.SPEED = 0.07 # cm per second
params.SPEED_STEP = 0.03 # cm per second
def prepare_text():
text = 'Hello, this is a sample text. ' * 100
return(textwrap.wrap(text, width=params.NUM_CHARS_ROW))
def create_rows():
rows = []
for i in range(params.NUM_ROWS + 1):
row = visual.TextStim(win, color=params.FG_COLOR,
font=params.FONT, antialias=True, height=params.ROW_HEIGHT, wrapWidth=params.ROW_WIDTH, alignHoriz='left', text='')
row.pos = (-params.ROW_WIDTH / 2,
(params.NUM_ROWS + 1) * params.ROW_HEIGHT / 2 -i * params.ROW_HEIGHT)
rows.append(row)
return(rows)
def set_aperture():
VERTICES = [(-mon.getWidth() / 2, params.NUM_ROWS * params.ROW_HEIGHT / 2),
(mon.getWidth() / 2, params.NUM_ROWS * params.ROW_HEIGHT / 2),
(mon.getWidth() / 2, -params.NUM_ROWS * params.ROW_HEIGHT / 2),
(-mon.getWidth() / 2, -params.NUM_ROWS * params.ROW_HEIGHT / 2)]
return(visual.Aperture(win, shape=VERTICES))
def move_text(ts, delta_t):
global current_row
for i, t in enumerate(ts):
t.pos += (0, delta_t * params.SPEED)
if t.pos[1] > params.NUM_ROWS * params.ROW_HEIGHT / 2 + params.ROW_HEIGHT / 2:
if current_row < len(split_text):
c1 = clock.getTime() # measure time
t.text = split_text[current_row]
print clock.getTime() - c1 # measure time
current_row += 1
else:
t.text = ''
if i == 0:
t.pos = (-params.ROW_WIDTH / 2, ts[-1].pos[1] - params.ROW_HEIGHT)
else:
t.pos = (-params.ROW_WIDTH / 2, ts[i - 1].pos[1] - params.ROW_HEIGHT)
########################################################
split_text = prepare_text()
mon = monitors.Monitor('testMonitor')
win = visual.Window([1920, 1080], monitor='testMonitor', color=params.BG_COLOR, allowStencil=True, winType='pyglet', units='cm')
rows = create_rows()
current_row = 0
aperture = set_aperture()
clock = core.Clock()
done = False
t_sim = t_sim_old = win.flip()
while not done:
move_text(rows, t_sim - t_sim_old)
for r in rows:
r.draw()
t_sim_old = t_sim
t_sim = win.flip()
allKeys = event.getKeys()
if len(allKeys)>0:
for thisKey in allKeys:
if thisKey =='right':
params.SPEED += params.SPEED_STEP
elif thisKey=='left':
params.SPEED -= params.SPEED_STEP
if params.SPEED <= 0:
params.SPEED += params.SPEED_STEP
elif thisKey in ['q', 'escape']:
done = True
event.clearEvents()
win.close()
core.quit()
So, the problem can be solved by using pygame. The disadvantage is that I cannot center the left justified text on the screen because boundingBox returns bounding box only when I use pyglet.
Another problem, that I cannot solve, is that when the speed of the text animation is low (the default example’s speed) there can be seen some “wave” artefacts. You can speed up/slow down the animation by pressing arrow keys (right/left). When the speed is higher there is no noticeable “wave” artefact.