blender-edutech-tutoriels/labyrinthe/3-arduino_pyfirmata/3-labyrinthe.py

207 lines
8.5 KiB
Python

import bge # Bibliothèque Blender Game Engine (BGE)
import pyfirmata # Protocole Firmata
import time # Protocole Firmata
import labyrinthe_carte # Liaison avec la carte
###############################################################################
# 3-labyrinthe.py
# @title: Module (unique) de la scène 3D du labyrinthe à bille pilotable avec une "manette Grove"
# @project: Blender-EduTech - Tutoriel 3 : Labyrinthe à bille - Interfacer avec une carte Arduino par le protocole Firmata
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2023 Philippe Roy
# @license: GNU GPL
#
# Commandes déclenchées par UPBGE pour le scène du labyrinthe
#
###############################################################################
# Récupérer la scène 3D
scene = bge.logic.getCurrentScene()
# print("Objets de la scene : ", scene.objects) # Lister les objets de la scène
# Constantes
JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED
JUST_RELEASED = bge.logic.KX_INPUT_JUST_RELEASED
ACTIVATE = bge.logic.KX_INPUT_ACTIVE
# carte = pyfirmata.Arduino('COM4') # Windows
# carte = pyfirmata.Arduino('/dev/ttyACM0') # GNU/Linux
# print("Communication Carte Arduino établie")
# Détection de la carte avec la protocol Firmata
carte = labyrinthe_carte.init_firmata()
if carte is None:
bge.logic.endGame()
# Itérateur pour les entrées
it = pyfirmata.util.Iterator(carte)
it.start()
# Définition des 4 boutons
bt_haut = carte.get_pin('d:2:i')
bt_bas = carte.get_pin('d:3:i')
bt_gauche = carte.get_pin('d:4:i')
bt_droit = carte.get_pin('d:5:i')
# Définition du joystick
jstk_x = carte.get_pin('a:0:i')
jstk_y = carte.get_pin('a:1:i')
# Définition de la led
led = carte.get_pin('d:7:o')
###############################################################################
# Gestion de la manette Arduino
###############################################################################
def manette(cont):
obj = cont.owner # obj est l'objet associé au contrôleur donc 'Plateau'
resolution = 0.01
led.write(False) # Éteindre led
# Bouton haut - Broche 2
if bt_haut.read() == True and bt_bas.read() == False:
obj.applyRotation((-resolution,0,-obj.worldOrientation.to_euler().z), False)
led.write(True)
# Bouton bas - Broche 3
if bt_haut.read() == False and bt_bas.read() == True:
obj.applyRotation((resolution,0,-obj.worldOrientation.to_euler().z), False)
led.write(True)
# Bouton gauche - Broche 4
if bt_gauche.read() == True and bt_droit.read() == False:
obj.applyRotation((0, -resolution,-obj.worldOrientation.to_euler().z), False)
led.write(True)
# Bouton droit - Broche 5
if bt_gauche.read() == False and bt_droit.read() == True:
obj.applyRotation((0, resolution,-obj.worldOrientation.to_euler().z), False)
led.write(True)
# Joystick : axe X
# de 0,25 à 0,75 avec une zone morte entre 0,48 et 0,52
# print (jstk_x.read(), jstk_y.read())
if jstk_x.read() is not None:
if jstk_x.read() <0.48 or jstk_x.read() >0.52:
resolution_prop= (jstk_x.read()-0.5)*(resolution/0.25)
obj.applyRotation((resolution_prop, 0, -obj.worldOrientation.to_euler().z), False)
led.write(True)
# Joystick : axe Y
if jstk_y.read() is not None:
if jstk_y.read() <0.48 or jstk_y.read() >0.52:
resolution_prop= (jstk_y.read()-0.5)*(resolution/0.25)
obj.applyRotation((0, resolution_prop, -obj.worldOrientation.to_euler().z), False)
led.write(True)
###############################################################################
# Gestion du clavier
###############################################################################
# Flèches pour tourner le plateau
def clavier(cont):
obj = cont.owner # obj est l'objet associé au contrôleur donc 'Plateau'
# obj = scene.objects['Plateau']
keyboard = bge.logic.keyboard
resolution = 0.01
global carte
# Touche ESC -> Quitter
if keyboard.inputs[bge.events.ESCKEY].status[0] == ACTIVATE:
carte.exit()
bge.logic.endGame()
# Flèche haut - Up arrow
if keyboard.inputs[bge.events.UPARROWKEY].status[0] == ACTIVATE:
obj.applyRotation((-resolution,0,-obj.worldOrientation.to_euler().z), False)
# Flèche bas - Down arrow
if keyboard.inputs[bge.events.DOWNARROWKEY].status[0] == ACTIVATE:
obj.applyRotation((resolution,0,-obj.worldOrientation.to_euler().z), False)
# Flèche gauche - Left arrow
if keyboard.inputs[bge.events.LEFTARROWKEY].status[0] == ACTIVATE:
obj.applyRotation((0, -resolution,-obj.worldOrientation.to_euler().z), False)
# Flèche droit - Right arrow
if keyboard.inputs[bge.events.RIGHTARROWKEY].status[0] == ACTIVATE:
obj.applyRotation((0, resolution, -obj.worldOrientation.to_euler().z), False)
###############################################################################
# Gameplay
###############################################################################
# Initialisation de la scène
def init(cont):
obj = cont.owner # obj est l'objet associé au contrôleur donc 'Bille'
# Mémorisation de la position de départ de la bille
obj['init_x']=obj.worldPosition.x
obj['init_y']=obj.worldPosition.y
obj['init_z']=obj.worldPosition.z
# Cacher le panneau de la victoire et suspendre la physique du panneau cliquable
scene.objects['Panneau victoire'].setVisible(False,True)
scene.objects['Panneau victoire - plan'].suspendPhysics (True)
scene.objects['Bouton fermer'].color = (0, 0, 0, 1) # Noir
# Cycle (boucle de contrôle de la bille)
def cycle(cont):
obj = cont.owner # obj est l'objet associé au contrôleur donc 'Bille'
obj['z']=obj.worldPosition.z # la propriété z est mis à jour avec la position globale en z de la bille
obj_plateau = scene.objects['Plateau'] # obj_plateau est l'objet 'Plateau'
obj_plateau['rot_x']=obj_plateau.worldOrientation.to_euler().x # propriété 'rot_x' mis à jour avec l'orientation globale en x du plateau
obj_plateau['rot_y']=obj_plateau.worldOrientation.to_euler().y # propriété 'rot_y' mis à jour avec l'orientation globale en y du plateau
obj_plateau['rot_z']=obj_plateau.worldOrientation.to_euler().z # propriété 'rot_z' mis à jour avec l'orientation globale en z du plateau
# Redémarrer la partie si la bille a chuté et si la panneau victoire n'est pas visible
if obj['z'] < -20 and scene.objects['Panneau victoire'].visible == False:
print ("Chuuuu.....te")
# Replacement du plateau (tous les angles à 0 en plusieurs fois)
while obj_plateau.worldOrientation.to_euler().x != 0 and obj_plateau.worldOrientation.to_euler().y !=0 and obj_plateau.worldOrientation.to_euler().z !=0 :
obj_plateau.applyRotation((-obj_plateau.worldOrientation.to_euler().x, -obj_plateau.worldOrientation.to_euler().y, -obj_plateau.worldOrientation.to_euler().z), False)
# Mettre la bille à la position de départ avec une vitesse nulle
obj.worldLinearVelocity=(0, 0, 0)
obj.worldAngularVelocity=(0, 0, 0)
obj.worldPosition.x = obj['init_x']
obj.worldPosition.y = obj['init_y']
obj.worldPosition.z = obj['init_z']+0.5 # On repose la bille
# Victoire (colision de la bille avec l'arrivée)
def victoire(cont):
scene.objects['Panneau victoire'].setVisible(True,True) # Afficher le panneau de la victoire
scene.objects['Panneau victoire - plan'].restorePhysics() # Restaurer la physique du panneau cliquable
start = 1
end = 100
layer = 0
priority = 1
blendin = 1.0
mode = bge.logic.KX_ACTION_MODE_PLAY
layerWeight = 0.0
ipoFlags = 0
speed = 1
scene.objects['Panneau victoire'].playAction('Panneau victoireAction', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
# Highlight du bouton Fermer
def victoire_fermer_hl(cont):
obj = cont.owner
# Activation
if cont.sensors['MO'].status == JUST_ACTIVATED:
obj.color = (1, 1, 1, 1) # Blanc
# Désactivation
if cont.sensors['MO'].status == JUST_RELEASED:
obj.color = (0, 0, 0, 1) # Noir
# Fermer le panneau de la victoire (clic)
def victoire_fermer(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive:
scene.objects['Panneau victoire'].setVisible(False,True) # Cacher le panneau de la victoire
scene.objects['Panneau victoire - plan'].suspendPhysics (True) # Suspendre la physique du panneau cliquable
scene.objects['Bille']['z']= -21 # On provoque le redémarrage si la bille est ressortie