Реализация движения танка по консоли Pygame
Вопрос из серии: "почему не работает?" Есть программа (код ниже), реализующая передвижение танка по экрану. За движение отвечают кнопки WASD (впрочем, как обычно). В левом нижнем углу окна есть квадратики, которые меняют цвет, если нажата соответствующая кнопка (из WASD), и меняют его обратно при отпускании. Также нужно добавить текстовое отображение направления движения танка. В этом-то и заключается вся проблема: функционал этого текстового отчета есть, а почему не работает - ума не приложу.
За отображение текста отвечает класс Text, за саму отрисовку - функция draw, которая, в свою очередь вызывается в классах: UpCommand, DownCommand, LeftCommand и RightCommand.
Вот сам код:
import sys
from abc import ABC, abstractmethod
from math import cos, sin, pi
import pygame
class Color:
RED = (255, 0, 0)
GREEN = (0, 255, 0)
class PG:
_instance = None
def __init__(self, width=500, height=400):
if PG._instance is not None: # singleton implementation
raise ReferenceError('Tying to create singleton object twice')
else:
PG._instance = self
pygame.init()
self.screen = pygame.display.set_mode((width, height))
self.width = width
self.height = height
@staticmethod
def get():
if not PG._instance:
PG()
return PG._instance
class PGObject(ABC):
def __init__(self):
self.screen = PG.get().screen
def draw(self, string):
pass
def logic(self):
pass
class PGScene(ABC):
bgcolor = (0, 0, 0)
def __init__(self):
self.screen = PG.get().screen
self.sceneover = False
self.objects = []
def draw(self):
self.screen.fill(self.bgcolor)
for item in self.objects:
item.draw()
def process_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.sceneover = True
self.process_event(event)
def process_event(self, event):
pass
@abstractmethod
def process_logic(self):
for item in self.objects:
item.logic()
def main_loop(self):
while not self.sceneover:
self.process_events()
self.process_logic()
self.draw()
pygame.display.flip()
pygame.time.wait(10)
class GameScene(PGScene):
def __init__(self):
super().__init__()
self.panzer = Panzer(200, 200)
self.buttons = {
'up': StateRect(100, 500, 20, 20, Color.GREEN, Color.RED),
'down': StateRect(100, 530, 20, 20, Color.GREEN, Color.RED),
'left': StateRect(70, 530, 20, 20, Color.GREEN, Color.RED),
'right': StateRect(130, 530, 20, 20, Color.GREEN, Color.RED),
}
self.objects.append(self.panzer)
self.objects += self.buttons.values()
def process_logic(self):
super().process_logic()
def process_event(self, event):
if event.type == pygame.KEYUP and event.key in KeyUpMoment.keyup_events.keys():
KeyUpMoment.keyup_events[event.key](self).execute()
if event.type == pygame.KEYDOWN and event.key in KeyDownMoment.keydown_events.keys():
KeyDownMoment.keydown_events[event.key](self).execute()
class Text(PGObject):
def __init__(self):
super().__init__()
pygame.font.init()
self.font = pygame.font.SysFont('Comic Sans MS', 14, None)
self.color = Color.GREEN
def draw(self, string):
text = self.font.render(string, False, self.color)
self.screen.blit(text, (250, 150))
class Command(ABC):
def __init__(self, scene):
self.scene = scene
@abstractmethod
def execute(self):
pass
class UpCommand(Command):
def execute(self):
self.scene.panzer.move()
self.scene.buttons['up'].set_enabled(True)
self.scene.buttons['down'].set_enabled(False)
UpText = Text()
UpText.draw('движение вперёд')
print('движение вперёд')
class DownCommand(Command):
def execute(self):
self.scene.panzer.move_back()
self.scene.buttons['down'].set_enabled(True)
self.scene.buttons['up'].set_enabled(False)
DownText = Text()
DownText.draw('движение назад')
print('движение назад')
class LeftCommand(Command):
def execute(self):
self.scene.panzer.rotate(-0.5)
self.scene.buttons['left'].set_enabled(True)
self.scene.buttons['right'].set_enabled(False)
LeftText = Text()
LeftText.draw('движение влево')
print('движение влево')
class RightCommand(Command):
def execute(self):
self.scene.panzer.rotate(0.5)
self.scene.buttons['right'].set_enabled(True)
self.scene.buttons['left'].set_enabled(False)
RightText = Text()
RightText.draw('движение вправо')
print('движение вправо')
class KeyDownMoment(GameScene):
keydown_events = {
pygame.K_w: UpCommand,
pygame.K_s: DownCommand,
pygame.K_a: LeftCommand,
pygame.K_d: RightCommand,
}
class StopCommand(Command):
def execute(self):
self.scene.panzer.stop()
class StopUpCommand(StopCommand):
def execute(self):
super().execute()
self.scene.buttons['up']
class StopDownCommand(StopCommand):
def execute(self):
super().execute()
self.scene.buttons['down']
class StopLeftCommand(StopCommand):
def execute(self):
super().execute()
self.scene.buttons['left']
class StopRightCommand(StopCommand):
def execute(self):
super().execute()
self.scene.buttons['right']
class KeyUpMoment(GameScene):
keyup_events = {
pygame.K_w: StopUpCommand,
pygame.K_s: StopDownCommand,
pygame.K_a: StopLeftCommand,
pygame.K_d: StopRightCommand
}
class Panzer(PGObject):
def __init__(self, x, y):
super().__init__()
self.rotated_image = self.image = pygame.image.load("panzer.png")
self.rotated_rect = self.rect = self.image.get_rect()
self.x = x
self.y = y
self.direction = 0
self.speed = 0
self.max_speed = 1
def draw(self):
self.rect.x = self.x - self.rect.width // 2
self.rect.y = self.y - self.rect.height // 2
self.rotated_rect = self.rotated_image.get_rect(center=self.rect.center)
self.screen.blit(self.rotated_image, self.rotated_rect)
def move(self):
self.speed = self.max_speed
def move_back(self):
self.speed = -self.max_speed
def stop(self):
self.speed = 0
def step(self):
self.x += cos(self.direction) * self.speed
self.y += sin(self.direction) * self.speed
def rotate(self, angle):
self.direction += angle
self.rotated_image = pygame.transform.rotate(self.image, -self.direction / pi * 180)
self.rotated_rect = self.rotated_image.get_rect(center=self.rect.center)
def logic(self):
self.step()
class StateRect(PGObject):
def __init__(self, x, y, width, height, color_enabled, color_disabled):
super().__init__()
self.rect = (x, y, width, height)
self.color_enabled = color_enabled
self.color_disabled = color_disabled
self.enabled = False
def draw(self):
color = self.color_enabled if self.enabled else self.color_disabled,
pygame.draw.rect(self.screen, color, self.rect, 0)
def set_enabled(self, enabled):
self.enabled = enabled
if __name__ == "__main__":
PG(800, 600)
gs = GameScene()
gs.main_loop()
sys.exit()
Помогите, пожалуйста, с задачей. Если вдруг увидите ошибку, пожалуйста, подскажите решение проблемы. Заранее спасибо