Игра на Python и тайловой основе: ограничение скорости передвижения игрока

Я собирал изометрическую ролевую игру на основе плитки, используя Python и библиотеку Pyglet. Однако я столкнулся со следующей проблемой:

Мои движения игрока основаны на позициях в трехмерном массиве, состоящем из плиток. Чтобы ограничить скорость движения, я использую глобальную переменную: TILE_TO_TILE_DELAY = 200.

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

Система, которую я использовал, заключается в том, что у меня есть класс таймера, например:

import time

def GetSystemTimeInMS(): #Return system time in milliseconds
    systime = round((time.clock()*1000), 0)
    return systime

class Timer:
def __init__(self,time):
    #time = time for which the timer runs
    self.time = time
    self.start_time = 0
    self.stop_time  = 0

def StartTimer(self):
    #start_time = time at which the timer was started
    self.start_time = GetSystemTimeInMS()
    self.stop_time  = self.start_time + self.time

def TimerIsStopped(self):
    if GetSystemTimeInMS() >= self.stop_time:
        return True
    else:
        return False

У класса игрока есть объект Timer:

self.MoveTimer = Timer(TILE_TO_TILE_DELAY)

Когда игрок нажимает клавишу W, вызывается функция, которая проверяет player.MoveTimer.TimerIsStopped (). Если он возвращает True, он вызывает player.MoveTimer.StartTimer () и начинает новое движение к следующей позиции.

В четном цикле функция обновления (dt) должна выполняться 30 раз в секунду:

def update(dt):
    if player.MoveTimer.TimerIsStopped()
        player.UpdatePosition()

pyglet.clock.schedule_interval(update, 1/30)

Теперь, по моей логике, update (dt) должен 30 раз в секунду проверять, прошло ли время, чтобы гарантировать игроку новое событие движения. Однако почему-то игрок движется намного быстрее при более низком FPS.

Когда мой FPS составляет около 30, игрок движется намного быстрее, чем в областях, где меньше тайловых спрайтов, повышая частоту кадров до 60. В областях, где FPS высокий, игрок действительно, по моим измерениям, движется почти в два раза медленнее.

Я просто не могу понять этого, и я не нашел ничего в Интернете после дня поиска. Некоторая помощь будет очень признательна.

Изменить: код, запускающий MoveTimer:

def StartMovement(self, new_next_pos):
    self.RequestedMovement = False
    if self.GetCanMoveAgain():

        self.SetNextPos(new_next_pos)
        self.SetMoveDirection(self.GetDirection())


        #Start the timer for the movement
        self.MoveTimer.StartTimer()
        self.SetIsMoving(True)
        self.SetStartedMoving(True)

        self.SetWalking(True)

        self.SetNeedUpdate(True)

        self.MOVE_EVENT_HANDLER.CreateMoveEvent()

GetCanMoveAgain () возвращает значение player.can_move_again, которое возвращается в True с помощью UpdatePosition () в update (dt)


person Salajouni    schedule 30.07.2015    source источник
comment
Можете ли вы включить код, вызывающий StartTimer ()?   -  person user3757614    schedule 30.07.2015
comment
Пожалуйста, добавьте этот код в свой вопрос   -  person kvorobiev    schedule 30.07.2015
comment
Добавлен код, запускающий таймер.   -  person Salajouni    schedule 31.07.2015


Ответы (1)


Хорошо, я устранил проблему, но все еще не уверен, что ее вызвало. Возможно, это была какая-то ошибка округления в миллисекундах, связанная с тем, что часы выполнялись чаще, когда FPS выше. В любом случае решение:

Вместо использования системных часов я решил использовать собственный аргумент «dt» Pyglet в их функциях обновления:

Параметр dt указывает количество секунд (из-за задержки, нагрузки и неточности таймера это может быть немного больше или меньше запрошенного интервала).

Новый таймер выглядит так:

class dtTimer: #A timer based on the dt-paremeter of the pyglet event loop
def __init__(self,time):
    self.time = time
    self.time_passed = 0

def StartTimer(self):
    self.time_passed = 0

def UpdateTimer(self, dt):
    self.time_passed += dt*1000

def GetTime(self):
    return self.time

def GetTimePassed(self):
    if not self.TimerIsStopped():
        return self.time_passed
    else:
        return 0

def TimerIsStopped(self):
    if self.time_passed > self.time:
        return True
    else:
        return False

Когда цикл пытается обновить позицию игрока, если TimerIsStopped возвращает false, dt просто добавляется к self.time_passed таймера. Это устранило проблему: время, необходимое для перемещения игрока, теперь постоянно.

Спасибо, что посмотрели на мою проблему.

person Salajouni    schedule 31.07.2015