Разработка программного модуля информационной системы «Игра «Собачья академия» #3
20 changed files with 3093 additions and 157 deletions
Binary file not shown.
|
|
@ -95,13 +95,12 @@ def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
def get_user_progress(user_id):
|
def get_user_progress(user_id):
|
||||||
"""Получение прогресса пользователя по его ID."""
|
"""Получение игрового прогресса пользователя."""
|
||||||
session = get_session()
|
session = get_session()
|
||||||
try:
|
try:
|
||||||
progress = session.query(GameSession).filter_by(user_id=user_id).all()
|
return session.query(GameSession).filter_by(user_id=user_id).all()
|
||||||
return progress
|
except Exception as e:
|
||||||
except SQLAlchemyError as e:
|
print(f"Ошибка при получении прогресса пользователя: {e}")
|
||||||
print(f"Ошибка при получении прогресса: {e}")
|
|
||||||
return []
|
return []
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
session.close()
|
||||||
|
|
|
||||||
67
database/info/Dogs_table.py
Normal file
67
database/info/Dogs_table.py
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
from database.db_session import get_session
|
||||||
|
from database.models import Dogs
|
||||||
|
|
||||||
|
DOG_CHARACTERS = {
|
||||||
|
"Chihuahua": {
|
||||||
|
"characteristics": "Скорость: 8, Выносливость: 5, Умение: Быстрое уклонение.",
|
||||||
|
"behavior": "Энергичный, часто лайливый.",
|
||||||
|
"care_info": "Нуждается в регулярной чистке зубов и когтей.",
|
||||||
|
"admin_comments": "Идеален для активных владельцев."
|
||||||
|
},
|
||||||
|
"Corgi": {
|
||||||
|
"characteristics": "Скорость: 6, Выносливость: 7, Умение: Дополнительный прыжок.",
|
||||||
|
"behavior": "Дружелюбный, легко обучаемый.",
|
||||||
|
"care_info": "Важно контролировать вес из-за коротких лап.",
|
||||||
|
"admin_comments": "Подходит для семей с детьми."
|
||||||
|
},
|
||||||
|
"Golden Retriever": {
|
||||||
|
"characteristics": "Скорость: 7, Выносливость: 8, Умение: Увеличенные очки за правильные ответы.",
|
||||||
|
"behavior": "Очень умный и добрый.",
|
||||||
|
"care_info": "Требует регулярной чистки шерсти.",
|
||||||
|
"admin_comments": "Идеален для владельцев, ищущих верного друга."
|
||||||
|
},
|
||||||
|
"Husky": {
|
||||||
|
"characteristics": "Скорость: 9, Выносливость: 6, Умение: Ускорение.",
|
||||||
|
"behavior": "Независимый, требует много активности.",
|
||||||
|
"care_info": "Плохо переносит жару, требует частых прогулок.",
|
||||||
|
"admin_comments": "Для опытных владельцев."
|
||||||
|
},
|
||||||
|
"Pomeranian": {
|
||||||
|
"characteristics": "Скорость: 7, Выносливость: 4, Умение: Уменьшение штрафа за ошибки.",
|
||||||
|
"behavior": "Веселый, преданный.",
|
||||||
|
"care_info": "Шерсть требует ежедневного ухода.",
|
||||||
|
"admin_comments": "Идеален для жизни в квартире."
|
||||||
|
},
|
||||||
|
"Pug": {
|
||||||
|
"characteristics": "Скорость: 5, Выносливость: 9, Умение: Сохраняет здоровье при столкновениях.",
|
||||||
|
"behavior": "Ласковый, склонен к перееданию.",
|
||||||
|
"care_info": "Внимание к дыханию и физической активности.",
|
||||||
|
"admin_comments": "Для спокойного образа жизни."
|
||||||
|
},
|
||||||
|
"Yorkshire Terrier": {
|
||||||
|
"characteristics": "Скорость: 6, Выносливость: 5, Умение: Быстрое восстановление характеристик.",
|
||||||
|
"behavior": "Компактный, умный.",
|
||||||
|
"care_info": "Требует профессиональной стрижки.",
|
||||||
|
"admin_comments": "Подходит для маленьких пространств."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def populate_dogs():
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
for breed, data in DOG_CHARACTERS.items():
|
||||||
|
dog = Dogs(
|
||||||
|
breed=breed,
|
||||||
|
characteristics=data['characteristics'],
|
||||||
|
behavior=data['behavior'],
|
||||||
|
care_info=data['care_info'],
|
||||||
|
admin_comments=data['admin_comments']
|
||||||
|
)
|
||||||
|
session.add(dog)
|
||||||
|
session.commit()
|
||||||
|
print("Таблица Dogs успешно заполнена.")
|
||||||
|
except Exception as e:
|
||||||
|
session.rollback()
|
||||||
|
print(f"Ошибка при заполнении Dogs: {e}")
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
34
database/info/GameSessions_table.py
Normal file
34
database/info/GameSessions_table.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
from database.db_events import get_user_progress
|
||||||
|
from database.db_session import get_session
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
from database.models import GameSession
|
||||||
|
|
||||||
|
|
||||||
|
def save_game_session(user_id, level, score, duration, health, hunger, sleepiness):
|
||||||
|
"""Сохранение игрового процесса в таблицу GameSessions."""
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
# Создаем новый объект GameSession
|
||||||
|
game_session = GameSession(
|
||||||
|
user_id=user_id,
|
||||||
|
level=level,
|
||||||
|
score=score,
|
||||||
|
duration=duration,
|
||||||
|
health=health,
|
||||||
|
hunger=hunger,
|
||||||
|
sleepiness=sleepiness,
|
||||||
|
)
|
||||||
|
session.add(game_session)
|
||||||
|
session.commit() # Сохраняем данные в таблице
|
||||||
|
print(f"Игровой процесс для пользователя {user_id} на уровне {level} успешно сохранен.")
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
session.rollback()
|
||||||
|
print(f"Ошибка при сохранении игрового процесса: {e}")
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def print_user_progress(user_id):
|
||||||
|
"""Печать прогресса пользователя из таблицы GameSessions."""
|
||||||
|
progress = get_user_progress(user_id)
|
||||||
|
for session in progress:
|
||||||
|
print(f"Уровень: {session.level}, Очки: {session.score}, Время: {session.duration} секунд")
|
||||||
99
database/info/Questions_table.py
Normal file
99
database/info/Questions_table.py
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
from database.db_session import get_session
|
||||||
|
from database.models import Dogs, Questions
|
||||||
|
|
||||||
|
DOG_QUESTIONS = {
|
||||||
|
"Chihuahua": [
|
||||||
|
{
|
||||||
|
"question_text": "Почему у Чихуахуа часто возникают проблемы с зубами?",
|
||||||
|
"helpful_info": "Миниатюрный размер приводит к скоплению налета и зубных отложений.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Какая активность лучше всего подходит для Чихуахуа?",
|
||||||
|
"helpful_info": "Легкие прогулки и домашние игры.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Corgi": [
|
||||||
|
{
|
||||||
|
"question_text": "Почему важно контролировать вес Корги?",
|
||||||
|
"helpful_info": "Избыточный вес может негативно повлиять на суставы.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Как можно поддерживать здоровье суставов у Корги?",
|
||||||
|
"helpful_info": "Обеспечьте умеренную активность и сбалансированное питание.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Golden Retriever": [
|
||||||
|
{
|
||||||
|
"question_text": "Почему важно регулярно вычесывать шерсть Голден Ретривера?",
|
||||||
|
"helpful_info": "Это предотвращает образование колтунов.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Какое питание подходит для Голден Ретриверов?",
|
||||||
|
"helpful_info": "Сбалансированное питание с учетом активности и возраста.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Husky": [
|
||||||
|
{
|
||||||
|
"question_text": "Какой климат подходит для Хаски?",
|
||||||
|
"helpful_info": "Они комфортнее чувствуют себя в холодном климате.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Почему Хаски требуют много физической активности?",
|
||||||
|
"helpful_info": "Эта порода обладает высокой энергией и выносливостью.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Pomeranian": [
|
||||||
|
{
|
||||||
|
"question_text": "Как правильно ухаживать за шерстью Померанского шпица?",
|
||||||
|
"helpful_info": "Ежедневно расчесывать шерсть, чтобы избежать колтунов.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Почему важно следить за зубами Померанского шпица?",
|
||||||
|
"helpful_info": "Они склонны к зубному налету, что может привести к проблемам.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Pug": [
|
||||||
|
{
|
||||||
|
"question_text": "Почему мопсы склонны к ожирению?",
|
||||||
|
"helpful_info": "Их низкая активность и любовь к еде требуют контроля рациона.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Какие проблемы с дыханием могут возникнуть у мопсов?",
|
||||||
|
"helpful_info": "Из-за их плоской морды дыхание может быть затруднено.",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Yorkshire Terrier": [
|
||||||
|
{
|
||||||
|
"question_text": "Как часто нужно стричь шерсть Йоркширского терьера?",
|
||||||
|
"helpful_info": "Примерно раз в 4-6 недель для поддержания аккуратного вида.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question_text": "Как ухаживать за шерстью Йоркширского терьера?",
|
||||||
|
"helpful_info": "Регулярно расчесывать и использовать специальные средства.",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def populate_questions():
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
dogs = {dog.breed: dog.dog_id for dog in session.query(Dogs).all()}
|
||||||
|
for breed, questions in DOG_QUESTIONS.items():
|
||||||
|
dog_id = dogs.get(breed)
|
||||||
|
if not dog_id:
|
||||||
|
print(f"Порода '{breed}' отсутствует.")
|
||||||
|
continue
|
||||||
|
for question_data in questions:
|
||||||
|
question = Questions(
|
||||||
|
dog_id=dog_id,
|
||||||
|
question_text=question_data["question_text"],
|
||||||
|
helpful_info=question_data["helpful_info"]
|
||||||
|
)
|
||||||
|
session.add(question)
|
||||||
|
session.commit()
|
||||||
|
print("Таблица Questions успешно заполнена.")
|
||||||
|
except Exception as e:
|
||||||
|
session.rollback()
|
||||||
|
print(f"Ошибка при заполнении Questions: {e}")
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
0
database/info/__init__.py
Normal file
0
database/info/__init__.py
Normal file
2733
logs/logfile.log
2733
logs/logfile.log
File diff suppressed because it is too large
Load diff
39
src/tests/database_test.py
Normal file
39
src/tests/database_test.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
from database.db_session import get_session, init_db
|
||||||
|
from database.info.Dogs_table import populate_dogs
|
||||||
|
from database.info.Questions_table import populate_questions
|
||||||
|
from database.models import Dogs, Questions
|
||||||
|
|
||||||
|
|
||||||
|
def test_data_integrity():
|
||||||
|
session = get_session()
|
||||||
|
try:
|
||||||
|
# Проверяем, есть ли собаки
|
||||||
|
dogs = session.query(Dogs).all()
|
||||||
|
assert len(dogs) > 0, "Таблица Dogs пуста!"
|
||||||
|
|
||||||
|
# Проверяем, есть ли вопросы
|
||||||
|
questions = session.query(Questions).all()
|
||||||
|
assert len(questions) > 0, "Таблица Questions пуста!"
|
||||||
|
|
||||||
|
# Проверяем связь вопросов с породами
|
||||||
|
for question in questions:
|
||||||
|
assert question.dog_id is not None, f"У вопроса {question.question_id} отсутствует dog_id"
|
||||||
|
dog = session.query(Dogs).filter_by(dog_id=question.dog_id).first()
|
||||||
|
assert dog is not None, f"Ссылка на несуществующую собаку в вопросе {question.question_id}"
|
||||||
|
|
||||||
|
print("Все тесты успешно пройдены.")
|
||||||
|
except AssertionError as e:
|
||||||
|
print(f"Ошибка теста: {e}")
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Инициализируем базу данных (пересоздаём таблицы для чистого теста)
|
||||||
|
init_db(refresh=True)
|
||||||
|
|
||||||
|
# Заполняем таблицы
|
||||||
|
populate_dogs()
|
||||||
|
populate_questions()
|
||||||
|
|
||||||
|
# Запускаем тесты
|
||||||
|
test_data_integrity()
|
||||||
|
|
@ -7,7 +7,7 @@ from config import SETTINGS_IMG
|
||||||
from database.db_session import get_session
|
from database.db_session import get_session
|
||||||
from database.models import Dogs, Questions, Users
|
from database.models import Dogs, Questions, Users
|
||||||
from src.admin_functions import admin_logging, statistics
|
from src.admin_functions import admin_logging, statistics
|
||||||
from src.utils import clear_frame, feature_in_development # Импортируем общую функцию для очистки фрейма
|
from src.utils import clear_frame, feature_in_development_admin # Импортируем общую функцию для очистки фрейма
|
||||||
from database.db_events import check_user, get_all_users, get_all_questions, get_all_dogs
|
from database.db_events import check_user, get_all_users, get_all_questions, get_all_dogs
|
||||||
|
|
||||||
# Конфигурация цветов из config.py
|
# Конфигурация цветов из config.py
|
||||||
|
|
@ -99,18 +99,18 @@ class AdminApp:
|
||||||
("Просмотр таблиц", self.view_tables),
|
("Просмотр таблиц", self.view_tables),
|
||||||
]),
|
]),
|
||||||
("Управление игровым контентом", [
|
("Управление игровым контентом", [
|
||||||
("Создание и настройка уровней", feature_in_development),
|
("Создание и настройка уровней", feature_in_development_admin),
|
||||||
("Настройка параметров собаки", feature_in_development),
|
("Настройка параметров собаки", feature_in_development_admin),
|
||||||
]),
|
]),
|
||||||
("Управление интерфейсом пользователя", [
|
("Управление интерфейсом пользователя", [
|
||||||
("Добавление подсказок в интерфейс", feature_in_development),
|
("Добавление подсказок в интерфейс", feature_in_development_admin),
|
||||||
]),
|
]),
|
||||||
("Работа с базой знаний", [
|
("Работа с базой знаний", [
|
||||||
("Добавление информации", feature_in_development),
|
("Добавление информации", feature_in_development_admin),
|
||||||
("Редактирование записей", feature_in_development),
|
("Редактирование записей", feature_in_development_admin),
|
||||||
("Удаление записей", feature_in_development),
|
("Удаление записей", feature_in_development_admin),
|
||||||
("Просмотр базы знаний", feature_in_development),
|
("Просмотр базы знаний", feature_in_development_admin),
|
||||||
("Генерация вопросов", feature_in_development),
|
("Генерация вопросов", feature_in_development_admin),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,17 @@ class DogAcademyApp:
|
||||||
self.reg_password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
|
self.reg_password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
|
||||||
self.reg_password_entry.pack(pady=10)
|
self.reg_password_entry.pack(pady=10)
|
||||||
|
|
||||||
|
# Кнопка "Показать пароль"
|
||||||
|
show_password_button = tk.Button(
|
||||||
|
self.current_frame,
|
||||||
|
text="Показать пароль",
|
||||||
|
bg=BUTTON_COLOR,
|
||||||
|
fg=BUTTON_TEXT_COLOR,
|
||||||
|
font=FONT,
|
||||||
|
command=self.toggle_registration_password,
|
||||||
|
)
|
||||||
|
show_password_button.pack(pady=10)
|
||||||
|
|
||||||
# Никнейм
|
# Никнейм
|
||||||
username_label = tk.Label(self.current_frame, text="Никнейм:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
|
username_label = tk.Label(self.current_frame, text="Никнейм:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
|
||||||
username_label.pack()
|
username_label.pack()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import random
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from database.db_events import get_user_by_id
|
from database.db_events import get_user_by_id
|
||||||
|
from database.info.GameSessions_table import save_game_session
|
||||||
from src.user_functions.game_logs import setup_logging
|
from src.user_functions.game_logs import setup_logging
|
||||||
from config import DOG_CHARACTERS, DONE, BONE, BACKGROUND_GAME
|
from config import DOG_CHARACTERS, DONE, BONE, BACKGROUND_GAME
|
||||||
from src.utils import clear_frame
|
from src.utils import clear_frame
|
||||||
|
|
@ -41,6 +42,11 @@ class GameUI:
|
||||||
self.root.geometry("1920x1080")
|
self.root.geometry("1920x1080")
|
||||||
self.root.configure(bg="#E5E5E5")
|
self.root.configure(bg="#E5E5E5")
|
||||||
|
|
||||||
|
# Флаги
|
||||||
|
self.is_pause_menu_open = False
|
||||||
|
self.is_victory_screen_open = False
|
||||||
|
self.is_game_active = False # Для контроля состояния игры
|
||||||
|
|
||||||
# Привязка клавиш
|
# Привязка клавиш
|
||||||
self.root.bind("<KeyPress-w>", self.move_up)
|
self.root.bind("<KeyPress-w>", self.move_up)
|
||||||
self.root.bind("<KeyPress-s>", self.move_down)
|
self.root.bind("<KeyPress-s>", self.move_down)
|
||||||
|
|
@ -248,20 +254,29 @@ class GameUI:
|
||||||
self.update_map()
|
self.update_map()
|
||||||
|
|
||||||
def on_escape(self, event):
|
def on_escape(self, event):
|
||||||
"""Обработчик для нажатия клавиши ESC."""
|
"""Обработчик для клавиши ESC."""
|
||||||
self.show_pause_menu()
|
if self.map_canvas: # Проверяем, что игрок находится на карте
|
||||||
|
if self.is_pause_menu_open:
|
||||||
|
self.resume_game() # Закрываем окно паузы и продолжаем игру
|
||||||
|
else:
|
||||||
|
self.show_pause_menu() # Открываем окно паузы
|
||||||
|
|
||||||
def show_pause_menu(self):
|
def show_pause_menu(self):
|
||||||
"""Создание окна паузы."""
|
"""Создание окна паузы."""
|
||||||
pause_window = tk.Toplevel(self.root)
|
if self.is_pause_menu_open:
|
||||||
pause_window.title("Пауза")
|
return # Если окно паузы уже открыто, ничего не делаем
|
||||||
pause_window.geometry("400x200")
|
|
||||||
pause_window.configure(bg="#E5E5E5")
|
self.is_pause_menu_open = True # Устанавливаем флаг
|
||||||
pause_window.grab_set() # Блокируем взаимодействие с основным окном
|
|
||||||
|
self.pause_window = tk.Toplevel(self.root)
|
||||||
|
self.pause_window.title("Пауза")
|
||||||
|
self.pause_window.geometry("400x200")
|
||||||
|
self.pause_window.configure(bg="#E5E5E5")
|
||||||
|
self.pause_window.grab_set() # Блокируем взаимодействие с основным окном
|
||||||
|
|
||||||
# Кнопка "Сохранить и выйти"
|
# Кнопка "Сохранить и выйти"
|
||||||
save_exit_button = tk.Button(
|
save_exit_button = tk.Button(
|
||||||
pause_window,
|
self.pause_window,
|
||||||
text="Сохранить и выйти",
|
text="Сохранить и выйти",
|
||||||
font=("Comic Sans MS", 16),
|
font=("Comic Sans MS", 16),
|
||||||
bg="#FF6347",
|
bg="#FF6347",
|
||||||
|
|
@ -271,41 +286,19 @@ class GameUI:
|
||||||
|
|
||||||
# Кнопка "Продолжить"
|
# Кнопка "Продолжить"
|
||||||
continue_button = tk.Button(
|
continue_button = tk.Button(
|
||||||
pause_window,
|
self.pause_window,
|
||||||
text="Продолжить",
|
text="Продолжить",
|
||||||
font=("Comic Sans MS", 16),
|
font=("Comic Sans MS", 16),
|
||||||
bg="#4CAF50",
|
bg="#4CAF50",
|
||||||
command=pause_window.destroy
|
command=self.resume_game
|
||||||
)
|
)
|
||||||
continue_button.pack(pady=20)
|
continue_button.pack(pady=20)
|
||||||
|
|
||||||
def show_pause_menu(self):
|
def resume_game(self):
|
||||||
"""Создание окна паузы."""
|
"""Закрытие окна паузы и продолжение игры."""
|
||||||
pause_window = tk.Toplevel(self.root)
|
if self.is_pause_menu_open:
|
||||||
pause_window.title("Пауза")
|
self.pause_window.destroy() # Закрываем окно паузы
|
||||||
pause_window.geometry("400x200")
|
self.is_pause_menu_open = False # Сбрасываем флаг
|
||||||
pause_window.configure(bg="#E5E5E5")
|
|
||||||
pause_window.grab_set() # Блокируем взаимодействие с основным окном
|
|
||||||
|
|
||||||
# Кнопка "Сохранить и выйти"
|
|
||||||
save_exit_button = tk.Button(
|
|
||||||
pause_window,
|
|
||||||
text="Сохранить и выйти",
|
|
||||||
font=("Comic Sans MS", 16),
|
|
||||||
bg="#FF6347",
|
|
||||||
command=self.save_and_exit # Этот метод теперь определён
|
|
||||||
)
|
|
||||||
save_exit_button.pack(pady=20)
|
|
||||||
|
|
||||||
# Кнопка "Продолжить"
|
|
||||||
continue_button = tk.Button(
|
|
||||||
pause_window,
|
|
||||||
text="Продолжить",
|
|
||||||
font=("Comic Sans MS", 16),
|
|
||||||
bg="#4CAF50",
|
|
||||||
command=pause_window.destroy
|
|
||||||
)
|
|
||||||
continue_button.pack(pady=20)
|
|
||||||
|
|
||||||
def save_and_exit(self):
|
def save_and_exit(self):
|
||||||
"""Сохранение данных и выход в главное меню."""
|
"""Сохранение данных и выход в главное меню."""
|
||||||
|
|
@ -317,6 +310,9 @@ class GameUI:
|
||||||
|
|
||||||
def update_map(self):
|
def update_map(self):
|
||||||
"""Обновление карты."""
|
"""Обновление карты."""
|
||||||
|
if self.is_victory_screen_open: # Отключаем обновления, если окно победы открыто
|
||||||
|
return
|
||||||
|
|
||||||
self.map_canvas.delete("all")
|
self.map_canvas.delete("all")
|
||||||
self.draw_grid()
|
self.draw_grid()
|
||||||
|
|
||||||
|
|
@ -343,16 +339,22 @@ class GameUI:
|
||||||
|
|
||||||
# Условие перехода на следующий уровень
|
# Условие перехода на следующий уровень
|
||||||
target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия
|
target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия
|
||||||
if self.total_bones >= target_bones:
|
if self.total_bones >= target_bones and not self.is_victory_screen_open:
|
||||||
self.show_victory_screen()
|
self.show_victory_screen()
|
||||||
|
|
||||||
def show_victory_screen(self):
|
def show_victory_screen(self):
|
||||||
"""Экран победы."""
|
"""Экран победы."""
|
||||||
|
if self.is_victory_screen_open: # Проверяем, чтобы не было второго окна
|
||||||
|
return
|
||||||
|
|
||||||
|
self.is_victory_screen_open = True # Устанавливаем флаг
|
||||||
|
self.is_game_active = False # Останавливаем движение
|
||||||
|
|
||||||
victory_window = tk.Toplevel(self.root)
|
victory_window = tk.Toplevel(self.root)
|
||||||
victory_window.title("Ура, победа!")
|
victory_window.title("Ура, победа!")
|
||||||
victory_window.geometry("800x600")
|
victory_window.geometry("800x600")
|
||||||
victory_window.configure(bg="#E5E5E5")
|
victory_window.configure(bg="#E5E5E5")
|
||||||
victory_window.grab_set()
|
victory_window.grab_set() # Блокируем взаимодействие с основным окном
|
||||||
|
|
||||||
# Изображение собаки
|
# Изображение собаки
|
||||||
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((200, 200), Image.Resampling.LANCZOS)
|
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((200, 200), Image.Resampling.LANCZOS)
|
||||||
|
|
@ -384,15 +386,32 @@ class GameUI:
|
||||||
|
|
||||||
# Кнопка перехода на следующий уровень
|
# Кнопка перехода на следующий уровень
|
||||||
next_level_button = tk.Button(
|
next_level_button = tk.Button(
|
||||||
victory_window, text="Следующий уровень", font=("Comic Sans MS", 16), bg="#4CAF50",
|
victory_window,
|
||||||
|
text="Следующий уровень",
|
||||||
|
font=("Comic Sans MS", 16),
|
||||||
|
bg="#4CAF50",
|
||||||
command=lambda: [victory_window.destroy(), self.start_next_level()]
|
command=lambda: [victory_window.destroy(), self.start_next_level()]
|
||||||
)
|
)
|
||||||
next_level_button.place(relx=0.5, rely=0.75, anchor=tk.CENTER)
|
next_level_button.place(relx=0.5, rely=0.65, anchor=tk.CENTER)
|
||||||
|
|
||||||
|
# Кнопка выхода в главное меню
|
||||||
|
exit_button = tk.Button(
|
||||||
|
victory_window,
|
||||||
|
text="Выйти в главное меню",
|
||||||
|
font=("Comic Sans MS", 16),
|
||||||
|
bg="#FF6347",
|
||||||
|
command=lambda: [victory_window.destroy(), self.return_to_main_menu()]
|
||||||
|
)
|
||||||
|
exit_button.place(relx=0.5, rely=0.8, anchor=tk.CENTER)
|
||||||
|
|
||||||
|
def return_to_main_menu(self):
|
||||||
|
"""Возврат в главное меню."""
|
||||||
|
self.is_victory_screen_open = False # Сбрасываем флаг окна победы
|
||||||
|
self.return_to_main_menu_callback() # Вызываем колбэк для возврата
|
||||||
|
|
||||||
def start_next_level(self):
|
def start_next_level(self):
|
||||||
"""Переход на следующий уровень и сохранение прогресса."""
|
"""Переход на следующий уровень."""
|
||||||
# Сохранение прогресса
|
self.save_progress() # Сохраняем прогресс перед переходом на следующий уровень
|
||||||
self.save_progress()
|
|
||||||
|
|
||||||
# Переход на следующий уровень
|
# Переход на следующий уровень
|
||||||
self.current_level += 1
|
self.current_level += 1
|
||||||
|
|
@ -400,19 +419,14 @@ class GameUI:
|
||||||
self.start_level(self.current_level)
|
self.start_level(self.current_level)
|
||||||
|
|
||||||
def save_progress(self):
|
def save_progress(self):
|
||||||
"""Сохранение прогресса в базе данных."""
|
"""Сохранение игрового процесса в таблицу GameSessions."""
|
||||||
from database.db_events import save_progress, update_user_dog
|
from datetime import datetime
|
||||||
from database.db_events import get_user_by_id
|
|
||||||
|
|
||||||
# Получаем информацию о пользователе
|
# Получаем время начала и окончания уровня
|
||||||
user = get_user_by_id(self.user_id)
|
duration = self.steps_taken # Время можно рассчитать по шагам или в реальном времени
|
||||||
if not user:
|
score = self.total_bones # Количество собранных косточек
|
||||||
logging.error(f"Пользователь с ID {self.user_id} не найден в базе данных.")
|
|
||||||
return # Прерываем выполнение, если пользователь не найден
|
|
||||||
|
|
||||||
# Сохраняем прогресс текущего уровня
|
# Сохранение прогресса в базу данных
|
||||||
save_progress(self.user_id, self.current_level, self.total_bones, 0, 100, 0, 0)
|
save_game_session(self.user_id, self.current_level, score, duration, 100, 0, 0)
|
||||||
|
|
||||||
# Получаем уровень и собаку
|
# Также можно сохранять дополнительные параметры, если необходимо (например, здоровье, голод, усталость)
|
||||||
dog_id = user.dog_id # Получаем id собаки пользователя
|
|
||||||
update_user_dog(self.user_id, dog_id) # Сохраняем собаку в профиль
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
@ -8,8 +8,6 @@ import math
|
||||||
from config import EXIT_BUTTON_WIDTH, EXIT_BUTTON_HEIGHT, BUTTON_COLOR_EXIT
|
from config import EXIT_BUTTON_WIDTH, EXIT_BUTTON_HEIGHT, BUTTON_COLOR_EXIT
|
||||||
from src.ui.user_ui.game_ui import GameUI
|
from src.ui.user_ui.game_ui import GameUI
|
||||||
from src.ui.user_ui.profile_ui import profile_ui
|
from src.ui.user_ui.profile_ui import profile_ui
|
||||||
from src.ui.user_ui.shop_ui import shop_ui
|
|
||||||
from src.ui.user_ui.knowledge_ui import knowledge_ui
|
|
||||||
from src.utils import clear_frame
|
from src.utils import clear_frame
|
||||||
|
|
||||||
# Пути к изображениям собак
|
# Пути к изображениям собак
|
||||||
|
|
@ -74,7 +72,7 @@ class UserApp:
|
||||||
relief=tk.FLAT,
|
relief=tk.FLAT,
|
||||||
padx=20,
|
padx=20,
|
||||||
pady=10,
|
pady=10,
|
||||||
command=self.show_shop
|
state=tk.DISABLED # Делаем кнопку некликабельной
|
||||||
)
|
)
|
||||||
shop_button.pack(side=tk.LEFT, padx=20)
|
shop_button.pack(side=tk.LEFT, padx=20)
|
||||||
|
|
||||||
|
|
@ -87,7 +85,7 @@ class UserApp:
|
||||||
relief=tk.FLAT,
|
relief=tk.FLAT,
|
||||||
padx=20,
|
padx=20,
|
||||||
pady=10,
|
pady=10,
|
||||||
command=self.show_knowledge
|
state=tk.DISABLED # Делаем кнопку некликабельной
|
||||||
)
|
)
|
||||||
knowledge_button.pack(side=tk.LEFT, padx=20)
|
knowledge_button.pack(side=tk.LEFT, padx=20)
|
||||||
|
|
||||||
|
|
@ -154,17 +152,7 @@ class UserApp:
|
||||||
def show_profile(self):
|
def show_profile(self):
|
||||||
"""Показать экран профиля пользователя."""
|
"""Показать экран профиля пользователя."""
|
||||||
self.clear_frame()
|
self.clear_frame()
|
||||||
profile_ui(self.root, self.user_id) # Передаем user_id в profile_ui
|
profile_ui(self.root, self.user_id, self) # Передаем сам объект self для доступа к show_user_dashboard
|
||||||
|
|
||||||
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):
|
def clear_frame(self):
|
||||||
"""Очистить текущий экран."""
|
"""Очистить текущий экран."""
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from src.utils import clear_frame
|
||||||
from database.db_events import get_user_progress
|
from database.db_events import get_user_progress
|
||||||
|
|
||||||
|
|
||||||
def profile_ui(root, user_id):
|
def profile_ui(root, user_id, user_app):
|
||||||
"""Интерфейс профиля пользователя."""
|
"""Интерфейс профиля пользователя."""
|
||||||
clear_frame(root)
|
clear_frame(root)
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ def profile_ui(root, user_id):
|
||||||
|
|
||||||
tk.Label(frame, text="Профиль", font=("Comic Sans MS", 30), bg="#f8e1e1").pack(pady=20)
|
tk.Label(frame, text="Профиль", font=("Comic Sans MS", 30), bg="#f8e1e1").pack(pady=20)
|
||||||
|
|
||||||
# Статистика пользователя
|
# Получение прогресса пользователя из базы данных
|
||||||
progress = get_user_progress(user_id)
|
progress = get_user_progress(user_id)
|
||||||
levels_completed = len(progress) # Считаем количество уровней
|
levels_completed = len(progress) # Считаем количество уровней
|
||||||
bones_collected = sum([session.score for session in progress]) # Суммируем все собранные косточки
|
bones_collected = sum([session.score for session in progress]) # Суммируем все собранные косточки
|
||||||
|
|
@ -20,4 +20,12 @@ def profile_ui(root, user_id):
|
||||||
stats_text = f"Пройдено уровней: {levels_completed}\nСобрано косточек: {bones_collected}"
|
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.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)
|
# Кнопка "Назад"
|
||||||
|
back_button = tk.Button(
|
||||||
|
frame,
|
||||||
|
text="Назад",
|
||||||
|
command=lambda: [clear_frame(root), user_app.show_user_dashboard()], # Очистить экран и вернуться на главное меню
|
||||||
|
font=("Comic Sans MS", 20)
|
||||||
|
)
|
||||||
|
back_button.pack(pady=20)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
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)
|
|
||||||
|
|
@ -2,11 +2,12 @@ import tkinter as tk
|
||||||
|
|
||||||
|
|
||||||
def clear_frame(frame):
|
def clear_frame(frame):
|
||||||
"""Удаление всех виджетов из фрейма."""
|
"""Очистить все виджеты в frame"""
|
||||||
for widget in frame.winfo_children():
|
for widget in frame.winfo_children():
|
||||||
widget.destroy()
|
widget.destroy()
|
||||||
|
|
||||||
def feature_in_development(frame):
|
|
||||||
|
def feature_in_development_admin(frame):
|
||||||
"""Сообщение о том, что функционал недоступен."""
|
"""Сообщение о том, что функционал недоступен."""
|
||||||
clear_frame(frame) # Очистка фрейма перед выводом сообщения
|
clear_frame(frame) # Очистка фрейма перед выводом сообщения
|
||||||
tk.Label(
|
tk.Label(
|
||||||
|
|
@ -17,6 +18,7 @@ def feature_in_development(frame):
|
||||||
font=("Comic Sans MS", 16)
|
font=("Comic Sans MS", 16)
|
||||||
).pack(expand=True)
|
).pack(expand=True)
|
||||||
|
|
||||||
|
|
||||||
def show_message(message):
|
def show_message(message):
|
||||||
"""Показать сообщение пользователю"""
|
"""Показать сообщение пользователю"""
|
||||||
message_window = tk.Toplevel()
|
message_window = tk.Toplevel()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue