简体   繁体   中英

Python and tile based game: limiting player movement speed

I've been putting together an isometric tile-based RPG using Python and the Pyglet library. I've run into the following problem, however:

My player movement is based on positions on the three-dimensional array that consists of tiles. To limit movement speed, I use a global variable: TILE_TO_TILE_DELAY = 200.

TILE_TO_TILE_DELAY is supposed to be the amount of time in milliseconds it takes for the player to move from one tile to another. During this time, they should not be able to make a new movement.

The system I've been using is that I have a timer class, like this:

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

The player class has a Timer object:

self.MoveTimer = Timer(TILE_TO_TILE_DELAY)

When the player presses the W-key, a function is called that checks for player.MoveTimer.TimerIsStopped(). If it returns True, it calls player.MoveTimer.StartTimer() and starts a new movement to the next position.

In the even loop, the update(dt) function is set to happen 30 times a second:

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

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

Now, by my logic, update(dt) should check 30 times a second whether or not enough time has passed to warrant the player a new movement event. However, for some reason the player moves much faster at lower FPS.

When my FPS is around 30, the player moves much faster than in areas where there are less tile sprites, pumping the framerate to 60. In areas where FPS is high, the player indeed by my measurements moves almost twice as slowly.

I just cannot figure it out, nor did I find anything off the internet after a day of searching. Some help would be much appreciated.

Edit: The code that starts the 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() returns the value of player.can_move_again, which is set back to True by the UpdatePosition() in update(dt)

Alright, I fixed the problem, how ever I'm still unsure about what caused it. Maybe it was some sort of a rounding error with milliseconds, having to do with more checks being made to the clock when the FPS is higher. Anyways, the solution:

Instead of using the system clock, I decided to use Pyglet's own "dt" argument in their update functions:

The dt parameter gives the number of seconds (due to latency, load and timer inprecision, this might be slightly more or less than the requested interval).

The new timer looks like this:

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

When the loop attempts to update the player's position, if the TimerIsStopped returns false, dt is simply added to the Timer's self.time_passed. This has fixed the issue: the time it takes for the player to move is now constant.

Thanks for looking at my issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM