Search code examples
pythonpython-2.7psychopy

Getting dot to move along curved trajectory


I'm trying to create a dot that moves around the screen, bounces off the edges, and curves in a random direction every 50 frames or so.

What I've done so for is get a ball to move constantly and bounce off of the screen edges. Please note that this uses PsychoPy:

win = visual.Window(size=(1600, 900), fullscr=False, screen=0, allowGUI=False, allowStencil=False, units='pix',
monitor='testMonitor', colorSpace=u'rgb', color=[0.51,0.51,0.51])

keys = event.BuilderKeyResponse()

dot1 = visual.Circle(win=win, name='dot1',units='pix',
    radius=10, edges=32,
    ori=0, pos=(0,0),
    lineWidth=1, lineColor='red', lineColorSpace='rgb',
    fillColor='red', fillColorSpace='rgb',
    opacity=1,interpolate=True)

x_change = 10
y_change = 10

while True:
    dot1.pos+=(x_change,y_change)

    if dot1.pos[0] > 790 or dot1.pos[0] < -790:
        x_change = x_change * -1
    if dot1.pos[1] > 440 or dot1.pos[1] < -440:
        y_change = y_change * -1

    dot1.draw()
    win.flip()

    if event.getKeys(keyList=["escape"]):
        core.quit()

I imagine that this will require some trig, which I barely understand. Could anyone point me in the right direction? What variables will I need, and how should they be manipulated?


Solution

  • The general strategy would be this: count frames within the loop and alter x_change and y_change to the new angle on the desired frame (e.g. every 50 frames). I'll use angle and speed explicitly to set the values of x_change and y_change using trigonometry:

    # New stuff:
    import numpy as np
    frameN = 50  # To set angle in first loop iteration
    speed = 14  # initial speed in whatever unit the stimulus use.
    angle = 45  # initial angle in degrees
    x_change = np.cos(angle) * speed  # initial
    y_change = np.sin(angle) * speed  # initial
    
    while True:
        # More new stuff: Change direction angle (in degrees)
        if frameN == 50:
            angle_current = np.rad2deg(np.arctan(y_change / float(x_change)))  # float to prevent integer division
            angle_change = np.random.randint(-180, 180)  # change interval to your liking or set to a constant value or something
            angle = angle_current + angle_change  # new angle
    
            x_change = np.cos(angle) * speed
            y_change = np.sin(angle) * speed
            frameN = 0
        frameN += 1
    
        dot1.pos+=(x_change,y_change)
    
        if dot1.pos[0] > 790 or dot1.pos[0] < -790:
            x_change = x_change * -1
        if dot1.pos[1] > 440 or dot1.pos[1] < -440:
            y_change = y_change * -1
    
    
        dot1.draw()
        win.flip()
    
        if event.getKeys(keyList=["escape"]):
            core.quit()
    

    Options for more randomness:

    • You can control speed (e.g. setting speed = np.random.randint(1, 20))
    • You can control which frame to change angle at next time (frameN = np.random.randint(40, 60)
    • You can change the interval of the angle change as noted above.