Проблема с настройкой глобальной переменной

Программа должна обновлять значение глобальной переменной int_choice каждый раз, когда игрок набирает очки (это игра в понг).

int_choice может иметь значение только 1 или 0. Если это 1, функция left_or_right "говорит" мячу идти вправо, если 0, мяч идет влево.

int_choice обновляется в нескольких местах: сначала инициализируется, потом в функции left_or_right(), потом в функции draw().

Каждый раз, когда пользователь забивает, мяч должен возрождаться из центра стола в сторону этого пользователя, но мяч всегда возрождается дважды в одном и том же направлении, а затем дважды в противоположном направлении и так далее, независимо от того, кто был последним. счет.

Вот код:

import random

int_choice = random.randint(0,1)
direc = None

def left_or_right():
    global direc, int_choice
    if int_choice == 0:
        direc = "LEFT"
    elif int_choice == 1:
        direc = "RIGHT"
    return direc

def spawn_ball(direction):
    left_or_right()
    global ball_pos, ball_vel # these are vectors stored as lists
    ball_pos = [WIDTH / 2, HEIGHT / 2]
    if direction == "LEFT":
        ball_vel[0] = (random.randrange(12, 25)*(-0.1))
        print "Velocity[0]: ", ball_vel[0]
        ball_vel[1] =  (random.randrange(6, 19)*(-0.1))
    elif direction == "RIGHT":
        ball_vel[0] = (random.randrange(12, 25)*(0.1))
        print "Velocity[0]: ", ball_vel[0]
        ball_vel[1] =  (random.randrange(6, 19)*(-0.1))
        print "Velocity[1]: ", ball_vel[1]

def new_game():
    global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel, direc
    global score1, score2, 
    spawn_ball(direc)
    score1 = 0
    score2 = 0

def draw(canvas):
    global remaining_names, score1, score2, paddle1_pos, paddle2_pos,          ball_pos, ball_vel, BALL_RADIUS, direc
    global int_choice


    # update ball
    ball_pos[0] += ball_vel[0]
    ball_pos[1] += ball_vel[1]
    if ball_pos[1] - BALL_RADIUS <= 0:
        ball_vel[1] = ball_vel[1] + (ball_vel[1] * (-2))     
    elif ball_pos[1] + BALL_RADIUS >= HEIGHT:
        ball_vel[1] = ball_vel[1] + (ball_vel[1] * (-2))
    elif ball_pos[0] - BALL_RADIUS <= (0 + PAD_WIDTH):
        if (ball_pos[1] > paddle1_pos) and (ball_pos[1] < (paddle1_pos + PAD_HEIGHT)):
            ball_vel[0] = ball_vel[0] + (ball_vel[0] * (-2.1))
        else:
            int_choice = 1
            spawn_ball(direc)
            score2 = score2 + 1

    elif (ball_pos[0] + BALL_RADIUS) >= (WIDTH - PAD_WIDTH):
        if (ball_pos[1] > paddle2_pos) and (ball_pos[1] < (paddle2_pos + PAD_HEIGHT)):
            ball_vel[0] = ball_vel[0] + (ball_vel[0] * (-2.1))
        else:
            int_choice = 0
            spawn_ball(direc)
            score1 = score1 + 1

person Ekaterina1234    schedule 29.07.2016    source источник
comment
random.randint(0,1) — это псевдоним для random.randrange(2). Подумайте об использовании последнего.   -  person Mad Physicist    schedule 29.07.2016
comment
Почему вы вообще используете две глобальные переменные, которые означают одно и то же? И ваша функция left_or_right() может быть просто заменена списком: directions = ['LEFT', 'RIGHT'], а directions[int_choice] будет переводить целое число в текст каждый раз, когда вам нужен текст.   -  person Martijn Pieters    schedule 29.07.2016
comment
Вы также проходите в направлении spawn_ball(), который затем вызывает также left_or_right(). Зачем проходить в направлении, а затем вызывать функцию, чтобы установить его снова? Функция также возвращает направление, но вы везде игнорируете возвращаемое значение.   -  person Martijn Pieters    schedule 29.07.2016
comment
Более того, вызов left_or_right() в spawn_ball() переворачивает смысл int_choice от того, что вы хотите. Вероятно, вам следует удалить этот вызов.   -  person Mad Physicist    schedule 29.07.2016
comment
Тем не менее, я нигде в этом коде не вижу, чтобы int_choice в противном случае устанавливалось странным чередующимся образом в этом коде.   -  person Martijn Pieters    schedule 29.07.2016
comment
Похоже, вы используете global как своего рода объявление переменной. Например, вы дважды объявляете глобальные переменные score1 и score2. То же самое с директ. Вам не нужно объявлять переменные в Python, присваивание является объявлением.   -  person powlo    schedule 29.07.2016


Ответы (2)


Вы передаете старое значение direc перед вызовом left_or_right.

Скажем, вы установили int_cohice в 1:

int_choice = 1
spawn_ball(direc)  # old value of `direc`, nothing changed this yet

затем в spawn_ball():

def spawn_ball(direction):
    left_or_right()

поэтому direction задается старое значение, а left_or_right() задает новое значение, которое затем полностью игнорируется в spawn_ball(). Вы используете direction на протяжении всей функции.

Быстрое исправление заключается в использовании возвращаемого значения left_or_right(); или используйте глобальный файл direc. Поскольку любой из них работает с глобальными переменными, нет смысла передавать здесь direc:

int_choice = 1
spawn_ball()  # don't pass anything in

а также

def spawn_ball():
    direction = left_or_right()

Однако лучше всегда проходить в определенном направлении и полностью удалять (двойные) глобальные переменные.

Просто введите число, вы можете дать этому числу символические имена:

LEFT, RIGHT = 0, 1  # symbolic names for direction

def spawn_ball(direction):
    ball_pos = [WIDTH / 2, HEIGHT / 2]
    if direction == LEFT:  # using the global symbolic name
        return ball_pos, [
            random.randrange(12, 25)*(-0.1),
            random.randrange(6, 19)*(-0.1)]
    else:   # naturally the other option is going to be RIGHT
        return ball_pos, [
            random.randrange(12, 25)*(0.1)
            random.randrange(6, 19)*(-0.1)]

Обратите внимание, что функция возвращает новые позиции и скорость мяча; сохранить результат при вызове функции:

ball_pos, ball_vel = spawn_ball(direction)

Возможно, функция draw по-прежнему обрабатывает их как глобальные, но, по крайней мере, это больше не касается функции spawn_ball().

Теперь все, что вам нужно сделать, это установить одну переменную local в значение LEFT или RIGHT, чтобы создать мяч и передать эту переменную в функцию.

person Martijn Pieters    schedule 29.07.2016

Ваша проблема существует, потому что вы обновляете переменную в неправильное время в своем коде. Давайте рассмотрим пример того, что происходит после окончания игры.

int_choice = 0
spawn_ball(direc)

Вы устанавливаете int_choice в 0, затем вызываете spawn_ball(direc), но direc — это старое направление — оно еще не изменилось, изменилось только int_choice. Итак, теперь direc привязан к переменной «direction» в вашей функции spawn_ball. Несмотря на то, что spawn_ball немедленно вызывает left_or_right(), это будет обновлять только направление, а не направление, а это означает, что spawn_ball продолжит работу в том же направлении, в котором оно было первоначально передано, независимо от того, что сделал вызов left_or_right.

Быстрое решение было бы сказать

def spawn_ball(direction):
    direction = left_or_right()

Что, скорее всего, решит эту проблему. Тем не менее, я бы посоветовал вам немного реорганизовать свой код - это очень плохой стиль. Передача глобальных переменных, как вы, настолько подвержена ошибкам, подобным этой - использование локальных переменных, передаваемых через вызовы функций, является гораздо лучшим вариантом.

person James    schedule 29.07.2016