Как изменить код, при помощи другого кода?

Malchik_molodoi

Новичок
Пользователь
Июл 29, 2020
19
4
3
20
Здравствуйте, делаю игру на PyGame и хочу добавить в неё настройки.
В коде игры фигурирует переменная Immortality, которая не дает игроку проиграть. Вот код:
Python:
import pygame
from config import Immortality #это python файл, содержащий переменную Immortality

#код

if Immortality:                #Если игрок бессмертный
    pass                       #Ничего не произойдет
if not Immortality:            #Иначе
    player.lives -= 1          #Количество его жизней уменьшается
    
#Остальной код
Сама переменная Immortality находится в файле config.py:
Python:
#config.py

Immortality = False
Также у меня есть Tkinter-приложение, в котором есть "галочка на бессмертие":
screenshot.jpg

Подскажите, пожалуйста, как сделать так, чтобы при изменении состояния ChekButton'а (Поставить/убрать галочку) менялось значение переменной в config.py
Т.е. изменить переменную из config.py при помощи сonfig-changer.py (Tkinter-приложение) для использования этой переменной в игре (main.py)
 

Jerry

Пользователь
Пользователь
Июл 28, 2020
29
12
3
Не знаком с pygame и tkinter. Немного поколдовал, появился один из возможных вариантов (представлен ниже). Проверил чисто с tkinter. Как оно будет сочетаться с pygame - вопрос. Потому что, Tk().mainloop - блокирующий вызов. Дальше него управляющий поток не пойдет. А pygame, по логике, должен иметь свой цикл.
Если это так, то придется дополнять приложенное или искать новое решение. Возможно придется как-то запускать их в разных потоках или запускать два процесса и организовывать межпроцессное взаимодействие. Или поискать варианты в pygame: там может быть что-то для задания настроек.

config.py
Python:
immortality = False

main.py
Python:
import pygame

import config
from сonfig-changer.py import Settings

# some code

if not config.immortality:
    player.lives -= 1

сonfig-changer.py
Python:
from tkinter import Tk, Frame, Checkbutton, Button, BooleanVar
import config

class Settings(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.immortality = BooleanVar()
        self.immortality.set(config.immortality)
        checkbutton = Checkbutton(parent, text='Immortality',
        variable=self.immortality, command=self.update_immortality)

        checkbutton.pack()

    def update_immortality(self):
        config.immortality = self.immortality.get()
        print(f'config immortality set to {config.immortality}')

def main():
    root = Tk()
    Settings(root)
    root.mainloop()

if __name__ == '__main__':
    main()
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Подскажите, пожалуйста, как сделать так, чтобы при изменении состояния ChekButton'а (Поставить/убрать галочку) менялось значение переменной в config.py
Т.е. изменить переменную из config.py при помощи сonfig-changer.py (Tkinter-приложение) для использования этой переменной в игре (main.py)
Вот 2 варианта.
Первый (просто для демонстрации - делать так не нужно). Можно менять значение переменной в файле config.py (записывать новое значение в файл) при изменении состояния ChekButton'а, а в main.py загружать это значение:
config.py
Python:
immortality = False
config-changer.py
Python:
from tkinter import Tk, Frame, Checkbutton, BooleanVar
import config


class Settings(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.immortality = BooleanVar()
        self.immortality.set(config.immortality)
        self.checkbutton = Checkbutton(parent, text='Immortality',
        variable=self.immortality, command=self.update_immortality)

        self.checkbutton.pack()

    def update_immortality(self):
        print(f'config immortality set to {self.immortality.get()}')
        # записываем значение переменной в файл
        with open('config.py', 'w', encoding='utf-8') as f:
            f.write(f'immortality={self.immortality.get()}')

def main():
    root = Tk()
    Settings(root)
    root.mainloop()


if __name__ == '__main__':
    main()
main.py
Python:
import pygame
import sys
from importlib import reload
import config


class player():
    def __init__(self, lives):
        self.lives = lives

    def get_immortality(self):
        global config
        # запрашиваем значение переменной из файла
        config = reload(config)
        return config.immortality

    def decrease_lives(self):
        if not self.get_immortality():
            player.lives -= 1

        print(self.lives)


screen = pygame.display.set_mode((1200, 800))

pygame.init()

player = player(1000)


def run():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            # при нажатии на кнопку d уменьшаем player.lives
            if event.key == pygame.K_d:
                player.decrease_lives()


while True:
    run()
Второй. Объединить pygame и tkinter скрипты в один файл. tkinter-скрипт запускать в отдельном потоке, заменив mainloop на while True:
config.py
Python:
immortality = False
main.py
Python:
import tkinter as tk
import pygame
import sys
import threading
import time

import config


class Settings():
    def __init__(self):
        self.immortality = config.immortality
        self.flag = False
        self.start()

    def start(self):
        self.flag = False
        threading.Thread(target=self.config_changer).start()

    def stop(self):
        self.flag = True

    def set_immortality(self, value):
        self.immortality = value

    def get_immortality(self):
        return self.immortality

    def config_changer(self):
        root = tk.Tk()
        root.attributes("-topmost", True)
        immortality = tk.BooleanVar()
        immortality.set(self.immortality)
        checkbutton = tk.Checkbutton(root, text='Immortality',
                                     variable=immortality,
                                     command=lambda:
                                     self.set_immortality(immortality.get()))
        checkbutton.pack()
        while True:
            if self.flag:
                break
                root.destroy()
            try:
                root.update_idletasks()
                root.update()
                time.sleep(0.01)
            except:
                break


class player():
    def __init__(self, lives):
        self.lives = lives

    def decrease_lives(self):
        if not settings.get_immortality():
            player.lives -= 1

        print(self.lives)


settings = Settings()
screen = pygame.display.set_mode((1200, 800))

pygame.init()

player = player(1000)


def run():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            settings.stop()
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            # при нажатии на кнопку d уменьшаем player.lives
            if event.key == pygame.K_d:
                player.decrease_lives()


while True:
    run()
 
  • Мне нравится
Реакции: Malchik_molodoi

Malchik_molodoi

Новичок
Пользователь
Июл 29, 2020
19
4
3
20
Вот 2 варианта.
Первый (просто для демонстрации - делать так не нужно). Можно менять значение переменной в файле config.py (записывать новое значение в файл) при изменении состояния ChekButton'а, а в main.py загружать это значение:
config.py
Python:
immortality = False
config-changer.py
Python:
from tkinter import Tk, Frame, Checkbutton, BooleanVar
import config


class Settings(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.immortality = BooleanVar()
        self.immortality.set(config.immortality)
        self.checkbutton = Checkbutton(parent, text='Immortality',
        variable=self.immortality, command=self.update_immortality)

        self.checkbutton.pack()

    def update_immortality(self):
        print(f'config immortality set to {self.immortality.get()}')
        # записываем значение переменной в файл
        with open('config.py', 'w', encoding='utf-8') as f:
            f.write(f'immortality={self.immortality.get()}')

def main():
    root = Tk()
    Settings(root)
    root.mainloop()


if __name__ == '__main__':
    main()
main.py
Python:
import pygame
import sys
from importlib import reload
import config


class player():
    def __init__(self, lives):
        self.lives = lives

    def get_immortality(self):
        global config
        # запрашиваем значение переменной из файла
        config = reload(config)
        return config.immortality

    def decrease_lives(self):
        if not self.get_immortality():
            player.lives -= 1

        print(self.lives)


screen = pygame.display.set_mode((1200, 800))

pygame.init()

player = player(1000)


def run():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            # при нажатии на кнопку d уменьшаем player.lives
            if event.key == pygame.K_d:
                player.decrease_lives()


while True:
    run()
Второй. Объединить pygame и tkinter скрипты в один файл. tkinter-скрипт запускать в отдельном потоке, заменив mainloop на while True:
config.py
Python:
immortality = False
main.py
Python:
import tkinter as tk
import pygame
import sys
import threading
import time

import config


class Settings():
    def __init__(self):
        self.immortality = config.immortality
        self.flag = False
        self.start()

    def start(self):
        self.flag = False
        threading.Thread(target=self.config_changer).start()

    def stop(self):
        self.flag = True

    def set_immortality(self, value):
        self.immortality = value

    def get_immortality(self):
        return self.immortality

    def config_changer(self):
        root = tk.Tk()
        root.attributes("-topmost", True)
        immortality = tk.BooleanVar()
        immortality.set(self.immortality)
        checkbutton = tk.Checkbutton(root, text='Immortality',
                                     variable=immortality,
                                     command=lambda:
                                     self.set_immortality(immortality.get()))
        checkbutton.pack()
        while True:
            if self.flag:
                break
                root.destroy()
            try:
                root.update_idletasks()
                root.update()
                time.sleep(0.01)
            except:
                break


class player():
    def __init__(self, lives):
        self.lives = lives

    def decrease_lives(self):
        if not settings.get_immortality():
            player.lives -= 1

        print(self.lives)


settings = Settings()
screen = pygame.display.set_mode((1200, 800))

pygame.init()

player = player(1000)


def run():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            settings.stop()
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            # при нажатии на кнопку d уменьшаем player.lives
            if event.key == pygame.K_d:
                player.decrease_lives()


while True:
    run()
Спасибо, помогло!
У меня была мысль о том, чтобы открывать config.py при помощи "open as", но мне казалось что так нельзя, в любом случае у меня бы не получилось, т.к. я только что узнал о существовании importlib и reload(1 Вариант).
Второй вариант мне не совсем подходит, т.к. config-changer.py в будущем я хочу использовать как "лаунчер" для игры, который будет закрыватся при запуске game.py и работать в несколько потоков не будет необходимости, конечно можно было бы сделать внутриигровое меню с настройками, но на данном этапе я хочу сделать именно через лаунчер на Tkinter'e
 

Malchik_molodoi

Новичок
Пользователь
Июл 29, 2020
19
4
3
20
Не знаком с pygame и tkinter. Немного поколдовал, появился один из возможных вариантов (представлен ниже). Проверил чисто с tkinter. Как оно будет сочетаться с pygame - вопрос. Потому что, Tk().mainloop - блокирующий вызов. Дальше него управляющий поток не пойдет. А pygame, по логике, должен иметь свой цикл.
Если это так, то придется дополнять приложенное или искать новое решение. Возможно придется как-то запускать их в разных потоках или запускать два процесса и организовывать межпроцессное взаимодействие. Или поискать варианты в pygame: там может быть что-то для задания настроек.

config.py
Python:
immortality = False

main.py
Python:
import pygame

import config
from сonfig-changer.py import Settings

# some code

if not config.immortality:
    player.lives -= 1

сonfig-changer.py
Python:
from tkinter import Tk, Frame, Checkbutton, Button, BooleanVar
import config

class Settings(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        self.immortality = BooleanVar()
        self.immortality.set(config.immortality)
        checkbutton = Checkbutton(parent, text='Immortality',
        variable=self.immortality, command=self.update_immortality)

        checkbutton.pack()

    def update_immortality(self):
        config.immortality = self.immortality.get()
        print(f'config immortality set to {config.immortality}')

def main():
    root = Tk()
    Settings(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Мне надо изменить переменную immortality непосредственно в файле config.py, а также я хочу сделать config-changer.py "лаунчером" для игры, который будет закрываться при запуске game.py, т.е. необходимости в многопоточности нет.
В любом случае спасибо
 

Jerry

Пользователь
Пользователь
Июл 28, 2020
29
12
3
Мне надо изменить переменную immortality непосредственно в файле config.py, а также я хочу сделать config-changer.py "лаунчером" для игры, который будет закрываться при запуске game.py, т.е. необходимости в многопоточности нет.
В любом случае спасибо
Это многое меняет)
В таком случае могу предложить на рассмотрение два варианта:
1. Все выставленные в Tkinter приложении настройки передавать на вход приложению игры, которое config-changer.py будет запускать перед выходом.
2. Сделать настройки не в виде модуля питона, а, например, файла с json. Тогда ланчер в него будет все писать, а игра при старте все оттуда вычитывать и у себя уже складывать в любом удобном виде.
 

Форум IT Специалистов