import bge # Bibliothèque Blender Game Engine (UPBGE) import importlib import webbrowser ############################################################################### # twin_doc.py # @title: Documentation de l'environnement 3D pour jumeau numérique # @project: Blender-EduTech # @lang: fr # @authors: Philippe Roy # @copyright: Copyright (C) 2020-2022 Philippe Roy # @license: GNU GPL ############################################################################### # UPBGE scene scene = bge.logic.getCurrentScene() # Colors # color_link = (0.198, 0.109, 0.8, 1) # Violet # color_link_hl = (0.8, 0.005, 0.315, 1) # Magenta # Colors color_doc_chap = (0.198, 0.109, 0.8, 1) # Violet color_doc_fct = (0.198, 0.109, 0.8, 1) # Violet color_doc_hl = (0.8, 0.005, 0.315, 1) # Magenta # color_doc_activate = (0.936, 0.033, 1, 1) # Activé : Rose color_doc_activate = (0.051, 0.270, 0.279,1) # Turquoise # color_doc_activate = (0.936, 0.033, 1, 1) # Activé : Rose # UPBGE constants JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED JUST_RELEASED = bge.logic.KX_INPUT_JUST_RELEASED ACTIVATE = bge.logic.KX_INPUT_ACTIVE # JUST_DEACTIVATED = bge.logic.KX_SENSOR_JUST_DEACTIVATED # Cards description card_description ={} # Documentation du sytème system=importlib.import_module(scene.objects['System']['name']+'_doc') # Système system_card = system.get_system_card() card_description.update(system.get_card_description()) ############################################################################### # Documentation Python ############################################################################### # python_card=["function-card", "alternative-card", "loop-card", "flow-card", "text-card", "list-card", "dict-card", "oop-card", "console-card", "sleep-card"] python_card=["function-card", "alternative-card", "loop-card", "flow-card", "console-card", "sleep-card"] # Fonction card_function_title="Fonction" card_function_text=" La définition d'une fonction se fait \n avec \"def\". La fonction peut \n renvoyer une valeur avec \"return\". \n\n" card_function_text=card_function_text + " def fonction_1 (arguments) : \n instruction_1 \n instruction_2 \n ....\n return valeurs_renvoyées \n\n" card_function_text=card_function_text + " Les arguments sont des données \n transmises à la fonction." card_function_url=[["w3schools.com : functions","https://www.w3schools.com/python/python_functions.asp"]] card_description.update({"function-card" : [card_function_title, card_function_text, card_function_url]}) # Alternative card_alternative_title="Alternative" card_alternative_text=" L'alternative permet d'éxécuter des \n instructions en fonction d'un test. \n" card_alternative_text=card_alternative_text + " Elle se programme en suivant la \n suite : si ... alors ... sinon ... où \n" card_alternative_text=card_alternative_text + " \"si\" est \"if \" et \"sinon\" est \"else\". \n\n" card_alternative_text=card_alternative_text + " if condition :\n" card_alternative_text=card_alternative_text + " instruction_1\n" card_alternative_text=card_alternative_text + " else : \n" card_alternative_text=card_alternative_text + " instruction_2\n\n" card_alternative_text=card_alternative_text + "Le sinon (\"else\") est facultatif." card_alternative_url=[["w3schools.com : if ... else","https://www.w3schools.com/python/python_conditions.asp"]] card_description.update({"alternative-card" : [card_alternative_title, card_alternative_text, card_alternative_url]}) # Boucles card_loop_title="Boucles" card_loop_text=" Il y a deux types de boucle : \n - avec \"for\" pour définir un nombre \n de répétition (ici n), \n - avec \"while\" (tant que) pour \n prendre en compte une condition. \n \n" card_loop_text=card_loop_text + " for i in range (n) : \n instruction \n \n" card_loop_text=card_loop_text + " while condition : \n instruction" card_loop_url=[["w3schools.com : for","https://www.w3schools.com/python/python_for_loops.asp"], ["w3schools.com : while","https://www.w3schools.com/python/python_while_loops.asp"]] card_description.update({"loop-card" : [card_loop_title, card_loop_text, card_loop_url]}) # Flux card_flow_title="Contrôle du flux" card_flow_text=" Les structures (if, while, for) peuvent \n être gérées plus finement par les \n fonctions \"break\", \"continue\" et \"pass\". \n\n" card_flow_text= card_flow_text + "- \"break\" : Termine l'itération en cours \n et arrête la boucle.\n" card_flow_text= card_flow_text + "- \"continue\" : Termine l'itération en \n cours et reprend la boucle.\n" card_flow_text= card_flow_text + "- \"pass\" : Instruction vide." card_flow_url=[["w3schools.com : break","https://www.w3schools.com/python/ref_keyword_break.asp"], ["w3schools.com : continue","https://www.w3schools.com/python/ref_keyword_break.asp"], ["w3schools.com : pass","https://www.w3schools.com/python/ref_keyword_pass.asp"]] card_description.update({"flow-card" : [card_flow_title, card_flow_text, card_flow_url]}) # Chaine de caractère card_text_title="Chaîne de caractères\n(texte)" card_text_text="\nFIXME" card_text_url=[["w3schools.com : strings","https://www.w3schools.com/python/python_strings.asp"]] card_description.update({"text-card" : [card_text_title, card_text_text, card_text_url]}) # Liste card_list_title="Liste" card_list_text="FIXME" card_list_url=[["w3schools.com : lists","https://www.w3schools.com/python/python_lists.asp"]] card_description.update({"list-card" : [card_list_title, card_list_text, card_list_url]}) # Dictionnaire card_dict_title="Dictionnaire" card_dict_text="FIXME" card_dict_url=[["w3schools.com : dictionaries","https://www.w3schools.com/python/python_dictionaries.asp"]] card_description.update({"dict-card" : [card_dict_title, card_dict_text, card_dict_url]}) # Objet (POO) card_oop_title="Programmation\norientée objet (POO)" card_oop_text="\nFIXME" card_oop_url=[["w3schools.com : classes & objects","https://www.w3schools.com/python/python_classes.asp"]] card_description.update({"oop-card" : [card_oop_title, card_oop_text, card_oop_url]}) # Console card_console_title="Console" card_console_text=" Si vous avez executé Ropy dans un \n terminal avec l'option \"-con\", vous \n pouvez utiliser le terminal comme \n console de debuggage.\n\n" card_console_text= card_console_text + " print(\"Bonjour !\") \n -> Affiche le texte dans la console.\n\n" card_console_text= card_console_text + " variable = input () \n -> Permet la saisie, par exemple : \n" card_console_text= card_console_text + " entree = \"\"\n while entree == \"\" :\n entree = input ()" card_console_url=[["w3schools.com : print","https://www.w3schools.com/python/ref_func_print.asp"], ["w3schools.com : input","https://www.w3schools.com/python/ref_func_input.asp"]] card_description.update({"console-card" : [card_console_title, card_console_text, card_console_url]}) # Temps card_sleep_title="Gestion du temps" card_sleep_text=" Vous pouvez créer des temporisations \n dans le déroulement du script.\n\n" card_sleep_text= card_sleep_text + " time.sleep(x) \n -> Marque d'un temps d'arrêt de \n x secondes.\n\n" card_sleep_text= card_sleep_text + " Il faudra préalablement importer la \n bibliothèque \"time\" avec \"import time\"." card_sleep_url=[["docs.python.org : sleep","https://docs.python.org/fr/3/library/time.html#time.sleep"]] card_description.update({"sleep-card" : [card_sleep_title, card_sleep_text, card_sleep_url]}) ############################################################################### # Interface ############################################################################### ## # Initialisation de la documentation ## def init(): # Mettre les couleurs sur les icones (chapitres et cartes) chap=("general", "system", "python") for page in chap: scene.objects["Doc-"+page].color = color_doc_chap scene.objects["Doc-"+page+"-text"].color = color_doc_chap for i in range(len(system_card)): scene.objects[system_card[i]].color = color_doc_fct scene.objects[system_card[i]+"-icon"].color = color_doc_fct scene.objects[system_card[i]+"-text"].color = color_doc_fct for i in range(len(python_card)): scene.objects[python_card[i]].color = color_doc_fct scene.objects[python_card[i]+"-icon"].color = color_doc_fct scene.objects[python_card[i]+"-text"].color = color_doc_fct # Cacher et mettre les couleurs sur les liens (URL) scene.objects['Doc_chap-system-url_title'].setVisible(False,True) scene.objects['Doc_chap-python-url_title'].setVisible(False,True) for i in range(3): scene.objects['Doc_chap-python-url'+str(i)].setVisible(False,True) scene.objects['Doc_chap-python-url'+str(i)+'-colbox'].suspendPhysics() scene.objects['Doc_chap-python-url'+str(i)].color = color_doc_chap scene.objects['Doc_chap-system-url'+str(i)].setVisible(False,True) scene.objects['Doc_chap-system-url'+str(i)+'-colbox'].suspendPhysics() scene.objects['Doc_chap-system-url'+str(i)].color = color_doc_chap # Chargement du texte text_load() # Mémorisation de la position des pages for page in chap: scene.objects["Doc_chap-"+page]['init_lx']=scene.objects["Doc_chap-"+page].worldPosition.x scene.objects["Doc_chap-"+page]['init_ly']=scene.objects["Doc_chap-"+page].worldPosition.y scene.objects["Doc_chap-"+page]['init_lz']=scene.objects["Doc_chap-"+page].worldPosition.z # Page par défaut scene.objects['Doc']['page_chap'] = "general" ## # Ouvrir la documentation ## def open(): # Placer la tablette scene.active_camera = scene.objects["Camera-Doc"] scene.objects['Doc_close'].color= color_doc_fct scene.objects['Doc'].setVisible(True,True) text_hide() # Placer le nouveau chapitre name_chap = scene.objects['Doc']['page_chap'] scene.objects['Doc-'+name_chap].color = color_doc_activate scene.objects['Doc-'+name_chap+'-text'].color = color_doc_activate scene.objects['Doc_chap-'+name_chap].worldPosition = scene.objects['Doc'].worldPosition scene.objects['Doc_chap-'+name_chap].setVisible(True,True) # URL if name_chap == "system" or name_chap == "python": name_fct = scene.objects['Doc_chap-'+name_chap]['page_fct'] scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(False,True) for i in range(3): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(False,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].suspendPhysics() if name_fct !="": scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(True,True) for i in range(len(card_description[name_fct][2])): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)]['Text'] = card_description[name_fct][2][i][0] scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(True,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].restorePhysics() scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox']['Url'] = card_description[name_fct][2][i][1] # Afficher le texte de la carte active if name_chap != "general" and scene.objects['Doc_chap-'+name_chap]['page_fct'] !="": name_fct = scene.objects['Doc_chap-'+name_chap]['page_fct'] scene.objects['Doc_title']['Text'] = card_description[name_fct][0] scene.objects['Doc_title'].setVisible(True, False) text_show(name_fct) else: scene.objects['Doc_title']['Text'] = " " scene.objects['Doc_title'].setVisible(False,True) text_hide() ## # Fermer la documentation ## def close(cont): if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive : scene.active_camera = scene.objects["Camera"] chap=("general", "system", "python") for page in chap: scene.objects["Doc_chap-"+page].setVisible(False,True) scene.objects["Doc_chap-"+page].worldPosition.x = scene.objects["Doc_chap-"+page]['init_lx'] scene.objects["Doc_chap-"+page].worldPosition.y = scene.objects["Doc_chap-"+page]['init_ly'] scene.objects["Doc_chap-"+page].worldPosition.z = scene.objects["Doc_chap-"+page]['init_lz'] scene.objects['Doc'].setVisible(False,True) ## # Highlight ## def hl (cont): # Activation if cont.sensors['MO'].status == JUST_ACTIVATED : obj = cont.owner name=obj.name[:-7] name_text=name+"-text" name_icon=name+"-icon" # Close ou lien if name == "Doc_close" : scene.objects[name].color = color_doc_hl elif name == "Doc_chap-python-url0" or name == "Doc_chap-python-url1" or name == "Doc_chap-python-url2": scene.objects[name].color = color_doc_hl elif name == "Doc_chap-system-url0" or name == "Doc_chap-system-url1" or name == "Doc_chap-system-url2": scene.objects[name].color = color_doc_hl else: if "Doc-" in name : # Chapitre if name[4:] == scene.objects['Doc']['page_chap']: scene.objects[name].color = color_doc_activate scene.objects[name_text].color = color_doc_activate else: scene.objects[name].color = color_doc_hl scene.objects[name_text].color = color_doc_hl else: # Carte name_chap = scene.objects['Doc']['page_chap'] if name == scene.objects['Doc_chap-'+name_chap]['page_fct'] : scene.objects[name].color = color_doc_activate scene.objects[name_text].color = color_doc_activate scene.objects[name_icon].color = color_doc_activate else: scene.objects[name].color = color_doc_hl scene.objects[name_text].color = color_doc_hl scene.objects[name_icon].color = color_doc_hl # Désactivation if cont.sensors['MO'].status == JUST_RELEASED : obj = cont.owner name=obj.name[:-7] name_text=obj.name[:-7]+"-text" name_icon=obj.name[:-7]+"-icon" # Close ou lien if name == "Doc_close" : scene.objects[name].color = color_doc_fct elif name == "Doc_chap-python-url0" or name == "Doc_chap-python-url1" or name == "Doc_chap-python-url2": scene.objects[name].color = color_doc_fct elif name == "Doc_chap-system-url0" or name == "Doc_chap-system-url1" or name == "Doc_chap-system-url2": scene.objects[name].color = color_doc_fct else: if "Doc-" in name : # Chapitre if name[4:] == scene.objects['Doc']['page_chap']: scene.objects[name].color = color_doc_activate scene.objects[name_text].color = color_doc_activate else: scene.objects[name].color = color_doc_fct scene.objects[name_text].color = color_doc_fct else: # Carte name_chap = scene.objects['Doc']['page_chap'] if name == scene.objects['Doc_chap-'+name_chap]['page_fct'] : scene.objects[name].color = color_doc_activate scene.objects[name_text].color = color_doc_activate scene.objects[name_icon].color = color_doc_activate else: scene.objects[name].color = color_doc_fct scene.objects[name_text].color = color_doc_fct scene.objects[name_icon].color = color_doc_fct ## # Afficher le chapitre ## def chapter(cont): if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and cont.sensors['Click'].positive: obj = cont.owner scene.objects['Doc_title']['Text'] = " " # Enlever l'ancien chapitre scene.objects['Doc-'+scene.objects['Doc']['page_chap']].color = color_doc_chap scene.objects['Doc-'+scene.objects['Doc']['page_chap']+'-text'].color = color_doc_chap scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']].worldPosition.x = scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']]['init_lx'] scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']].worldPosition.y = scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']]['init_ly'] scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']].worldPosition.z = scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']]['init_lz'] if scene.objects['Doc']['page_chap'] != "general" and scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']]['page_fct'] !="": text_hide(scene.objects["Doc_chap-"+scene.objects['Doc']['page_chap']]['page_fct']) # Placer le nouveau chapitre name_chap= obj.name[4:-7] scene.objects['Doc-'+name_chap].color = color_doc_activate scene.objects['Doc-'+name_chap+'-text'].color = color_doc_activate scene.objects['Doc']['page_chap'] = name_chap scene.objects['Doc_chap-'+name_chap].worldPosition = scene.objects['Doc'].worldPosition scene.objects['Doc_chap-'+name_chap].setVisible(True,True) # URL if name_chap == "system" or name_chap == "python": name_fct = scene.objects['Doc_chap-'+name_chap]['page_fct'] scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(False,True) for i in range(3): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(False,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].suspendPhysics() if name_fct !="": scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(True,True) for i in range(len(card_description[name_fct][2])): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)]['Text'] = card_description[name_fct][2][i][0] scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(True,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].restorePhysics() scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox']['Url'] = card_description[name_fct][2][i][1] # Afficher le texte de la carte active if name_chap != "general" and scene.objects['Doc_chap-'+name_chap]['page_fct'] !="": name_fct = scene.objects['Doc_chap-'+name_chap]['page_fct'] scene.objects['Doc_title']['Text'] = card_description[name_fct][0] scene.objects['Doc_title'].setVisible(True, False) text_show(name_fct) else: scene.objects['Doc_title']['Text'] = " " scene.objects['Doc_title'].setVisible(False,True) text_hide() ## # Cacher le texte ## def text_hide(card=None): if card is None: for card in card_description: for i in range (13): scene.objects['Doc_text-l'+str(i+1)+'-'+str(card)].setVisible(False, False) else: for i in range (13): scene.objects['Doc_text-l'+str(i+1)+'-'+card].setVisible(False, False) ## # Afficher le texte ## def text_show(card=None): if card is None: for card in card_description: for i in range (13): scene.objects['Doc_text-l'+str(i+1)+'-'+str(card)].setVisible(True, False) else: for i in range (13): scene.objects['Doc_text-l'+str(i+1)+'-'+card].setVisible(True, False) ## # Préchargement des textes ## def text_load(): for i in range (13): scene.objects['Doc_text-l'+str(i+1)+'-ref']['Text'] = "" # Création des objets 3D for card in card_description: lines = card_description[card][1].split("\n") for i in range (13): doc_text= scene.addObject('Doc_text-l'+str(i+1), None, 0.00, True) doc_text.setParent(scene.objects['Doc']) doc_text.name = 'Doc_text-l'+str(i+1)+'-'+str(card) doc_text.worldPosition.x = scene.objects['Doc_text-l'+str(i+1)+'-ref'].worldPosition.x doc_text.worldPosition.y = scene.objects['Doc_text-l'+str(i+1)+'-ref'].worldPosition.y doc_text.worldPosition.z = scene.objects['Doc_text-l'+str(i+1)+'-ref'].worldPosition.z doc_text.setVisible(False, False) if i >= len(lines): scene.objects['Doc_text-l'+str(i+1)+'-'+str(card)]['Text']="" else: if len(lines[i]) ==0: scene.objects['Doc_text-l'+str(i+1)+'-'+str(card)]['Text']="" else: scene.objects['Doc_text-l'+str(i+1)+'-'+str(card)]['Text']=lines[i] ## # Afficher les details de la fonction à partir d'une carte ## def card (cont): if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive : obj = cont.owner name_chap = scene.objects['Doc']['page_chap'] name_fct= obj.name[:-7] scene.objects['Doc_title']['Text'] = " " # Enlever l'ancienne carte if scene.objects['Doc_chap-'+name_chap]['page_fct'] !="": text_hide(scene.objects['Doc_chap-'+name_chap]['page_fct']) scene.objects[scene.objects['Doc_chap-'+name_chap]['page_fct']].color = color_doc_fct scene.objects[scene.objects['Doc_chap-'+name_chap]['page_fct']+'-text'].color = color_doc_fct scene.objects[scene.objects['Doc_chap-'+name_chap]['page_fct']+'-icon'].color = color_doc_fct # Afficher le texte de la carte scene.objects['Doc_chap-'+name_chap]['page_fct'] = name_fct scene.objects[name_fct].color = color_doc_activate scene.objects[name_fct+'-icon'].color = color_doc_activate scene.objects[name_fct+'-text'].color = color_doc_activate scene.objects['Doc_title']['Text'] = card_description[name_fct][0] scene.objects['Doc_title'].setVisible(True, False) text_show(name_fct) # URL if name_chap == "system" or name_chap == "python": name_fct = scene.objects['Doc_chap-'+name_chap]['page_fct'] scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(False,True) for i in range(3): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(False,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].suspendPhysics() if name_fct !="": scene.objects['Doc_chap-'+name_chap+'-url_title'].setVisible(True,True) for i in range(len(card_description[name_fct][2])): scene.objects['Doc_chap-'+name_chap+'-url'+str(i)]['Text'] = card_description[name_fct][2][i][0] scene.objects['Doc_chap-'+name_chap+'-url'+str(i)].setVisible(True,True) scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox'].restorePhysics() scene.objects['Doc_chap-'+name_chap+'-url'+str(i)+'-colbox']['Url'] = card_description[name_fct][2][i][1] ## # Aller à la page internet ## def link (cont): if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive : webbrowser.open(cont.owner['Url'])