Я создаю шахматные часы для своего шахматного проекта. В шахматах есть форматы времени 5 | 5, когда каждому игроку (белому и черному) дается общее 5 минут, поэтому, когда любой из игроков делает ход, к часам добавляется 5 секунд. Таким образом, 15|10 — это 15 минут в целом и 10 секунд на ход.
Мой код:
import pygame
import time
pygame.init()
size = width, height = 300, 300
screen = pygame.display.set_mode(size)
# Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)
class Button:
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, screen, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(screen, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('freesansbold.ttf', 16)
text = font.render(self.text, 1, (0, 0, 0))
screen.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def setColor(self, new_color):
self.color = new_color
def isOver(self, pos):
# Pos is the mouse position or a tuple of (x,y) coordinates
if self.x < pos[0] < self.x + self.width:
if self.y < pos[1] < self.y + self.height:
return True
return False
def main():
global Second, Minute
running = True
Black = 0, 0, 0
White = 255, 255, 255
Second = 0
Minute = 0
five_five = False
Clock = pygame.time.Clock()
while running:
five_five_button = Button(White, 150, 150, 40, 20, '5|5')
five_plus_five = Button(White, 150, 180, 40, 20, "+5 secs")
five_five_button.draw(screen, None)
five_plus_five.draw(screen, None)
pygame.display.update()
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
if e.type == pygame.MOUSEBUTTONDOWN:
if five_five_button.isOver(e.pos):
five_five = True
if five_plus_five.isOver(e.pos):
Second = +5
if e.type == pygame.KEYDOWN:
pass # if you want to add keys to test things easier
if five_five:
Minute = 5
Second = 0
five_five = False
if not five_five:
if Second == 0:
Second = 58
Minute = Minute - 1
Second += 2
time.sleep(1)
Second -= 1
# Minute
MinuteFont = Font.render(str(Minute).zfill(2), True, Black)
MinuteFontR = MinuteFont.get_rect()
MinuteFontR.center = (50, 60)
# Second
SecondFont = Font.render(":" + str(Second).zfill(2), True, Black)
SecondFontR = SecondFont.get_rect()
SecondFontR.center = (80, 60)
screen.fill(White)
# Timer
# while Time==0: this will cause a crash !
screen.blit(SecondFont, SecondFontR)
screen.blit(MinuteFont, MinuteFontR)
pygame.display.flip()
Clock.tick(60)
if __name__ == '__main__':
main()
Проблемы, с которыми я сталкиваюсь:
Допустим, игрок делает ход, и время 4:59. Мы хотим добавить 5 секунд. Так что это добавляет 5 секунд, то есть 4:64, то есть минус минута, то есть 3:04. Я не знаю, как это исправить.
Другой заключается в том, что всякий раз, когда вы хотите добавить 5 секунд или что-то еще, оно никогда не превысит 59, и добавьте эти секунды к общему количеству и добавьте минуту.
Я часами работал над этим, верьте этому или нет, выясняя простые вещи. Я искал, как сделать часы и другие вещи в python (или pygame), и я всегда добавляю часы. Я никогда не встречал часы, которые прибавляют время, но при этом еще и отсчитывают время.
Всякий раз, когда я даже пытаюсь загрузить или нажать одну из кнопок. Регистрация занимает несколько секунд. Поэтому, если вы можете помочь мне разобраться во всем этом или найти лучший способ сделать это, я очень ценю это.
Итак, давайте просто перестроим блок, в котором вы обрабатываете мелкие изменения.
Вещи, которые нам нужно реализовать:
Мы можем сделать все это с помощью простых операторов if. Взгляните на следующее.
Я также собираюсь переместить секундную галочку перед проверкой, чтобы сделать нашу математику немного более понятной (измените время, а затем исправьте это).
Second -= 1
if not five_five:
if Second < 0:
Minute -= 1
Second += 60 # Since Seconds will probably be -1
elif Second > 59:
Minute += 1
Second -= 60
Это все еще происходит? В моем коде минуты должны увеличиваться, если добавляется время, а не уменьшаться.
Прежде всего, я бы переименовал некоторые переменные, чтобы лучше передать их значение (учитывая, что некоторые из них не были сразу очевидны), поэтому я изменил эти:
five_five_button -> reset_button
five_plus_five -> add_button
Second -> seconds
Minute -> minutes
Black -> BLACK
White -> WHITE
Далее, я не думаю, что вам нужно заново создавать две кнопки в каждом кадре. Одного раза должно быть достаточно, чтобы их можно было нарисовать, поэтому я переместил их, как показано на рисунке:
# moved to here
reset_button = Button(White, 150, 150, 40, 20, '5|5')
add_button = Button(White, 150, 180, 40, 20, "+5 secs")
while running:
# removed from here
# reset_button = Button(White, 150, 150, 40, 20, '5|5')
# add_button = Button(White, 150, 180, 40, 20, "+5 secs")
# ... rest of loop code ...
Далее, мне нравится то, что вы хотели сделать со сбросом и добавлением временного кода, но думаю, что в таком сценарии это на самом деле только усложняет ситуацию. Поэтому я удалил эти утверждения if
:
if five_five:
minutes = 5
seconds = 0
five_five = False
if not five_five:
if seconds == 0:
seconds = 58
minutes = minutes - 1
seconds += 2
и перенесли свою логику прямо в код цикла обработки событий pygame:
if e.type == pygame.MOUSEBUTTONDOWN:
if reset_button.isOver(e.pos):
minutes = 5
seconds = 0
if add_button.isOver(e.pos):
seconds += 5
но это также означает, что у нас нет никакой логики, чтобы справиться с тем, что произойдет, если секунды выйдут за пределы допустимого, поэтому я написал следующее, чтобы это произошло сразу после нашего цикла событий pygame:
while seconds >= 60:
seconds -= 60
minutes += 1
while seconds < 0:
seconds += 60
minutes -= 1
Рефакторинг кода почти завершен, но перед этим я хочу разделить наш код на функции, чтобы упростить сопровождение и модульность. Мне также очень нравится использование классов для кнопок.
Сначала мне нужна функция «нарисовать все на экране»:
def draw_screen():
global WHITE, BLACK
screen.fill(WHITE)
# buttons
reset_button.draw(screen, None)
add_button.draw(screen, None)
# minutes tezt
minutesFont = Font.render(str(minutes).zfill(2), True, BLACK)
minutesFontR = minutesFont.get_rect()
minutesFontR.center = (50, 60)
screen.blit(minutesFont, minutesFontR)
# seconds text
secondsFont = Font.render(":" + str(seconds).zfill(2), True, BLACK)
secondsFontR = secondsFont.get_rect()
secondsFontR.center = (80, 60)
screen.blit(secondsFont, secondsFontR)
pygame.display.flip()
Причина, по которой вы чувствуете, что кнопки реагируют вечно, заключается в том, что pygame может реагировать на нажатия кнопок только один раз в секунду. Это из-за вашего time.sleep(1)
, что означает, что ваш цикл событий запускается только один раз в секунду. Нам понадобится неблокирующий способ уменьшения таймера секунд на 1
один раз в секунду:
previousTime = time.time()
# ...
while running:
# ...
if time.time() - previousTime > 1:
previousTime = time.time()
seconds -= 1
import pygame
import time
pygame.init()
size = width, height = 300, 300
screen = pygame.display.set_mode(size)
# Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)
class Button:
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, screen, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(screen, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('freesansbold.ttf', 16)
text = font.render(self.text, 1, (0, 0, 0))
screen.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def setColor(self, new_color):
self.color = new_color
def isOver(self, pos):
# Pos is the mouse position or a tuple of (x,y) coordinates
if self.x < pos[0] < self.x + self.width:
if self.y < pos[1] < self.y + self.height:
return True
return False
def draw_screen(minutes, seconds):
global WHITE, BLACK
screen.fill(WHITE)
# buttons
reset_button.draw(screen, None)
add_button.draw(screen, None)
# minutes tezt
minutesFont = Font.render(str(minutes).zfill(2), True, BLACK)
minutesFontR = minutesFont.get_rect()
minutesFontR.center = (50, 60)
screen.blit(minutesFont, minutesFontR)
# seconds text
secondsFont = Font.render(":" + str(seconds).zfill(2), True, BLACK)
secondsFontR = secondsFont.get_rect()
secondsFontR.center = (80, 60)
screen.blit(secondsFont, secondsFontR)
pygame.display.flip()
def fix_time(minutes, seconds):
while seconds >= 60:
seconds -= 60
minutes += 1
while seconds < 0:
seconds += 60
minutes -= 1
return minutes, seconds
def handle_events(minutes, seconds, reset_button, add_button):
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
if e.type == pygame.MOUSEBUTTONDOWN:
if reset_button.isOver(e.pos):
minutes = 5
seconds = 0
if add_button.isOver(e.pos):
seconds += 5
return minutes, seconds
def main():
global seconds, minutes
running = True
BLACK = 0, 0, 0
WHITE = 255, 255, 255
seconds = 0
minutes = 0
previousTime = time.time()
Clock = pygame.time.Clock()
reset_button = Button(WHITE, 150, 150, 40, 20, '5|5')
add_button = Button(WHITE, 150, 180, 40, 20, "+5 secs")
while running:
minutes, seconds = handle_events(minutes, seconds, reset_button, add_button)
if time.time() - previousTime > 1:
previousTime = time.time()
seconds -= 1
minutes, seconds = fix_time(minutes, seconds)
draw_screen(minutes, seconds):
Clock.tick(60)
if __name__ == '__main__':
main()
Я не запускал код, но мысль, намерение и улучшение по-прежнему актуальны. Есть еще улучшения, которые можно внести в код (необходимость возвращать minutes
и seconds
и передавать reset_button
и add_button
в качестве параметров — это «нехорошо»), поэтому не стесняйтесь использовать мой пример в качестве вдохновения.
Вы действительно устранили проблемы. Я исправлю параметры. Большое спасибо.
Это помогает, это делает игру лучше, но что произойдет, если игрок сделает ход на 4:59, добавив 5 секунд. Что получается должно быть 5:04, а получается 4:04. Поэтому я не знаю, как это исправить.