Изменён пользовательский интерфейс main_menu.py, game_ui.py. Настроен вызов функций для запуска игрового процесса: после нажатия кнопки 'играть' открывается выбор собаки, а затем выбор уровня. Обновлена структура базы данных. Удалены не нужные файлы для проекта.

This commit is contained in:
Xatiko 2024-11-26 23:02:04 +03:00
parent 989a9056e7
commit c08cf51998
46 changed files with 804 additions and 111 deletions

View file

@ -1,3 +1,7 @@
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from tkinter import Tk, messagebox
from src.ui.auth_ui import DogAcademyApp # Путь к приложению
from database.db_session import init_db, close_sessions # Функция для закрытия сессий

View file

@ -219,4 +219,4 @@ class DogAcademyApp:
def show_user_dashboard(self):
self.clear_frame()
"""Перейти к главному меню пользователя после авторизации."""
UserApp(self.root, self)
UserApp(self.root)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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)

View file

@ -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)

View file

@ -1,78 +1,167 @@
import tkinter as tk
from config import (
BACKGROUND_COLOR_USER,
TOP_PANEL_COLOR_USER,
BUTTON_COLOR_PROFILE_USER,
BUTTON_COLOR_PLAY_USER,
BUTTON_COLOR_EXIT_USER,
BUTTON_TEXT_COLOR_USER,
FONT_USER,
BIG_FONT_USER,
BUTTON_RADIUS_USER,
EXIT_BUTTON_SIZE_USER,
)
from tkinter import Canvas
from PIL import Image, ImageTk
import math
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.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
# Пути к изображениям собак
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:
def __init__(self, root, auth_ui):
def __init__(self, root, user_id=None):
self.root = root
self.auth_ui = auth_ui
self.root.configure(bg=BACKGROUND_COLOR_USER)
self.root.geometry("1920x1080") # Разрешение окна
self.user_id = user_id
self.root.configure(bg=BACKGROUND_COLOR)
self.root.geometry("1920x1080")
self.root.title("Собачья академия")
print("Главное меню активно") # Лог при открытии меню
self.show_user_dashboard()
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)
# Кнопки на верхней панели
for text, command in [("Профиль", self.show_profile), ("Магазин", self.show_shop), ("База знаний", self.show_knowledge)]:
button = tk.Button(
top_panel,
text=text,
bg=BUTTON_COLOR_PROFILE_USER,
fg=BUTTON_TEXT_COLOR_USER,
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,
profile_button = tk.Button(
top_panel,
text="Профиль",
bg="#555555",
fg="white",
font=FONT,
relief=tk.FLAT,
height=2,
width=10,
command=self.play_game,
padx=20,
pady=10,
command=self.show_profile
)
play_button.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
profile_button.pack(side=tk.LEFT, padx=20)
# Кнопка "Выход" в правом нижнем углу
exit_button = tk.Button(
self.root,
text="Выход",
bg=BUTTON_COLOR_EXIT_USER,
fg=BUTTON_TEXT_COLOR_USER,
font=FONT_USER,
width=EXIT_BUTTON_SIZE_USER[0] // 10,
height=EXIT_BUTTON_SIZE_USER[1] // 10,
command=self.exit_app,
shop_button = tk.Button(
top_panel,
text="Магазин",
bg="#555555",
fg="white",
font=FONT,
relief=tk.FLAT,
padx=20,
pady=10,
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):
"""Заглушка для игры."""
"""Переход к игровому интерфейсу."""
clear_frame(self.root) # Очищаем главное меню
GameUI(self.root, self.user_id) # Открываем игровой интерфейс
print("Запуск игры...")
def exit_app(self):
@ -80,14 +169,9 @@ class UserApp:
print("Приложение закрыто")
self.root.quit()
def show_profile(self):
"""Заглушка для профиля."""
print("Переход в профиль...")
# Запуск главного окна
if __name__ == "__main__":
root = tk.Tk()
app = UserApp(root, user_id=123) # Передаем user_id (это может быть получено после авторизации)
root.mainloop()
def show_shop(self):
"""Заглушка для магазина."""
print("Переход в магазин...")
def show_knowledge(self):
"""Заглушка для базы знаний."""
print("Переход в базу знаний...")

View file

@ -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)

View file

@ -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)

View 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

View 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

View file

@ -1,4 +1,6 @@
import tkinter as tk
from tkinter import messagebox
def clear_frame(frame):
"""Удаление всех виджетов из фрейма."""
@ -16,16 +18,10 @@ def feature_in_development(frame):
font=("Comic Sans MS", 16)
).pack(expand=True)
def create_tooltip(widget, text):
"""Создание подсказки для виджета."""
tooltip = tk.Toplevel()
tooltip.wm_overrideredirect(True) # Отключаем рамки окна
tooltip.wm_geometry(f"+{widget.winfo_rootx() + 20}+{widget.winfo_rooty() + 20}")
label = tk.Label(tooltip, text=text, bg="#333", fg="#fff", font=("Comic Sans MS", 10), padx=5, pady=5)
label.pack()
def hide_tooltip(event):
tooltip.destroy()
widget.bind("<Enter>", lambda event: tooltip.deiconify())
widget.bind("<Leave>", hide_tooltip)
def show_message(message):
"""Показать сообщение пользователю"""
message_window = tk.Toplevel()
message_label = tk.Label(message_window, text=message, font=("Comic Sans MS", 16))
message_label.pack(pady=20)
ok_button = tk.Button(message_window, text="OK", command=message_window.destroy)
ok_button.pack(pady=10)