Move object left to right while it moves forward

OS: MacOS High Sierra
Psychopy version: 1.90.2
Standard Standalone: yes

What are you trying to achieve?:
I’m trying to code the Tetris Brick Racing game

So far, I’ve been able to make my stimulus (a yellow circle) move left and right if the left and right key is pressed. I’ve also been able to make it move forward.

However, I haven’t successfully been able to integrate the two concepts together. I’m wondering how to code the environment so that the circle keeps moving forward even when the left or right key is pressed. Right now, I have the object move forward ONLY when a key is pressed. I need it to continuously move forward and only move left and right when I press the corresponding keys.

What did you try to make it work?:


import os
from psychopy import visual, event, core

win = visual.Window(units = 'pix', color = 'black') # Set the window

k = ['']
y = 0
x = 100

POSITIONS = {
    "LEFT": (-100, y),
    "RIGHT": (100, y)
}

while True:
    circle = visual.Circle(win, radius = 10, pos = (x, y), fillColor= 'yellow')
    circle.draw()
    y += 2 # make circle constantly move upwards
    win.flip() # make the drawn things visible

    k = event.getKeys()
    if k[0] == 'left':
        circle.pos = POSITIONS["LEFT"]
        circle.draw()
        print(circle.pos)
    elif k[0] == 'right':
        circle.pos = POSITIONS["RIGHT"]
        circle.draw()
    elif k[0] == 'q':
        core.quit()
win.close()

How nice to get a good, concise code example rather than a Builder question.

General comments:

  • creating an object is a much more time-expensive process than just updating the attributes (e.g. position or colour) of an already existing object. So you should put the line creating your circle stimulus before your while loop. i.e. at the moment, you are recreating it from scratch on every iteration of the loop, but this should actually only be done once, before the loop starts. [This is just a general performance tip: not relevant to your specific question here.]
  • you have the right idea of making the increase of the y position non-contingent on the key press, but at the moment, updating the value of y is not reflected in your POSITIONS objects. i.e. they get a value for y of 0 when they are created, but this value is not subsequently updated when the value of the y variable is itself updated later.

i.e. the value in y is just a value, not an object which can be updated. i.e. in Python, the ‘link’ between the variable y is not maintained back to your positions objects (this is a bit confusing at first, because we are told that everything in Python is an object, but not all objects are ‘mutable’). Instead, what is happening in your code is that the stimulus gets value from the y variable when it is re-created on every iteration (but note that this is the value from the previous iteration, so it is already out of date, because the value of y isn’t updated until the next line.). But if a key is pressed, then both x and y are overwritten with values from the POSITIONS dictionary, which still has the initial value of y = 0.

For such a simple example, you’ve opened up a bit of a can of worms about the meaning of references, values, and objects in Python :wink:

I’d suggest just some minor modifications to your code, like this (untested):

import os
from psychopy import visual, event, core

win = visual.Window(units = 'pix', color = 'black') # Set the window

x = 0 # initial positions
y = 0

LEFT = -100
RIGHT = 100

# create just once, no need to specify a position yet:
circle = visual.Circle(win, radius = 10, fillColor= 'yellow')

while True: # draw moving stimulus
    
    k = event.getKeys()
    if k: # if there was an actual key pressed:
        if k[0] == 'left':
            x = LEFT
        elif k[0] == 'right':
            x = RIGHT
        elif k[0] == 'q':
            core.quit()

    y += 2 # make circle constantly move upwards
    circle.pos = [x, y] # directly update both x *and* y
    circle.draw()
    win.flip() # make the drawn things visible

win.close()
core.quit()
1 Like

Michael,

Thank you so much for guiding me in the right direction. The code worked splendidly - thank you for pointing out the original errors. I also initiated x and also changed if k[0] == 'left' to if 'left' in k because of an “index out of range” issue.

And I also really appreciate your concise explanation - it really helps me learn quicker.

Hanna

1 Like