Page Crédits et choix du script

This commit is contained in:
Philippe Roy 2023-02-05 18:17:16 +01:00
parent 5df7aebc65
commit fbc1069d4a
7 changed files with 199 additions and 28 deletions

View File

@ -64,15 +64,27 @@ Le code source, les fichiers blender et les assets sont hébergés sur le dépô
Les bibliothèques suivantes ne sont pas incluses par défaut dans l'environnement UPBGE :
- [**Pylint**](https://pylint.pycqa.org) : vérificateur du code Python
- [**pySerial**](https://pyserial.readthedocs.io) : communication sur le port série
- [**pyFirmata**](https://pyfirmata.readthedocs.io) : protocole Firmata (protocole générique de communication entre un logiciel et un microcontrôleur)
- [**wxPython**](https://www.wxpython.org/) : interface graphique utilisateur (GUI, utilisé ici pour Windows)
- [**pyQt5**](https://www.riverbankcomputing.com/software/pyqt/) : interface graphique utilisateur (GUI, utilisé ici pour GNU/Linux)
Il faut donc les installer localement (dans UPBGE), les étapes sont :
- **GNU/Linux** : La configuration ici présente est UPBGE installé sur ~ avec Python 3.9 :
- Aller dans le répertoire local de Python de UPBGE: $ cd ~/UPBGE-0.30-linux-x86_64/3.0/python/bin
- Installer le gestionnaire de paquet pip : $ ./python3.9 -m ensurepip --default-pip
- Installer Pylint : $ ./pip install pylint -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages
- Installer pySerial : $ ./pip install pyserial -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages
- **Windows** : La configuration ici présente est UPBGE installé sur le bureau utilisateur (prenom.nom) avec la distribution Anaconda installée :
- Avec Anaconda Navigator ouvrir un terminal Powershell
- Installer Pylint : pip install pylint -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages
- Installer pySerial : pip install pyserial -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages
- Télécharger le script ['get-pip.py'](https://bootstrap.pypa.io/get-pip.py) pour installer le gestionnaire de paquet [**Pip**](https://pip.pypa.io)
- Installer le gestionnaire de paquet Pip : $ ./python3.9 get-pip.py
- Installer Pylint : $ ./pip install pylint
- Installer pySerial : $ ./pip install pyserial
- Installer pyFirmata : $ ./pip install pyfirmata
- Installer PyQt5 : $ ./pip install PyQt5
- **Windows** : La configuration ici présente est UPBGE installé sur le bureau utilisateur (prenom.nom) :
- Ouvrir un terminal Powershell (éventuellement en passant par Anaconda Navigator)
- Aller dans le répertoire local de Python de UPBGE: cd C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\bin
- Télécharger le script ['get-pip.py'](https://bootstrap.pypa.io/get-pip.py) pour installer le gestionnaire de paquet [**Pip**](https://pip.pypa.io)
- Installer le gestionnaire de paquet Pip : python.exe get-pip.py
- Aller dans le répertoire 'Scripts' : cd C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\Scripts
- Installer Pylint : pip.exe install pylint
- Installer pySerial : pip.exe install pyserial
- Installer pyFirmata : pip.exe install pyfirmata
- Installer wxPython : pip.exe install wxpython

Binary file not shown.

BIN
ropy-32.blend Normal file

Binary file not shown.

57
rp.py
View File

@ -9,6 +9,7 @@ import sys
import os
import webbrowser # Lien internet
import threading # Multithreading
import subprocess # Multiprocessus
import xml.etree.ElementTree as ET # Creating/parsing XML file
import runpy # Exécution de script Python légère (sans import)
from pylint import epylint as lint # Mesure de la qualité d'un code Python
@ -39,6 +40,7 @@ import rp_about # About
# Debug flag
scene = bge.logic.getCurrentScene()
scene.objects['Commands']['debug_fps']=False
scene.objects['Commands']['script'] = os.path.join(os.getcwd(), "rp_cmd.py") # Script par défaut
# Memory
sys.setrecursionlimit(10**5) # Limite sur la récursivité (valeur par défaut : 1000) -> segfault de Blender
@ -210,17 +212,25 @@ def terrain_init (cont):
# cam2.setViewport(int(width / 2), 0, width, height)
##
# Mise en route et pause du cycle
# Validation du code Python
##
def python_validation():
(pylint_stdout, pylint_stderr) = lint.py_run('rp_cmd.py --disable=C --disable=W --disable=R', return_std=True)
def python_validation(file):
(pylint_stdout, pylint_stderr) = lint.py_run(file+' --disable=C --disable=W --disable=R', return_std=True)
stdout = pylint_stdout.read()
stderr = pylint_stderr.read()
if " error (" in stdout: # Présence d'erreur
print(stdout)
# UI : information
scene.objects['Cmd-text']['modal']= True
scene.objects['Cmd-text']['Text']= "Erreur dans le script ... "
scene.objects['Cmd-text'].setVisible(True,False)
print(stdout) # Affichage console
return False
else:
scene.objects['Cmd-text']['modal']= False
scene.objects['Cmd-text']['Text']= ""
scene.objects['Cmd-text'].setVisible(False,False)
return True
def terrain_run ():
@ -251,14 +261,13 @@ def terrain_run ():
time.sleep(0.125)
# Nombre de ligne du script Python
# print (os.getcwd())
file = open('rp_cmd.py', 'r')
file = open(scene.objects['Commands']['script'], 'r')
file_txt = file.read()
scene.objects['Points']['nbligne'] = len(file_txt.split("\n"))-28 # 28 lignes utilisées de base
file.close()
scene.objects['Rover']['stop'] = False
if python_validation():
runpy.run_module('rp_cmd', run_name='start') # Execution du script utilisateur
if python_validation(scene.objects['Commands']['script']):
runpy.run_path(scene.objects['Commands']['script'], run_name='start') # Execution du script utilisateur
# Arrêt de la pause
else:
@ -280,8 +289,8 @@ def terrain_stop ():
def terrain_end (cont):
if cont.sensors['End cycle'].positive:
scene.objects['Terrain']['run']=False
if python_validation():
runpy.run_module('rp_cmd', run_name='stop') # Fin du script utilisateur
if python_validation(scene.objects['Commands']['script']):
runpy.run_path(scene.objects['Commands']['script'], run_name='stop') # Fin du script utilisateur
# Commandes
scene.objects['Pause'].setVisible(False,False)
@ -444,6 +453,7 @@ def cmd_init(cont):
scene.objects['Points-Map-text'].setVisible(True,False)
scene.objects['Points-Twins'].setVisible(False,True)
scene.objects['Points-Twins-text'].setVisible(False,False)
scene.objects['Script-text']['Text']=scene.objects['Commands']['script']
# scene.objects['Info-1-text'].setVisible(False,False)
# scene.objects['Info-2-text'].setVisible(False,False)
@ -536,6 +546,7 @@ def cmd_hl(cont):
"Task-cmd":"Liste des tâches",
"Task_close-cmd":"Fermer la liste des tâches",
"ResetView": "Reset de la vue (Touche Début)",
"File": "Changer le fichier de commandes",
"About-cmd": "A propos",
"Speed_down": "Moins vite (-)",
"Speed_up": "Plus vite (+)",
@ -547,6 +558,7 @@ def cmd_hl(cont):
# "Aim":"Show aim",
# "Doc-cmd":"Documentation",
# "ResetView": "Reset view (Home key)",
# "File": "Change the commands file",
# "About-cmd": "About",
# "Speed_down": "Speed down (-)",
# "Speed_up": "Speed up (+)",
@ -641,6 +653,9 @@ def cmd_click (cont):
if obj.name=="Doc-cmd-colbox":
sound_play (snd_open)
tablet_open ()
if obj.name=="File":
sound_play (snd_open)
file_open ()
if obj.name=="About-cmd":
sound_play (snd_open)
about_open ()
@ -1337,6 +1352,28 @@ def store_close_click(cont):
sound_play (snd_close)
store_close()
###############################################################################
# Fichier
###############################################################################
def file_open():
# Terminer le processus file précédent
if ('file_proc' in scene.objects['Commands']):
if scene.objects['Commands']['file_proc'].poll()==None:
scene.objects['Commands']['file_proc'].terminate()
# Démarrer le processus file
if sys.platform=="linux": # wxPython ne s'installe pas bien sur GNU/linux -> Qt5
scene.objects['Commands']['file_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "rp_file_qt.py")], stdout=subprocess.PIPE, encoding = 'utf8')
else: # Qt5 ne s'installe pas bien sur Windows -> wxPython
scene.objects['Commands']['file_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "rp_file_wx.py")], stdout=subprocess.PIPE, encoding = 'utf8')
stout = scene.objects['Commands']['file_proc'].communicate()
if stout[0][:-1] != 'None':
scene.objects['Commands']['script'] = stout[0][:-1]
scene.objects['Script-text']['Text']=scene.objects['Commands']['script']
###############################################################################
# About
###############################################################################

View File

@ -23,24 +23,52 @@ JUST_RELEASED = bge.logic.KX_INPUT_JUST_RELEASED
ACTIVATE = bge.logic.KX_INPUT_ACTIVE
# JUST_DEACTIVATED = bge.logic.KX_SENSOR_JUST_DEACTIVATED
###############################################################################
# Crédits
###############################################################################
credits_description = {
'Blender' : ["Blender","Plateforme de modélisation et d'animation 3D","https://blender.org", "GNU GPL"],
'UPBGE' : ["UPBGE","Moteur de jeu 3D","https://upbge.org", "GNU GPL"],
'Python' : ["Python","Langage de programmation","https://python.org", "PSFL"],
'Pylint' : ["Pylint","Bibliothèque de vérification d'un code Python","https://pylint.pycqa.org", "GNU GPL"],
'pySerial' : ["pySerial","Bibliothèque de communication série","https://pyserial.readthedocs.io", "BSD-3-Clause"],
'wxWidgets' : ["wxWidgets","Bibliothèque GUI","https://www.wxwidgets.org", "wxWindows Library Licence"],
'wxPython' : ["wxPython","API Python de wxWidgets","https://www.wxpython.org", "GNU GPL"],
'Qt5' : ["Qt5","Bibliothèque GUI","https://www.qt.io", "GNU LGPL-3"],
'PyQt' : ["PyQt","API Python de Qt5","https://www.riverbankcomputing.com/software/pyqt","GNU GPL"],
'Polygonrunway' : ["Roman Klčo","Modèles 3D","https://www.patreon.com/polygonrunway/",""],
'KayKit' : ["Kay Lousberg","Modèles 3D","www.kaylousberg.com","CC0 1.0"],
'Kenney' : ["Kenney","Modèles 3D, icônes et sons","https://www.kenney.nl","CC0 1.0"],
'Game-icons.net' : ["Game-icons.net","Icônes","https://game-icons.net","CC BY 3.0"],
'Mainframe' : ["Mainframe","Police de caractères","https://www.dafont.com/fr/mainframe.font", "CC BY 4.0"]}
###############################################################################
# Page About
###############################################################################
##
# Ouverture
##
def open():
scene.objects['About_close'].color= color_link
scene.objects['About_credits'].color= color_link
# Configuration
scene.objects['About_screen-up'].color= color_link
scene.objects['About_screen-down'].color= color_link
scene.objects['About_screen']['Text']= "SCREEN SIZE : "+str(bge.render.getWindowWidth()) +" x "+str(bge.render.getWindowHeight())
scene.objects['About_quality-up'].color= color_link
scene.objects['About_quality-down'].color= color_link
# scene.objects['About_screen']['Text']= "SCREEN SIZE : "+str(bge.render.getWindowWidth()) +" x "+str(bge.render.getWindowHeight())
# Liens
scene.objects['About_link-git'].color= color_link
scene.objects['About_link-gpl'].color= color_link
scene.objects['About_link-upbge'].color= color_link
scene.objects['About_link-kay'].color= color_link
scene.objects['About_link-kenney'].color= color_link
scene.objects['About_link-polygonrunway'].color= color_link
scene.objects['About_link-icons'].color= color_link
# Animation
scene.objects['About'].setVisible(True,True)
scene.objects['About'].worldPosition = [0, 1.53623, -1.8] # old [0, 1.53623, -0.892838]
scene.objects['About']['timer'] = 0
@ -98,11 +126,7 @@ def link(cont):
link={
'About_link-git' : 'https://gitlab.com/blender-edutech/ropy',
'About_link-gpl' : 'https://www.gnu.org/licenses/gpl-3.0.html',
'About_link-upbge' : 'https://www.upbge.org',
'About_link-kay' : 'https://www.kaylousberg.com',
'About_link-kenney' : 'https://www.kenney.nl',
'About_link-polygonrunway' : 'https://www.patreon.com/polygonrunway/',
'About_link-icons' : 'https://game-icons.net/'}
'About_link-upbge' : 'https://www.upbge.org'}
webbrowser.open(link [name])
def link_hl(cont):
@ -116,3 +140,56 @@ def link_hl(cont):
obj = cont.owner
name=obj.name[:-7]
scene.objects[name].color = color_link
###############################################################################
# Page Crédits
###############################################################################
def credits(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
# Mémorisation de la position des pages avant changement
scene.objects["About"]['init_lx']=scene.objects["About"].worldPosition.x
scene.objects["About"]['init_ly']=scene.objects["About"].worldPosition.y
scene.objects["About"]['init_lz']=scene.objects["About"].worldPosition.z
scene.objects["Credits"]['init_lx']=scene.objects["Credits"].worldPosition.x
scene.objects["Credits"]['init_ly']=scene.objects["Credits"].worldPosition.y
scene.objects["Credits"]['init_lz']=scene.objects["Credits"].worldPosition.z
# Afficher la page Crédits
scene.objects["Credits"].worldPosition.x = scene.objects["About"]['init_lx']
scene.objects["Credits"].worldPosition.y = scene.objects["About"]['init_ly']
scene.objects["Credits"].worldPosition.z = scene.objects["About"]['init_lz']
scene.objects["About"].worldPosition.x = scene.objects["Credits"]['init_lx']
scene.objects["About"].worldPosition.y = scene.objects["Credits"]['init_ly']
scene.objects["About"].worldPosition.z = scene.objects["Credits"]['init_lz']
scene.objects['Credits_close'].color= color_link
scene.objects['About'].setVisible(False,True)
scene.objects['Credits'].setVisible(True,True)
# Afficher les descriptions
credits_description_list=list (credits_description)
for i in range(len(credits_description_list)):
scene.objects["Credits_url-"+str(i+1)]['Text']= credits_description[credits_description_list[i]][0]
scene.objects["Credits_url-"+str(i+1)].color= color_link
scene.objects["Credits_text-"+str(i+1)]['Text']= credits_description[credits_description_list[i]][1]
scene.objects["Credits_license-"+str(i+1)]['Text']= credits_description[credits_description_list[i]][3]
def credits_close(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
# Revenir à la page About
scene.objects["Credits"].worldPosition.x = scene.objects["Credits"]['init_lx']
scene.objects["Credits"].worldPosition.y = scene.objects["Credits"]['init_ly']
scene.objects["Credits"].worldPosition.z = scene.objects["Credits"]['init_lz']
scene.objects["About"].worldPosition.x = scene.objects["About"]['init_lx']
scene.objects["About"].worldPosition.y = scene.objects["About"]['init_ly']
scene.objects["About"].worldPosition.z = scene.objects["About"]['init_lz']
scene.objects['Credits'].setVisible(False,True)
scene.objects['About'].setVisible(True,True)
def credits_link(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
obj = cont.owner
idx=int(obj.name[12:-7])
webbrowser.open(credits_description[list(credits_description)[idx-1]][2])

23
rp_file_qt.py Normal file
View File

@ -0,0 +1,23 @@
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QFileDialog
###############################################################################
# twin_file_qt.py
# @title: Selecteur de fichier (pyQt5)
# @project: Blender-EduTech
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2023 Philippe Roy
# @license: GNU GPL
###############################################################################
def dialog():
file , check = QFileDialog.getOpenFileName(None, "Sélection du fichier de commande", "", "Python Files (*.py)")
if check:
return file
app = QApplication(sys.argv)
file = dialog()
print (file)
sys.exit(0)

22
rp_file_wx.py Normal file
View File

@ -0,0 +1,22 @@
import wx
###############################################################################
# twin_file_wx.py
# @title: Selecteur de fichier (wxPython)
# @project: Blender-EduTech
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2023 Philippe Roy
# @license: GNU GPL
###############################################################################
app = wx.App()
frame = wx.Frame(None, -1, 'win.py')
# frame.SetDimensions(0,0,200,50)
openFileDialog = wx.FileDialog(frame, "Sélection du fichier de commande", "", "",
"Fichier Python (*.py)|*.py", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
openFileDialog.ShowModal()
print(openFileDialog.GetPath())
openFileDialog.Destroy()