Ошибка - Fatal Python error: PyEval_SaveThread - Python3.9
Пишу игру при помощи модуля PyGame. В игре присутствует объект танк, который может поворачивать на все 8 сторон. Повороты на 4 стороны: вверх, вниз, влево и вправо - срабатывают как нужно, но при поворотах на 45 градусов происходит начто непонятное: картинки, из которых состоит танк, размываются с каждым поворотом в одну из таких сторон всё сильнее и сильнее, при каждом последующем повороте на угол в 45 градусов игра начинает лагать и зависать, в итоге останавливается и один раз выдало ошибку:
Fatal Python error: PyEval_SaveThread: the function must be called with t
he GIL held, but the GIL is released (the current Python thread state is
NULL)
Python runtime state: initialized
Current thread 0x00003394 (most recent call first):
File "Z:\myProgs\Python\Project\tanks.py", line 493 in turn
File "Z:\myProgs\Python\Project\tanks.py", line 360 in check
File "Z:\myProgs\Python\Project\tanks.py", line 613 in run
File "Z:\myProgs\Python\Project\tanks.py", line 587 in __init__
File "Z:\myProgs\Python\Project\tanks.py", line 619 in <module>
Не могу понять в чём моя ошибка, всё работает так как нужно: танк правильно поворачивает, едет также правильно, но при переходе с угла в 45 градусов в любую другую сторону, происходит ошибка по непонятным причинам.
Полный код:
import os, sys, time, random, math
import pygame as pg, numpy as np
class Game:
pg.init()
class Color:
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
class Location:
SIZE = (100, 100)
IMAGE = pg.transform.scale(pg.image.load('objects/floor/floor.jpg'), SIZE)
PLACE = IMAGE.get_rect()
def __init__(self, screen, info):
self.screen = screen
self.info = info
# create size
self.WIDTH, self.HEIGHT = self.info.current_w, self.info.current_h
# create surface
self.surface = pg.Surface((self.WIDTH, self.HEIGHT))
# rendering and adding
self.render()
self.add()
def add(self):
self.screen.blit(self.surface, (0, 0))
def update(self):
pass
def render(self):
for i in range(1000):
self.surface.blit(self.IMAGE, self.PLACE)
if self.PLACE.x >= self.info.current_w:
self.PLACE.x = 0
self.PLACE.y += 100
else:
self.PLACE.x += 100
if self.PLACE.y >= self.info.current_h:
break
class Tank:
SIZE = (80, 100)
class Move:
def __init__(self, upstairs=True, downstairs=False, left=False, right=False):
self.upstairs = upstairs
self.downstairs = downstairs
self.left = left
self.right = right
def update(self, to):
if to == 'upstairs-left':
self.upstairs = True
self.downstairs = False
self.left = True
self.right = False
elif to == 'upstairs-right':
self.upstairs = True
self.downstairs = False
self.left = False
self.right = True
elif to == 'downstairs-left':
self.upstairs = False
self.downstairs = True
self.left = True
self.right = False
elif to == 'downstairs-right':
self.upstairs = False
self.downstairs = True
self.left = False
self.right = True
elif to == 'upstairs':
self.upstairs = True
self.downstairs = False
self.left = False
self.right = False
elif to == 'downstairs':
self.upstairs = False
self.downstairs = True
self.left = False
self.right = False
elif to == 'left':
self.upstairs = False
self.downstairs = False
self.left = True
self.right = False
elif to == 'right':
self.upstairs = False
self.downstairs = False
self.left = False
self.right = True
move = Move(
upstairs=True,
downstairs=False,
left=False,
right=False,
)
speed = 1
def __init__(self, screen, pos=(0, 0)):
self.screen = screen
self.info = pg.display.Info()
# create surface
self.person = pg.Surface(self.SIZE)
self.person.set_colorkey((0, 0, 0))
# create object with position's data
self.object = self.person.get_rect()
# rendering
self.render()
# update positions and add to window
self.update(pos)
self.add()
def render(self):
def foot():
images = {
'1':pg.image.load('objects/tank/foot.png'),
'2':pg.transform.flip(pg.image.load('objects/tank/foot.png'), True, False),
'3':pg.transform.flip(pg.image.load('objects/tank/foot.png'), True, True),
'4':pg.transform.flip(pg.image.load('objects/tank/foot.png'), False, True),
}
for i, image in images.items():
rect = image.get_rect()
rect.width, rect.height = rect.width/4, rect.height/4
image = pg.transform.scale(image, (rect.width, rect.height))
if i == '1':
pass
elif i == '2':
rect.right = self.object.width
elif i == '3':
rect.right = self.object.width
rect.bottom = self.object.height
elif i == '4':
rect.bottom = self.object.height
self.person.blit(image, rect)
def body():
image = pg.image.load('objects/tank/body.png')
rect = image.get_rect()
rect.width, rect.height = rect.width/4, rect.height/4
image = pg.transform.scale(image, (rect.width, rect.height))
rect.centerx, rect.centery = self.object.centerx, self.object.centery+3
self.person.blit(image, (rect.x, rect.y))
def head():
image = pg.image.load('objects/tank/head.png')
rect = image.get_rect()
rect.width, rect.height = rect.width/4, rect.height/4
image = pg.transform.scale(image, (rect.width, rect.height))
rect.centerx, rect.centery = self.object.centerx, self.object.centery-10
self.person.blit(image, (rect.x, rect.y))
foot()
body()
head()
def add(self):
self.screen.blit(self.person, (self.object.x, self.object.y))
def update(self, pos):
self.object.x, self.object.y = pos[0]-40, pos[1]-50
def rotate(self, pos):
pass
def start(self):
self.speed = 1
def stop(self):
self.speed = 0
def check(self, key):
if (key[pg.K_w] or key[pg.K_UP]) and (key[pg.K_s] or key[pg.K_DOWN]):
return self.stop()
elif (key[pg.K_a] or key[pg.K_LEFT]) and (key[pg.K_d] or key[pg.K_RIGHT]):
return self.stop()
else:
self.start()
if key[pg.K_w] or key[pg.K_UP]:
if key[pg.K_a] or key[pg.K_LEFT]:
if self.move.upstairs and self.move.left:
of = to = 'upstairs-left'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'upstairs-left'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'upstairs-left'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'upstairs-left'
elif self.move.upstairs:
of, to = 'upstairs', 'upstairs-left'
elif self.move.downstairs:
of, to = 'downstairs', 'upstairs-left'
elif self.move.left:
of, to = 'left', 'upstairs-left'
elif self.move.right:
of, to = 'right', 'upstairs-left'
elif key[pg.K_d] or key[pg.K_RIGHT]:
if self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'upstairs-right'
elif self.move.upstairs and self.move.right:
of = to = 'upstairs-right'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'upstairs-right'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'upstairs-right'
elif self.move.upstairs:
of, to = 'upstairs', 'upstairs-right'
elif self.move.downstairs:
of, to = 'downstairs', 'upstairs-right'
elif self.move.left:
of, to = 'left', 'upstairs-right'
elif self.move.right:
of, to = 'right', 'upstairs-right'
elif self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'upstairs'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'upstairs'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'upstairs'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'upstairs'
elif self.move.upstairs:
of = to = 'upstairs'
elif self.move.downstairs:
of, to = 'downstairs', 'upstairs'
elif self.move.left:
of, to = 'left', 'upstairs'
elif self.move.right:
of, to = 'right', 'upstairs'
elif key[pg.K_s] or key[pg.K_DOWN]:
if key[pg.K_a] or key[pg.K_LEFT]:
if self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'downstairs-left'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'downstairs-left'
elif self.move.downstairs and self.move.left:
of = to = 'downstairs-left'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'downstairs-left'
elif self.move.upstairs:
of, to = 'upstairs', 'downstairs-left'
elif self.move.downstairs:
of, to = 'downstairs', 'downstairs-left'
elif self.move.left:
of, to = 'left', 'downstairs-left'
elif self.move.right:
of, to = 'right', 'downstairs-left'
elif key[pg.K_d] or key[pg.K_RIGHT]:
if self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'downstairs-right'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'downstairs-right'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'downstairs-right'
elif self.move.downstairs and self.move.right:
of = to = 'downstairs-right'
elif self.move.upstairs:
of, to = 'upstairs', 'downstairs-right'
elif self.move.downstairs:
of, to = 'downstairs', 'downstairs-right'
elif self.move.left:
of, to = 'left', 'downstairs-right'
elif self.move.right:
of, to = 'right', 'downstairs-right'
elif self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'downstairs'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'downstairs'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'downstairs'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'downstairs'
elif self.move.upstairs:
of, to = 'upstairs', 'downstairs'
elif self.move.downstairs:
of = to = 'downstairs'
elif self.move.left:
of, to = 'left', 'downstairs'
elif self.move.right:
of, to = 'right', 'downstairs'
elif key[pg.K_a] or key[pg.K_LEFT]:
if self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'left'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'left'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'left'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'left'
elif self.move.upstairs:
of, to = 'upstairs', 'left'
elif self.move.downstairs:
of, to = 'downstairs', 'left'
elif self.move.left:
of = to = 'left'
elif self.move.right:
of, to = 'right', 'left'
elif key[pg.K_d] or key[pg.K_RIGHT]:
if self.move.upstairs and self.move.left:
of, to = 'upstairs-left', 'right'
elif self.move.upstairs and self.move.right:
of, to = 'upstairs-right', 'right'
elif self.move.downstairs and self.move.left:
of, to = 'downstairs-left', 'right'
elif self.move.downstairs and self.move.right:
of, to = 'downstairs-right', 'right'
elif self.move.upstairs:
of, to = 'upstairs', 'right'
elif self.move.downstairs:
of, to = 'downstairs', 'right'
elif self.move.left:
of, to = 'left', 'right'
elif self.move.right:
of = to = 'right'
else:
of = to = None
self.turn(of=of, to=to)
self.move.update(to=to)
def turn(self, of, to):
if of is None and to is None:
pass
if of == to:
return self.moving(to=to)
degs = 0
if of == 'upstairs-left':
if to == 'upstairs-right':
degs = -90
elif to == 'downstairs-left':
degs = 90
elif to == 'downstairs-right':
degs = 180
elif to == 'upstairs':
degs = -45
elif to == 'downstairs':
degs = 135
elif to == 'left':
degs = 45
elif to == 'right':
degs = -135
elif of == 'upstairs-right':
if to == 'upstairs-left':
degs = 90
elif to == 'downstairs-left':
degs = 180
elif to == 'downstairs-right':
degs = 90
elif to == 'upstairs':
degs = 45
elif to == 'downstairs':
degs = -135
elif to == 'left':
degs = 135
elif to == 'right':
degs = -45
elif of == 'downstairs-left':
if to == 'upstairs-left':
degs = -90
elif to == 'upstairs-right':
degs = 180
elif to == 'downstairs-right':
degs = 90
elif to == 'upstairs':
degs = -135
elif to == 'downstairs':
degs = 45
elif to == 'left':
degs = -45
elif to == 'right':
degs = 135
elif of == 'downstairs-right':
if to == 'upstairs-left':
degs = 180
elif to == 'upstairs-right':
degs = 90
elif to == 'downstairs-left':
degs = -90
elif to == 'upstairs':
degs = 135
elif to == 'downstairs':
degs = -45
elif to == 'left':
degs = -135
elif to == 'right':
degs = 45
elif of == 'upstairs':
if to == 'upstairs-left':
degs = 45
elif to == 'upstairs-right':
degs = -45
elif to == 'downstairs-left':
degs = 135
elif to == 'downstairs-right':
degs = -135
elif to == 'downstairs':
degs = 180
elif to == 'left':
degs = 90
elif to == 'right':
degs = -90
elif of == 'downstairs':
if to == 'upstairs-left':
degs = -135
elif to == 'upstairs-right':
degs = 135
elif to == 'downstairs-left':
degs = -45
elif to == 'downstairs-right':
degs = 45
elif to == 'upstairs':
degs = 180
elif to == 'left':
degs = -90
elif to == 'right':
degs = 90
elif of == 'left':
if to == 'upstairs-left':
degs = -45
elif to == 'upstairs-right':
degs = -135
elif to == 'downstairs-left':
degs = 45
elif to == 'downstairs-right':
degs = 135
elif to == 'upstairs':
degs = -90
elif to == 'downstairs':
degs = 90
elif to == 'right':
degs = 180
elif of == 'right':
if to == 'upstairs-left':
degs = 135
elif to == 'upstairs-right':
degs = 45
elif to == 'downstairs-left':
degs = -135
elif to == 'downstairs-right':
degs = -45
elif to == 'upstairs':
degs = 90
elif to == 'downstairs':
degs = -90
elif to == 'left':
degs = 180
self.person = pg.transform.rotate(self.person, degs)
self.object = self.person.get_rect(center=self.object.center)
def moving(self, to):
# check bounds
if self.object.top == 0:
self.stop()
if to != 'upstairs' and to != 'upstairs-left' and to != 'upstairs-right':
if self.object.left == 0:
self.stop()
if to != 'left':
self.start()
elif self.object.right == (self.info.current_w-17):
self.stop()
if to != 'right':
self.start()
else:
self.start()
elif self.object.bottom == self.info.current_h:
self.stop()
if to != 'downstairs' and to != 'downstairs-left' and to != 'downstairs-right':
if self.object.left == 0:
self.stop()
if to != 'left':
self.start()
elif self.object.right == (self.info.current_w-17):
self.stop()
if to != 'right':
self.start()
else:
self.start()
elif self.object.left == 0:
self.stop()
if to != 'left':
self.start()
elif self.object.right == (self.info.current_w-17):
self.stop()
if to != 'right':
self.start()
else:
self.start()
# moving
if to == 'upstairs-left':
self.object.x -= self.speed
self.object.y -= self.speed
elif to == 'upstairs-right':
self.object.x += self.speed
self.object.y -= self.speed
elif to == 'downstairs-left':
self.object.x -= self.speed
self.object.y += self.speed
elif to == 'downstairs-right':
self.object.x += self.speed
self.object.y += self.speed
elif to == 'upstairs':
self.object.y -= self.speed
elif to == 'downstairs':
self.object.y += self.speed
elif to == 'left':
self.object.x -= self.speed
elif to == 'right':
self.object.x += self.speed
TITLE = 'Tanks'
SIZE = (0, 0)
TYPE = pg.FULLSCREEN
FPS = 50
CLOCK = pg.time.Clock()
BACKGROUND = Color.BLACK
EXIT = False
def __init__(self):
pg.display.set_caption(self.TITLE)
self.screen = pg.display.set_mode(self.SIZE, self.TYPE)
self.window = pg.display.Info()
self.run()
def update(self):
self.screen.fill(self.BACKGROUND)
def run(self):
self.location = self.Location(self.screen, self.window)
self.tank = self.Tank(self.screen, (self.window.current_w//2, self.window.current_h//2))
while not self.EXIT:
# check FPS
self.CLOCK.tick(self.FPS)
# render objects for each FPS
self.screen.fill((0, 0, 0))
self.location.add()
self.tank.add()
# flip window
pg.display.flip()
for event in pg.event.get():
if event.type == pg.QUIT:
self.EXIT = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
self.EXIT = True
key = pg.key.get_pressed()
self.tank.check(key)
pg.event.pump()
if __name__ == '__main__':
game = Game()