Изменён пользовательский интерфейс main_menu.py, game_ui.py. Настроен вызов функций для запуска игрового процесса: после нажатия кнопки 'играть' открывается выбор собаки, а затем выбор уровня. Обновлена структура базы данных. Удалены не нужные файлы для проекта.
BIN
assets/background.png
Normal file
|
After Width: | Height: | Size: 821 KiB |
BIN
assets/bone.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
assets/dogs/Chihuahua.png
Normal file
|
After Width: | Height: | Size: 326 KiB |
BIN
assets/dogs/Corgi.png
Normal file
|
After Width: | Height: | Size: 253 KiB |
BIN
assets/dogs/Golden_Retriever.png
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
assets/dogs/Husky.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
assets/dogs/Pomeranian.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
assets/dogs/Pug.png
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
assets/dogs/Yorkshire_Terrier.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
assets/logo.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
103
config.py
|
|
@ -6,7 +6,7 @@ ADMIN_BUTTON_TEXT_COLOR = "#ffffff"
|
||||||
ADMIN_FONT = ("Comic Sans MS", 25)
|
ADMIN_FONT = ("Comic Sans MS", 25)
|
||||||
ADMIN_BIG_FONT = ("Comic Sans MS", 40)
|
ADMIN_BIG_FONT = ("Comic Sans MS", 40)
|
||||||
|
|
||||||
# Интерфейс пользователя
|
# Интерфейс пользователя (АВТОРИЗАЦИЯ)
|
||||||
BACKGROUND_COLOR = "#f8e1e1"
|
BACKGROUND_COLOR = "#f8e1e1"
|
||||||
PRIMARY_COLOR = "#ff6347"
|
PRIMARY_COLOR = "#ff6347"
|
||||||
BUTTON_COLOR = "#87ceeb"
|
BUTTON_COLOR = "#87ceeb"
|
||||||
|
|
@ -14,6 +14,26 @@ BUTTON_TEXT_COLOR = "white"
|
||||||
FONT = ("Comic Sans MS", 25)
|
FONT = ("Comic Sans MS", 25)
|
||||||
BIG_FONT = ("Comic Sans MS", 40)
|
BIG_FONT = ("Comic Sans MS", 40)
|
||||||
|
|
||||||
|
# ГЛАВНОЕ МЕНЮ
|
||||||
|
BACKGROUND_COLOR_USER = "#bcabe5" # Основной фон
|
||||||
|
TOP_PANEL_COLOR_USER = "#aa9bcd" # Цвет верхней панели
|
||||||
|
BUTTON_COLOR_PROFILE_USER = "#a2c792" # Цвет кнопок "Профиль", "Магазин", "База знаний"
|
||||||
|
BUTTON_COLOR_PLAY_USER = "#b4e1a1" # Цвет кнопки "Играть"
|
||||||
|
BUTTON_COLOR_EXIT_USER = "#a2c792" # Цвет кнопки "Выход"
|
||||||
|
BUTTON_TEXT_COLOR_USER = "white" # Цвет текста на кнопках
|
||||||
|
FONT_USER = ("Comic Sans MS", 20) # Шрифт для текста кнопок
|
||||||
|
BIG_FONT_USER = ("Comic Sans MS", 30) # Большой шрифт (например, для заголовков)
|
||||||
|
BUTTON_RADIUS_USER = 50 # Радиус круглой кнопки
|
||||||
|
EXIT_BUTTON_SIZE_USER = (80, 40) # Размер кнопки "Выход"
|
||||||
|
TOP_PANEL_COLOR = "#BBA0D0"
|
||||||
|
BUTTON_COLOR_PROFILE = "#8FC085"
|
||||||
|
BUTTON_COLOR_PLAY = "#8FC085"
|
||||||
|
BUTTON_COLOR_EXIT = "#8FC085"
|
||||||
|
# Размеры
|
||||||
|
PLAY_BUTTON_RADIUS = 100
|
||||||
|
EXIT_BUTTON_WIDTH = 100
|
||||||
|
EXIT_BUTTON_HEIGHT = 50
|
||||||
|
|
||||||
# Данные для авторизации администратора
|
# Данные для авторизации администратора
|
||||||
ADMIN_LOGIN = "admin"
|
ADMIN_LOGIN = "admin"
|
||||||
ADMIN_PASSWORD = "admin123"
|
ADMIN_PASSWORD = "admin123"
|
||||||
|
|
@ -23,23 +43,78 @@ DATABASE_URL = "sqlite:///database/DogAcademy.db" # Обновлено на п
|
||||||
|
|
||||||
# Иконки
|
# Иконки
|
||||||
SETTINGS_IMG = "assets/settings.png"
|
SETTINGS_IMG = "assets/settings.png"
|
||||||
|
LOGO = "F:/Projects/Dog_Academy/assets/logo.png"
|
||||||
|
BACKGROUND_GAME = "F:/Projects/Dog_Academy/assets/background.png"
|
||||||
|
BONE = "F:/Projects/Dog_Academy/assets/bone.png"
|
||||||
|
|
||||||
|
# Собаки
|
||||||
|
CHIHUAHUA = "F:/Projects/Dog_Academy/assets/dogs/Chihuahua.png"
|
||||||
|
CORGI = "F:/Projects/Dog_Academy/assets/dogs/Corgi.png"
|
||||||
|
RETRIEVER = "F:/Projects/Dog_Academy/assets/dogs/Golden_Retriever.png"
|
||||||
|
HUSKY = "F:/Projects/Dog_Academy/assets/dogs/Husky.png"
|
||||||
|
POMERANIAN = "F:/Projects/Dog_Academy/assets/dogs/Pomeranian.png"
|
||||||
|
PUG = "F:/Projects/Dog_Academy/assets/dogs/Pug.png"
|
||||||
|
YORKSHIRE = "F:/Projects/Dog_Academy/assets/dogs/Yorkshire_Terrier.png"
|
||||||
|
|
||||||
|
DOG_CHARACTERS = {
|
||||||
|
"Chihuahua": {
|
||||||
|
"image": CHIHUAHUA,
|
||||||
|
"speed": 8,
|
||||||
|
"endurance": 5,
|
||||||
|
"special_ability": "Fast Dodge", # Уклонение от препятствий
|
||||||
|
},
|
||||||
|
"Corgi": {
|
||||||
|
"image": CORGI,
|
||||||
|
"speed": 6,
|
||||||
|
"endurance": 7,
|
||||||
|
"special_ability": "Extra Jump", # Дополнительный прыжок
|
||||||
|
},
|
||||||
|
"Golden Retriever": {
|
||||||
|
"image": RETRIEVER,
|
||||||
|
"speed": 7,
|
||||||
|
"endurance": 8,
|
||||||
|
"special_ability": "Bonus Points", # Увеличенные очки за правильные ответы
|
||||||
|
},
|
||||||
|
"Husky": {
|
||||||
|
"image": HUSKY,
|
||||||
|
"speed": 9,
|
||||||
|
"endurance": 6,
|
||||||
|
"special_ability": "Speed Boost", # Ускорение
|
||||||
|
},
|
||||||
|
"Pomeranian": {
|
||||||
|
"image": POMERANIAN,
|
||||||
|
"speed": 7,
|
||||||
|
"endurance": 4,
|
||||||
|
"special_ability": "Charm", # Уменьшает штраф за ошибки
|
||||||
|
},
|
||||||
|
"Pug": {
|
||||||
|
"image": PUG,
|
||||||
|
"speed": 5,
|
||||||
|
"endurance": 9,
|
||||||
|
"special_ability": "Resilience", # Сохраняет здоровье при столкновениях
|
||||||
|
},
|
||||||
|
"Yorkshire Terrier": {
|
||||||
|
"image": YORKSHIRE,
|
||||||
|
"speed": 6,
|
||||||
|
"endurance": 5,
|
||||||
|
"special_ability": "Quick Recovery", # Быстрое восстановление характеристик
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# Утилиты
|
# Утилиты
|
||||||
NOTIFICATION_LEVEL = "info" # Возможные значения: "info", "warning", "error"
|
NOTIFICATION_LEVEL = "info" # Возможные значения: "info", "warning", "error"
|
||||||
USE_DATABASE_LOGS = True
|
USE_DATABASE_LOGS = True
|
||||||
|
|
||||||
# ГЛАВНОЕ МЕНЮ
|
# Игровые параметры
|
||||||
BACKGROUND_COLOR_USER = "#bcabe5" # Основной фон
|
INITIAL_SCORE = 5 # Начальные очки игрока
|
||||||
TOP_PANEL_COLOR_USER = "#aa9bcd" # Цвет верхней панели
|
POINTS_CORRECT_ANSWER = 2 # Очки за правильный ответ
|
||||||
BUTTON_COLOR_PROFILE_USER = "#a2c792" # Цвет кнопок "Профиль", "Магазин", "База знаний"
|
POINTS_WRONG_ANSWER = -1 # Штраф за неправильный ответ
|
||||||
BUTTON_COLOR_PLAY_USER = "#b4e1a1" # Цвет кнопки "Играть"
|
MAX_LEVELS = 100 # Максимальное количество уровней
|
||||||
BUTTON_COLOR_EXIT_USER = "#a2c792" # Цвет кнопки "Выход"
|
INITIAL_DOG_STATUS = {"health": 100, "hunger": 0, "sleepiness": 0} # Стартовые характеристики собаки
|
||||||
|
|
||||||
# Текст и шрифты
|
# Параметры карты
|
||||||
BUTTON_TEXT_COLOR_USER = "white" # Цвет текста на кнопках
|
MIN_OBSTACLES = 3 # Минимум препятствий на уровне
|
||||||
FONT_USER = ("Comic Sans MS", 20) # Шрифт для текста кнопок
|
MAX_OBSTACLES = 6 # Максимум препятствий на уровне
|
||||||
BIG_FONT_USER = ("Comic Sans MS", 30) # Большой шрифт (например, для заголовков)
|
|
||||||
|
|
||||||
# Размеры кнопок
|
# Графика и анимация
|
||||||
BUTTON_RADIUS_USER = 50 # Радиус круглой кнопки
|
COUNTDOWN_DURATION = 3 # Продолжительность обратного отсчёта в секундах
|
||||||
EXIT_BUTTON_SIZE_USER = (80, 40) # Размер кнопки "Выход"
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
|
from sqlalchemy import func
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
from database.db_session import get_session
|
from database.db_session import get_session
|
||||||
from database.models import Auth, Notifications, Users
|
from database.models import Auth, Notifications, Users, GameSession, Dogs, Questions
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
||||||
def create_user(login, password):
|
def create_user(login, password, username):
|
||||||
"""Создание нового пользователя в базе данных."""
|
"""Создание нового пользователя в базе данных."""
|
||||||
session = get_session()
|
session = get_session()
|
||||||
try:
|
try:
|
||||||
new_user = Auth(login=login, password=password)
|
new_user_auth = Auth(login=login, password=password)
|
||||||
|
session.add(new_user_auth)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
new_user = Users(username=username, auth=new_user_auth)
|
||||||
session.add(new_user)
|
session.add(new_user)
|
||||||
session.commit()
|
session.commit()
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
|
|
@ -20,9 +26,111 @@ def check_user(login, password):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
try:
|
try:
|
||||||
user = session.query(Auth).filter_by(login=login, password=password).first()
|
user = session.query(Auth).filter_by(login=login, password=password).first()
|
||||||
return user is not None
|
if user:
|
||||||
|
return user.user_id
|
||||||
|
return None
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
print(f"Ошибка при проверке пользователя: {e}")
|
print(f"Ошибка при проверке пользователя: {e}")
|
||||||
return False
|
return None
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
|
||||||
|
"""Сохраняет прогресс пользователя в базу данных."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
session_data = GameSession(
|
||||||
|
user_id=user_id,
|
||||||
|
level=level,
|
||||||
|
score=score,
|
||||||
|
duration=duration,
|
||||||
|
health=health,
|
||||||
|
hunger=hunger,
|
||||||
|
sleepiness=sleepiness,
|
||||||
|
end_time=func.now()
|
||||||
|
)
|
||||||
|
session.add(session_data)
|
||||||
|
session.commit()
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при сохранении прогресса: {e}")
|
||||||
|
session.rollback()
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def get_user_progress(user_id):
|
||||||
|
"""Получение прогресса пользователя по его ID."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
progress = session.query(GameSession).filter_by(user_id=user_id).all()
|
||||||
|
return progress
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при получении прогресса: {e}")
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def create_notification(user_id, message):
|
||||||
|
"""Создание уведомления для пользователя."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
notification = Notifications(user_id=user_id, message=message)
|
||||||
|
session.add(notification)
|
||||||
|
session.commit()
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при создании уведомления: {e}")
|
||||||
|
session.rollback()
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def get_notifications(user_id):
|
||||||
|
"""Получение уведомлений для пользователя."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
notifications = session.query(Notifications).filter_by(user_id=user_id).all()
|
||||||
|
return notifications
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при получении уведомлений: {e}")
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def get_knowledge_base():
|
||||||
|
"""Получение базы знаний (статей о собаках)."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
dogs = session.query(Dogs).all()
|
||||||
|
return dogs # Список объектов Dogs
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при получении базы знаний: {e}")
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def get_dogs():
|
||||||
|
"""Получение списка пород собак."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
dogs = session.query(Dogs).all()
|
||||||
|
return dogs # Список объектов Dogs
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при получении списка собак: {e}")
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def update_user_dog(user_id, dog_id):
|
||||||
|
"""Обновление выбранной пользователем породы собаки."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
user = session.query(Users).filter_by(user_id=user_id).first()
|
||||||
|
if user:
|
||||||
|
user.dog_id = dog_id
|
||||||
|
session.commit()
|
||||||
|
print(f"Порода пользователя обновлена на {dog_id}")
|
||||||
|
else:
|
||||||
|
print("Пользователь не найден.")
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
print(f"Ошибка при обновлении породы собаки: {e}")
|
||||||
|
session.rollback()
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ Session = sessionmaker(bind=engine)
|
||||||
# Переменная для хранения текущей сессии
|
# Переменная для хранения текущей сессии
|
||||||
current_session = None
|
current_session = None
|
||||||
|
|
||||||
|
|
||||||
def init_db(refresh=False):
|
def init_db(refresh=False):
|
||||||
"""
|
"""
|
||||||
Инициализация базы данных: создание файла и таблиц.
|
Инициализация базы данных: создание файла и таблиц.
|
||||||
|
|
@ -33,18 +32,14 @@ def init_db(refresh=False):
|
||||||
# Инициализация сессии при запуске
|
# Инициализация сессии при запуске
|
||||||
current_session = get_session()
|
current_session = get_session()
|
||||||
|
|
||||||
|
|
||||||
def get_session():
|
def get_session():
|
||||||
"""Возвращает сессию для работы с базой данных."""
|
"""Возвращает сессию для работы с базой данных."""
|
||||||
return Session()
|
return Session()
|
||||||
|
|
||||||
|
|
||||||
def close_sessions():
|
def close_sessions():
|
||||||
"""Закрытие всех сессий перед выходом из программы."""
|
"""Закрытие всех сессий перед выходом из программы."""
|
||||||
global current_session
|
if current_session:
|
||||||
if current_session is not None:
|
|
||||||
print("Закрытие сессии...")
|
print("Закрытие сессии...")
|
||||||
current_session.close() # Закрываем текущую сессию базы данных
|
current_session.close()
|
||||||
current_session = None
|
|
||||||
else:
|
else:
|
||||||
print("Нет активной сессии для закрытия.")
|
print("Нет активной сессии для закрытия.")
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime
|
from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, UniqueConstraint, Boolean
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
class Auth(Base):
|
class Auth(Base):
|
||||||
__tablename__ = 'auth'
|
__tablename__ = 'auth'
|
||||||
user_id = Column(Integer, primary_key=True)
|
user_id = Column(Integer, primary_key=True)
|
||||||
|
|
@ -50,7 +49,7 @@ class Questions(Base):
|
||||||
__tablename__ = 'questions'
|
__tablename__ = 'questions'
|
||||||
question_id = Column(Integer, primary_key=True)
|
question_id = Column(Integer, primary_key=True)
|
||||||
dog_id = Column(Integer, ForeignKey('dogs.dog_id'))
|
dog_id = Column(Integer, ForeignKey('dogs.dog_id'))
|
||||||
question_text = Column(Text, nullable=False) # Исправлено поле
|
question_text = Column(Text, nullable=False)
|
||||||
image_url = Column(String)
|
image_url = Column(String)
|
||||||
helpful_info = Column(Text)
|
helpful_info = Column(Text)
|
||||||
incorrect_attempts = Column(Integer, default=0)
|
incorrect_attempts = Column(Integer, default=0)
|
||||||
|
|
@ -61,24 +60,31 @@ class Questions(Base):
|
||||||
|
|
||||||
class GameSession(Base):
|
class GameSession(Base):
|
||||||
__tablename__ = 'game_sessions'
|
__tablename__ = 'game_sessions'
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint('user_id', 'level', name='uix_user_level'),
|
||||||
|
)
|
||||||
session_id = Column(Integer, primary_key=True)
|
session_id = Column(Integer, primary_key=True)
|
||||||
user_id = Column(Integer, ForeignKey('users.user_id'))
|
user_id = Column(Integer, ForeignKey('users.user_id'))
|
||||||
level = Column(Integer, nullable=False)
|
level = Column(Integer, nullable=False)
|
||||||
score = Column(Integer, default=0)
|
score = Column(Integer, default=0)
|
||||||
duration = Column(Integer) # Время игры в секундах
|
duration = Column(Integer) # Время игры в секундах
|
||||||
start_time = Column(DateTime, default=func.now()) # Исправлено
|
start_time = Column(DateTime, default=func.now())
|
||||||
end_time = Column(DateTime, nullable=True)
|
end_time = Column(DateTime, nullable=True)
|
||||||
|
health = Column(Integer, default=100) # Здоровье
|
||||||
|
hunger = Column(Integer, default=0) # Голод
|
||||||
|
sleepiness = Column(Integer, default=0) # Сонливость
|
||||||
|
|
||||||
# Связь с таблицей Users
|
# Связь с таблицей Users
|
||||||
user = relationship("Users", back_populates="game_sessions")
|
user = relationship("Users", back_populates="game_sessions")
|
||||||
|
|
||||||
|
|
||||||
class Notifications(Base):
|
class Notifications(Base):
|
||||||
__tablename__ = 'notifications'
|
__tablename__ = 'notifications'
|
||||||
notification_id = Column(Integer, primary_key=True)
|
notification_id = Column(Integer, primary_key=True)
|
||||||
user_id = Column(Integer, ForeignKey('users.user_id'))
|
user_id = Column(Integer, ForeignKey('users.user_id'))
|
||||||
message = Column(Text, nullable=False)
|
message = Column(Text, nullable=False)
|
||||||
timestamp = Column(DateTime, default=func.now())
|
timestamp = Column(DateTime, default=func.now())
|
||||||
is_read = Column(Integer, default=0) # 0 - не прочитано, 1 - прочитано
|
is_read = Column(Boolean, default=False) # Булевый тип для read
|
||||||
|
|
||||||
# Связь с таблицей Users
|
# Связь с таблицей Users
|
||||||
user = relationship("Users", back_populates="notifications")
|
user = relationship("Users", back_populates="notifications")
|
||||||
|
|
|
||||||
BIN
ishodniki/background_game.psd
Normal file
BIN
ishodniki/dogs.psd
Normal file
BIN
ishodniki/user_ui.psd
Normal file
125
logs/logfile.log
|
|
@ -1343,3 +1343,128 @@ WHERE auth.login = ? AND auth.password = ?
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
2024-11-25 22:36:09 - [generated in 0.00045s] ('lubluNikitu', 'meow123', 1, 0)
|
2024-11-25 22:36:09 - [generated in 0.00045s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
2024-11-25 22:36:09 - ROLLBACK
|
2024-11-25 22:36:09 - ROLLBACK
|
||||||
|
2024-11-26 12:26:39 - BEGIN (implicit)
|
||||||
|
2024-11-26 12:26:39 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 12:26:39 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 12:26:39 - ROLLBACK
|
||||||
|
2024-11-26 12:33:48 - BEGIN (implicit)
|
||||||
|
2024-11-26 12:33:48 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 12:33:48 - [generated in 0.00022s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 12:33:48 - ROLLBACK
|
||||||
|
2024-11-26 12:38:38 - BEGIN (implicit)
|
||||||
|
2024-11-26 12:38:38 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 12:38:38 - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 12:38:38 - ROLLBACK
|
||||||
|
2024-11-26 17:00:02 - BEGIN (implicit)
|
||||||
|
2024-11-26 17:00:02 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 17:00:02 - [generated in 0.00024s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 17:00:02 - ROLLBACK
|
||||||
|
2024-11-26 17:01:01 - BEGIN (implicit)
|
||||||
|
2024-11-26 17:01:01 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 17:01:01 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 17:01:01 - ROLLBACK
|
||||||
|
2024-11-26 17:07:02 - BEGIN (implicit)
|
||||||
|
2024-11-26 17:07:02 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 17:07:02 - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 17:07:02 - ROLLBACK
|
||||||
|
2024-11-26 17:08:03 - BEGIN (implicit)
|
||||||
|
2024-11-26 17:08:03 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 17:08:03 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 17:08:03 - ROLLBACK
|
||||||
|
2024-11-26 17:27:44 - BEGIN (implicit)
|
||||||
|
2024-11-26 17:27:44 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 17:27:44 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 17:27:44 - ROLLBACK
|
||||||
|
2024-11-26 19:46:13 - BEGIN (implicit)
|
||||||
|
2024-11-26 19:46:13 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 19:46:13 - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 19:46:13 - ROLLBACK
|
||||||
|
2024-11-26 21:23:20 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:23:20 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 21:23:20 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 21:23:20 - ROLLBACK
|
||||||
|
2024-11-26 21:31:58 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:31:58 - SELECT count(*) AS count_1
|
||||||
|
FROM (SELECT users.user_id AS users_user_id, users.dog_id AS users_dog_id, users.username AS users_username, users.level AS users_level, users.achievement AS users_achievement
|
||||||
|
FROM users) AS anon_1
|
||||||
|
2024-11-26 21:31:58 - [generated in 0.00026s] ()
|
||||||
|
2024-11-26 21:31:58 - SELECT game_sessions.level AS game_sessions_level, count(game_sessions.session_id) AS count_1
|
||||||
|
FROM game_sessions GROUP BY game_sessions.level
|
||||||
|
2024-11-26 21:31:58 - [generated in 0.00022s] ()
|
||||||
|
2024-11-26 21:31:58 - SELECT questions.question_text AS questions_question_text, questions.incorrect_attempts AS questions_incorrect_attempts
|
||||||
|
FROM questions ORDER BY questions.incorrect_attempts DESC
|
||||||
|
2024-11-26 21:31:58 - [generated in 0.00019s] ()
|
||||||
|
2024-11-26 21:31:58 - SELECT avg(game_sessions.duration) AS avg_1
|
||||||
|
FROM game_sessions
|
||||||
|
2024-11-26 21:31:58 - [generated in 0.00014s] ()
|
||||||
|
2024-11-26 21:31:58 - ROLLBACK
|
||||||
|
2024-11-26 21:31:58 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:31:58 - SELECT game_sessions.start_time AS game_sessions_start_time
|
||||||
|
FROM game_sessions
|
||||||
|
2024-11-26 21:31:58 - [generated in 0.00017s] ()
|
||||||
|
2024-11-26 21:31:58 - ROLLBACK
|
||||||
|
2024-11-26 21:34:57 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:34:57 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 21:34:57 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 21:34:57 - ROLLBACK
|
||||||
|
2024-11-26 21:47:02 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:47:02 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 21:47:02 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 21:47:02 - ROLLBACK
|
||||||
|
2024-11-26 21:49:25 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:49:25 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 21:49:25 - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 21:49:25 - ROLLBACK
|
||||||
|
2024-11-26 21:54:33 - BEGIN (implicit)
|
||||||
|
2024-11-26 21:54:33 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 21:54:33 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 21:54:33 - ROLLBACK
|
||||||
|
2024-11-26 22:41:31 - BEGIN (implicit)
|
||||||
|
2024-11-26 22:41:31 - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
|
||||||
|
FROM auth
|
||||||
|
WHERE auth.login = ? AND auth.password = ?
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
2024-11-26 22:41:31 - [generated in 0.00027s] ('lubluNikitu', 'meow123', 1, 0)
|
||||||
|
2024-11-26 22:41:31 - ROLLBACK
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
|
||||||
from tkinter import Tk, messagebox
|
from tkinter import Tk, messagebox
|
||||||
from src.ui.auth_ui import DogAcademyApp # Путь к приложению
|
from src.ui.auth_ui import DogAcademyApp # Путь к приложению
|
||||||
from database.db_session import init_db, close_sessions # Функция для закрытия сессий
|
from database.db_session import init_db, close_sessions # Функция для закрытия сессий
|
||||||
|
|
|
||||||
|
|
@ -219,4 +219,4 @@ class DogAcademyApp:
|
||||||
def show_user_dashboard(self):
|
def show_user_dashboard(self):
|
||||||
self.clear_frame()
|
self.clear_frame()
|
||||||
"""Перейти к главному меню пользователя после авторизации."""
|
"""Перейти к главному меню пользователя после авторизации."""
|
||||||
UserApp(self.root, self)
|
UserApp(self.root)
|
||||||
|
|
|
||||||
BIN
src/ui/user_ui/__pycache__/game_ui.cpython-313.pyc
Normal file
BIN
src/ui/user_ui/__pycache__/knowledge_ui.cpython-313.pyc
Normal file
BIN
src/ui/user_ui/__pycache__/profile_ui.cpython-313.pyc
Normal file
BIN
src/ui/user_ui/__pycache__/shop_ui.cpython-313.pyc
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
from src.utils import clear_frame
|
||||||
|
from config import DOG_CHARACTERS, BACKGROUND_GAME, LOGO, COUNTDOWN_DURATION
|
||||||
|
from src.user_functions.map_generator import generate_map
|
||||||
|
from src.user_functions.game_functions import handle_obstacle
|
||||||
|
|
||||||
|
|
||||||
|
class GameUI:
|
||||||
|
def __init__(self, root, user_id):
|
||||||
|
self.root = root
|
||||||
|
self.user_id = user_id
|
||||||
|
self.selected_dog = None
|
||||||
|
self.current_level = 1
|
||||||
|
self.score = 0
|
||||||
|
|
||||||
|
self.root.configure(bg="lightblue")
|
||||||
|
self.create_logo()
|
||||||
|
self.show_dog_selection()
|
||||||
|
|
||||||
|
def create_logo(self):
|
||||||
|
"""Создание логотипа."""
|
||||||
|
logo_image = Image.open(LOGO)
|
||||||
|
logo_photo = ImageTk.PhotoImage(logo_image.resize((200, 100), Image.Resampling.LANCZOS))
|
||||||
|
logo_label = tk.Label(self.root, image=logo_photo, bg="lightblue")
|
||||||
|
logo_label.image = logo_photo
|
||||||
|
logo_label.pack(pady=10)
|
||||||
|
|
||||||
|
def show_dog_selection(self):
|
||||||
|
"""Выбор собаки пользователем."""
|
||||||
|
clear_frame(self.root)
|
||||||
|
tk.Label(
|
||||||
|
self.root, text="Выберите собаку", font=("Comic Sans MS", 24), bg="lightblue"
|
||||||
|
).pack(pady=20)
|
||||||
|
|
||||||
|
dog_frame = tk.Frame(self.root, bg="lightblue")
|
||||||
|
dog_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Центрируем фрейм
|
||||||
|
|
||||||
|
for breed, details in DOG_CHARACTERS.items():
|
||||||
|
dog_image = Image.open(details["image"])
|
||||||
|
dog_photo = ImageTk.PhotoImage(dog_image.resize((150, 150), Image.Resampling.LANCZOS))
|
||||||
|
|
||||||
|
# Фрейм для кнопки и подписи
|
||||||
|
dog_item = tk.Frame(dog_frame, bg="lightblue")
|
||||||
|
dog_item.pack(side=tk.LEFT, padx=15, pady=15)
|
||||||
|
|
||||||
|
# Кнопка с изображением
|
||||||
|
button = tk.Button(
|
||||||
|
dog_item,
|
||||||
|
image=dog_photo,
|
||||||
|
command=lambda b=breed: self.confirm_dog_selection(b),
|
||||||
|
bg="lightblue",
|
||||||
|
borderwidth=0,
|
||||||
|
)
|
||||||
|
button.image = dog_photo # Сохраняем ссылку на изображение
|
||||||
|
button.pack()
|
||||||
|
|
||||||
|
# Подпись с породой собаки
|
||||||
|
tk.Label(
|
||||||
|
dog_item,
|
||||||
|
text=breed,
|
||||||
|
font=("Comic Sans MS", 16),
|
||||||
|
bg="lightblue"
|
||||||
|
).pack(pady=5)
|
||||||
|
|
||||||
|
def confirm_dog_selection(self, breed):
|
||||||
|
"""Подтверждение выбора собаки."""
|
||||||
|
self.selected_dog = breed
|
||||||
|
self.show_level_selection()
|
||||||
|
|
||||||
|
def show_level_selection(self):
|
||||||
|
"""Отображение выбора уровня."""
|
||||||
|
clear_frame(self.root)
|
||||||
|
tk.Label(
|
||||||
|
self.root, text="Выберите уровень", font=("Comic Sans MS", 20), bg="lightblue"
|
||||||
|
).pack(pady=10)
|
||||||
|
|
||||||
|
level_frame = tk.Frame(self.root, bg="lightblue")
|
||||||
|
level_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Центрируем фрейм
|
||||||
|
|
||||||
|
for level in range(1, 6): # Доступно 5 уровней
|
||||||
|
tk.Button(
|
||||||
|
level_frame,
|
||||||
|
text=f"Уровень {level}",
|
||||||
|
command=lambda l=level: self.start_level(l),
|
||||||
|
font=("Comic Sans MS", 16),
|
||||||
|
bg="lightgreen",
|
||||||
|
width=12,
|
||||||
|
).pack(pady=10)
|
||||||
|
|
||||||
|
def start_level(self, level):
|
||||||
|
"""Начало выбранного уровня."""
|
||||||
|
self.current_level = level
|
||||||
|
self.countdown()
|
||||||
|
|
||||||
|
def countdown(self):
|
||||||
|
"""Обратный отсчёт перед началом уровня."""
|
||||||
|
clear_frame(self.root)
|
||||||
|
countdown_label = tk.Label(
|
||||||
|
self.root, text="", font=("Comic Sans MS", 30), bg="lightblue"
|
||||||
|
)
|
||||||
|
countdown_label.pack(expand=True)
|
||||||
|
|
||||||
|
for i in range(COUNTDOWN_DURATION, 0, -1):
|
||||||
|
countdown_label.config(text=f"{i}...")
|
||||||
|
self.root.update()
|
||||||
|
self.root.after(1000)
|
||||||
|
|
||||||
|
self.start_game()
|
||||||
|
|
||||||
|
def start_game(self):
|
||||||
|
"""Запуск игрового процесса."""
|
||||||
|
clear_frame(self.root)
|
||||||
|
|
||||||
|
# Генерация карты
|
||||||
|
map_data = generate_map(self.current_level)
|
||||||
|
|
||||||
|
for obstacle in map_data:
|
||||||
|
result = handle_obstacle(obstacle, self.score, self.root)
|
||||||
|
self.score = result["new_score"]
|
||||||
|
|
||||||
|
if self.score >= 10: # Условие победы
|
||||||
|
self.show_victory_screen()
|
||||||
|
|
||||||
|
def show_victory_screen(self):
|
||||||
|
"""Экран победы."""
|
||||||
|
clear_frame(self.root)
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
self.root, text="Ура, победа!", font=("Comic Sans MS", 30), bg="lightblue"
|
||||||
|
).pack(pady=10)
|
||||||
|
|
||||||
|
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"])
|
||||||
|
dog_photo = ImageTk.PhotoImage(dog_image.resize((150, 150), Image.Resampling.LANCZOS))
|
||||||
|
tk.Label(self.root, image=dog_photo, bg="lightblue").pack(pady=10)
|
||||||
|
tk.Label(
|
||||||
|
self.root,
|
||||||
|
text=f"Порода: {self.selected_dog}\nСобрано косточек: {self.score}",
|
||||||
|
font=("Comic Sans MS", 20),
|
||||||
|
bg="lightblue",
|
||||||
|
).pack(pady=10)
|
||||||
|
|
||||||
|
tk.Button(
|
||||||
|
self.root,
|
||||||
|
text="Вернуться в главное меню",
|
||||||
|
command=lambda: self.__init__(self.root, self.user_id),
|
||||||
|
font=("Comic Sans MS", 16),
|
||||||
|
bg="lightgreen",
|
||||||
|
).pack(pady=10)
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from src.utils import clear_frame
|
||||||
|
from database.db_events import get_knowledge_base
|
||||||
|
|
||||||
|
|
||||||
|
def knowledge_ui(root):
|
||||||
|
"""Интерфейс базы знаний."""
|
||||||
|
clear_frame(root)
|
||||||
|
|
||||||
|
frame = tk.Frame(root, bg="#f8e1e1")
|
||||||
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
tk.Label(frame, text="База знаний", font=("Comic Sans MS", 30), bg="#f8e1e1").pack(pady=20)
|
||||||
|
|
||||||
|
articles = get_knowledge_base()
|
||||||
|
for article in articles:
|
||||||
|
article_frame = tk.Frame(frame, bg="#f8f8f8", bd=2, relief=tk.RIDGE)
|
||||||
|
article_frame.pack(pady=5, padx=10, fill=tk.X)
|
||||||
|
|
||||||
|
tk.Label(article_frame, text=article.breed, font=("Comic Sans MS", 20), bg="#f8f8f8").pack(side=tk.LEFT,
|
||||||
|
padx=10)
|
||||||
|
tk.Button(article_frame, text="Читать", command=lambda a=article: show_article(a)).pack(side=tk.RIGHT, padx=10)
|
||||||
|
|
||||||
|
tk.Button(frame, text="Назад", command=lambda: clear_frame(root), font=("Comic Sans MS", 20)).pack(pady=20)
|
||||||
|
|
||||||
|
|
||||||
|
def show_article(article):
|
||||||
|
"""Показать содержимое статьи."""
|
||||||
|
top = tk.Toplevel()
|
||||||
|
top.title(article.breed)
|
||||||
|
text = tk.Text(top, wrap=tk.WORD)
|
||||||
|
text.pack(fill=tk.BOTH, expand=True)
|
||||||
|
text.insert(tk.END, article.content)
|
||||||
|
text.config(state=tk.DISABLED)
|
||||||
|
|
@ -1,78 +1,167 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from config import (
|
from tkinter import Canvas
|
||||||
BACKGROUND_COLOR_USER,
|
from PIL import Image, ImageTk
|
||||||
TOP_PANEL_COLOR_USER,
|
import math
|
||||||
BUTTON_COLOR_PROFILE_USER,
|
|
||||||
BUTTON_COLOR_PLAY_USER,
|
from config import EXIT_BUTTON_WIDTH, EXIT_BUTTON_HEIGHT, BUTTON_COLOR_EXIT
|
||||||
BUTTON_COLOR_EXIT_USER,
|
from src.ui.user_ui.game_ui import GameUI
|
||||||
BUTTON_TEXT_COLOR_USER,
|
from src.ui.user_ui.profile_ui import profile_ui
|
||||||
FONT_USER,
|
from src.ui.user_ui.shop_ui import shop_ui
|
||||||
BIG_FONT_USER,
|
from src.ui.user_ui.knowledge_ui import knowledge_ui
|
||||||
BUTTON_RADIUS_USER,
|
from src.utils import clear_frame
|
||||||
EXIT_BUTTON_SIZE_USER,
|
|
||||||
)
|
# Пути к изображениям собак
|
||||||
|
DOG_IMAGES = [
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Chihuahua.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Corgi.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Golden_Retriever.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Husky.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Pomeranian.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Pug.png",
|
||||||
|
"F:/Projects/Dog_Academy/assets/dogs/Yorkshire_Terrier.png"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Настройки
|
||||||
|
BACKGROUND_COLOR = "#E5E5E5" # Цвет фона
|
||||||
|
BUTTON_COLOR_PLAY = "#4CAF50" # Цвет кнопки играть
|
||||||
|
BUTTON_TEXT_COLOR = "white" # Цвет текста на кнопке
|
||||||
|
FONT = ("Arial", 12)
|
||||||
|
BIG_FONT = ("Arial", 24)
|
||||||
|
PLAY_BUTTON_RADIUS = 100 # Радиус кнопки "Играть"
|
||||||
|
|
||||||
|
|
||||||
class UserApp:
|
class UserApp:
|
||||||
def __init__(self, root, auth_ui):
|
def __init__(self, root, user_id=None):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.auth_ui = auth_ui
|
self.user_id = user_id
|
||||||
self.root.configure(bg=BACKGROUND_COLOR_USER)
|
self.root.configure(bg=BACKGROUND_COLOR)
|
||||||
self.root.geometry("1920x1080") # Разрешение окна
|
self.root.geometry("1920x1080")
|
||||||
self.root.title("Собачья академия")
|
self.root.title("Собачья академия")
|
||||||
print("Главное меню активно") # Лог при открытии меню
|
|
||||||
self.show_user_dashboard()
|
self.show_user_dashboard()
|
||||||
|
|
||||||
def show_user_dashboard(self):
|
def show_user_dashboard(self):
|
||||||
"""Показать интерфейс пользователя."""
|
"""Показать интерфейс пользователя."""
|
||||||
|
center_x, center_y = 960, 540 # Центр экрана
|
||||||
|
radius = 300 # Радиус круга для размещения собак
|
||||||
|
num_dogs = len(DOG_IMAGES)
|
||||||
|
|
||||||
# Верхняя панель
|
# Верхняя панель
|
||||||
top_panel = tk.Frame(self.root, bg=TOP_PANEL_COLOR_USER, height=100)
|
top_panel = tk.Frame(self.root, bg="#333333", height=100)
|
||||||
top_panel.pack(fill=tk.X, side=tk.TOP)
|
top_panel.pack(fill=tk.X, side=tk.TOP)
|
||||||
|
|
||||||
# Кнопки на верхней панели
|
# Кнопки на верхней панели
|
||||||
for text, command in [("Профиль", self.show_profile), ("Магазин", self.show_shop), ("База знаний", self.show_knowledge)]:
|
profile_button = tk.Button(
|
||||||
button = tk.Button(
|
top_panel,
|
||||||
top_panel,
|
text="Профиль",
|
||||||
text=text,
|
bg="#555555",
|
||||||
bg=BUTTON_COLOR_PROFILE_USER,
|
fg="white",
|
||||||
fg=BUTTON_TEXT_COLOR_USER,
|
font=FONT,
|
||||||
font=FONT_USER,
|
|
||||||
relief=tk.FLAT,
|
|
||||||
padx=20,
|
|
||||||
pady=10,
|
|
||||||
command=command,
|
|
||||||
)
|
|
||||||
button.pack(side=tk.LEFT, padx=20)
|
|
||||||
|
|
||||||
# Кнопка "Играть" в центре
|
|
||||||
play_button = tk.Button(
|
|
||||||
self.root,
|
|
||||||
text="Играть",
|
|
||||||
bg=BUTTON_COLOR_PLAY_USER,
|
|
||||||
fg=BUTTON_TEXT_COLOR_USER,
|
|
||||||
font=BIG_FONT_USER,
|
|
||||||
relief=tk.FLAT,
|
relief=tk.FLAT,
|
||||||
height=2,
|
padx=20,
|
||||||
width=10,
|
pady=10,
|
||||||
command=self.play_game,
|
command=self.show_profile
|
||||||
)
|
)
|
||||||
play_button.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
profile_button.pack(side=tk.LEFT, padx=20)
|
||||||
|
|
||||||
# Кнопка "Выход" в правом нижнем углу
|
shop_button = tk.Button(
|
||||||
exit_button = tk.Button(
|
top_panel,
|
||||||
self.root,
|
text="Магазин",
|
||||||
text="Выход",
|
bg="#555555",
|
||||||
bg=BUTTON_COLOR_EXIT_USER,
|
fg="white",
|
||||||
fg=BUTTON_TEXT_COLOR_USER,
|
font=FONT,
|
||||||
font=FONT_USER,
|
relief=tk.FLAT,
|
||||||
width=EXIT_BUTTON_SIZE_USER[0] // 10,
|
padx=20,
|
||||||
height=EXIT_BUTTON_SIZE_USER[1] // 10,
|
pady=10,
|
||||||
command=self.exit_app,
|
command=self.show_shop
|
||||||
)
|
)
|
||||||
exit_button.place(relx=1.0, rely=1.0, x=-20, y=-20, anchor=tk.SE)
|
shop_button.pack(side=tk.LEFT, padx=20)
|
||||||
|
|
||||||
|
knowledge_button = tk.Button(
|
||||||
|
top_panel,
|
||||||
|
text="База знаний",
|
||||||
|
bg="#555555",
|
||||||
|
fg="white",
|
||||||
|
font=FONT,
|
||||||
|
relief=tk.FLAT,
|
||||||
|
padx=20,
|
||||||
|
pady=10,
|
||||||
|
command=self.show_knowledge
|
||||||
|
)
|
||||||
|
knowledge_button.pack(side=tk.LEFT, padx=20)
|
||||||
|
|
||||||
|
# Размещение собак по кругу
|
||||||
|
self.place_dog_images(center_x, center_y, radius, num_dogs)
|
||||||
|
|
||||||
|
# Кнопка "Играть" (увеличенная)
|
||||||
|
play_button_canvas = tk.Canvas(
|
||||||
|
self.root,
|
||||||
|
width=PLAY_BUTTON_RADIUS * 2,
|
||||||
|
height=PLAY_BUTTON_RADIUS * 2,
|
||||||
|
bg=BACKGROUND_COLOR,
|
||||||
|
highlightthickness=0,
|
||||||
|
)
|
||||||
|
play_button_canvas.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
||||||
|
|
||||||
|
play_button_canvas.create_oval(
|
||||||
|
0, 0, PLAY_BUTTON_RADIUS * 2, PLAY_BUTTON_RADIUS * 2,
|
||||||
|
fill=BUTTON_COLOR_PLAY,
|
||||||
|
outline=BUTTON_COLOR_PLAY,
|
||||||
|
)
|
||||||
|
play_button_canvas.create_text(
|
||||||
|
PLAY_BUTTON_RADIUS,
|
||||||
|
PLAY_BUTTON_RADIUS,
|
||||||
|
text="Играть",
|
||||||
|
fill=BUTTON_TEXT_COLOR,
|
||||||
|
font=BIG_FONT,
|
||||||
|
)
|
||||||
|
play_button_canvas.tag_bind("all", "<Button-1>", lambda e: self.play_game())
|
||||||
|
|
||||||
|
def place_dog_images(self, center_x, center_y, radius, num_dogs):
|
||||||
|
"""Размещает изображения собак по кругу."""
|
||||||
|
angle_step = 2 * math.pi / num_dogs # Шаг угла для размещения собак
|
||||||
|
for i in range(num_dogs):
|
||||||
|
angle = i * angle_step
|
||||||
|
x = center_x + radius * math.cos(angle)
|
||||||
|
y = center_y + radius * math.sin(angle)
|
||||||
|
|
||||||
|
# Загрузка изображения собаки
|
||||||
|
image_path = DOG_IMAGES[i]
|
||||||
|
try:
|
||||||
|
dog_image = Image.open(image_path)
|
||||||
|
dog_image = dog_image.resize((100, 100), Image.Resampling.LANCZOS)
|
||||||
|
dog_photo = ImageTk.PhotoImage(dog_image)
|
||||||
|
|
||||||
|
# Создание метки с изображением
|
||||||
|
dog_label = tk.Label(self.root, image=dog_photo, bg=BACKGROUND_COLOR)
|
||||||
|
dog_label.image = dog_photo # Сохраняем ссылку на изображение
|
||||||
|
dog_label.place(x=x - 50, y=y - 50) # Центрируем метку относительно позиции
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка загрузки изображения {image_path}: {e}")
|
||||||
|
|
||||||
|
def show_profile(self):
|
||||||
|
"""Показать экран профиля пользователя."""
|
||||||
|
self.clear_frame()
|
||||||
|
profile_ui(self.root, self.user_id) # Передаем user_id в profile_ui
|
||||||
|
|
||||||
|
def show_shop(self):
|
||||||
|
"""Показать экран магазина."""
|
||||||
|
self.clear_frame()
|
||||||
|
shop_ui(self.root)
|
||||||
|
|
||||||
|
def show_knowledge(self):
|
||||||
|
"""Показать базу знаний."""
|
||||||
|
self.clear_frame()
|
||||||
|
knowledge_ui(self.root)
|
||||||
|
|
||||||
|
def clear_frame(self):
|
||||||
|
"""Очистить текущий экран."""
|
||||||
|
for widget in self.root.winfo_children():
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
def play_game(self):
|
def play_game(self):
|
||||||
"""Заглушка для игры."""
|
"""Переход к игровому интерфейсу."""
|
||||||
|
clear_frame(self.root) # Очищаем главное меню
|
||||||
|
GameUI(self.root, self.user_id) # Открываем игровой интерфейс
|
||||||
print("Запуск игры...")
|
print("Запуск игры...")
|
||||||
|
|
||||||
def exit_app(self):
|
def exit_app(self):
|
||||||
|
|
@ -80,14 +169,9 @@ class UserApp:
|
||||||
print("Приложение закрыто")
|
print("Приложение закрыто")
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
def show_profile(self):
|
# Запуск главного окна
|
||||||
"""Заглушка для профиля."""
|
if __name__ == "__main__":
|
||||||
print("Переход в профиль...")
|
root = tk.Tk()
|
||||||
|
app = UserApp(root, user_id=123) # Передаем user_id (это может быть получено после авторизации)
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
def show_shop(self):
|
|
||||||
"""Заглушка для магазина."""
|
|
||||||
print("Переход в магазин...")
|
|
||||||
|
|
||||||
def show_knowledge(self):
|
|
||||||
"""Заглушка для базы знаний."""
|
|
||||||
print("Переход в базу знаний...")
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from src.utils import clear_frame
|
||||||
|
from database.db_events import get_user_progress
|
||||||
|
|
||||||
|
|
||||||
|
def profile_ui(root, user_id):
|
||||||
|
"""Интерфейс профиля пользователя."""
|
||||||
|
clear_frame(root)
|
||||||
|
|
||||||
|
frame = tk.Frame(root, bg="#f8e1e1")
|
||||||
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
tk.Label(frame, text="Профиль", font=("Comic Sans MS", 30), bg="#f8e1e1").pack(pady=20)
|
||||||
|
|
||||||
|
# Статистика пользователя
|
||||||
|
progress = get_user_progress(user_id)
|
||||||
|
levels_completed = len(progress)
|
||||||
|
bones_collected = sum([session.score for session in progress])
|
||||||
|
|
||||||
|
stats_text = f"Пройдено уровней: {levels_completed}\nСобрано косточек: {bones_collected}"
|
||||||
|
tk.Label(frame, text=stats_text, font=("Comic Sans MS", 20), bg="#f8e1e1").pack(pady=10)
|
||||||
|
|
||||||
|
tk.Button(frame, text="Назад", command=lambda: clear_frame(root), font=("Comic Sans MS", 20)).pack(pady=20)
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import tkinter as tk
|
||||||
|
from src.utils import clear_frame
|
||||||
|
from database.db_events import get_dogs, update_user_dog
|
||||||
|
|
||||||
|
|
||||||
|
def shop_ui(root, user_id):
|
||||||
|
"""Интерфейс магазина."""
|
||||||
|
clear_frame(root)
|
||||||
|
|
||||||
|
frame = tk.Frame(root, bg="#e5e5e5")
|
||||||
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
tk.Label(frame, text="Магазин", font=("Comic Sans MS", 30), bg="#e5e5e5").pack(pady=20)
|
||||||
|
|
||||||
|
dogs = get_dogs() # Получить список собак из базы данных
|
||||||
|
for dog in dogs:
|
||||||
|
dog_frame = tk.Frame(frame, bg="#f8f8f8", bd=2, relief=tk.RIDGE)
|
||||||
|
dog_frame.pack(pady=5, padx=10, fill=tk.X)
|
||||||
|
|
||||||
|
tk.Label(dog_frame, text=dog.breed, font=("Comic Sans MS", 20), bg="#f8f8f8").pack(side=tk.LEFT, padx=10)
|
||||||
|
tk.Button(dog_frame, text="Купить", command=lambda d=dog: update_user_dog(user_id, d.dog_id)).pack(
|
||||||
|
side=tk.RIGHT, padx=10)
|
||||||
|
|
||||||
|
tk.Button(frame, text="Назад", command=lambda: clear_frame(root), font=("Comic Sans MS", 20)).pack(pady=20)
|
||||||
BIN
src/user_functions/__pycache__/game_functions.cpython-313.pyc
Normal file
BIN
src/user_functions/__pycache__/map_generator.cpython-313.pyc
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import time
|
||||||
|
import tkinter as tk
|
||||||
|
from src.utils import clear_frame
|
||||||
|
from database.db_events import save_progress
|
||||||
|
|
||||||
|
|
||||||
|
def start_game(root, user_id, dog_id):
|
||||||
|
"""Игровой процесс."""
|
||||||
|
clear_frame(root)
|
||||||
|
|
||||||
|
# Обратный отсчет
|
||||||
|
for i in range(3, 0, -1):
|
||||||
|
clear_frame(root)
|
||||||
|
tk.Label(root, text=f"{i}...", font=("Comic Sans MS", 30)).pack(expand=True)
|
||||||
|
root.update()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# Начало уровня
|
||||||
|
# Здесь подключается логика работы с картой и вопросами
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def handle_obstacle(obstacle, current_score, root):
|
||||||
|
"""
|
||||||
|
Обработка препятствия (вопроса) с использованием окна.
|
||||||
|
Возвращает новый счёт игрока.
|
||||||
|
"""
|
||||||
|
result = {"new_score": current_score}
|
||||||
|
|
||||||
|
def submit_answer():
|
||||||
|
user_answer = answer_var.get().strip().lower()
|
||||||
|
if user_answer == "правильно": # Условие для правильного ответа
|
||||||
|
result["new_score"] += 1
|
||||||
|
else:
|
||||||
|
result["new_score"] -= 1
|
||||||
|
question_window.destroy() # Закрываем окно вопроса
|
||||||
|
|
||||||
|
# Создаём новое окно для вопроса
|
||||||
|
question_window = tk.Toplevel(root)
|
||||||
|
question_window.title("Вопрос")
|
||||||
|
question_window.geometry("400x200")
|
||||||
|
|
||||||
|
# Отображение текста вопроса
|
||||||
|
tk.Label(question_window, text=f"Вопрос сложности {obstacle['difficulty']}:", font=("Arial", 14)).pack(pady=10)
|
||||||
|
|
||||||
|
# Поле ввода ответа
|
||||||
|
answer_var = tk.StringVar()
|
||||||
|
tk.Entry(question_window, textvariable=answer_var, font=("Arial", 12)).pack(pady=10)
|
||||||
|
|
||||||
|
# Кнопка подтверждения ответа
|
||||||
|
tk.Button(question_window, text="Ответить", command=submit_answer).pack(pady=10)
|
||||||
|
|
||||||
|
# Ожидаем закрытия окна
|
||||||
|
question_window.grab_set() # Блокируем основное окно
|
||||||
|
root.wait_window(question_window) # Ждём завершения окна вопроса
|
||||||
|
|
||||||
|
return result
|
||||||
13
src/user_functions/map_generator.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
def generate_map(level):
|
||||||
|
"""Генерация карты уровня."""
|
||||||
|
num_obstacles = random.randint(3, 6)
|
||||||
|
map_data = []
|
||||||
|
for i in range(num_obstacles):
|
||||||
|
map_data.append({
|
||||||
|
"type": "question",
|
||||||
|
"difficulty": level,
|
||||||
|
"position": random.randint(1, 100)
|
||||||
|
})
|
||||||
|
return map_data
|
||||||
22
src/utils.py
|
|
@ -1,4 +1,6 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from tkinter import messagebox
|
||||||
|
|
||||||
|
|
||||||
def clear_frame(frame):
|
def clear_frame(frame):
|
||||||
"""Удаление всех виджетов из фрейма."""
|
"""Удаление всех виджетов из фрейма."""
|
||||||
|
|
@ -16,16 +18,10 @@ def feature_in_development(frame):
|
||||||
font=("Comic Sans MS", 16)
|
font=("Comic Sans MS", 16)
|
||||||
).pack(expand=True)
|
).pack(expand=True)
|
||||||
|
|
||||||
def create_tooltip(widget, text):
|
def show_message(message):
|
||||||
"""Создание подсказки для виджета."""
|
"""Показать сообщение пользователю"""
|
||||||
tooltip = tk.Toplevel()
|
message_window = tk.Toplevel()
|
||||||
tooltip.wm_overrideredirect(True) # Отключаем рамки окна
|
message_label = tk.Label(message_window, text=message, font=("Comic Sans MS", 16))
|
||||||
tooltip.wm_geometry(f"+{widget.winfo_rootx() + 20}+{widget.winfo_rooty() + 20}")
|
message_label.pack(pady=20)
|
||||||
label = tk.Label(tooltip, text=text, bg="#333", fg="#fff", font=("Comic Sans MS", 10), padx=5, pady=5)
|
ok_button = tk.Button(message_window, text="OK", command=message_window.destroy)
|
||||||
label.pack()
|
ok_button.pack(pady=10)
|
||||||
|
|
||||||
def hide_tooltip(event):
|
|
||||||
tooltip.destroy()
|
|
||||||
|
|
||||||
widget.bind("<Enter>", lambda event: tooltip.deiconify())
|
|
||||||
widget.bind("<Leave>", hide_tooltip)
|
|
||||||