mirror of
https://forge.apps.education.fr/blender-edutech/ropy.git
synced 2024-01-27 08:23:20 +01:00
426 lines
16 KiB
Python
426 lines
16 KiB
Python
import bge # Blender Game Engine (UPBGE)
|
|
import bpy # Blender
|
|
import aud # Sounds
|
|
import threading # Multithreading
|
|
import trace
|
|
import sys
|
|
import time
|
|
import math
|
|
import mathutils
|
|
import random
|
|
|
|
###############################################################################
|
|
# rp_lib.py
|
|
# @title: Bibliothèque du Rover Ropy (rp_*)
|
|
# @project: Ropy (Blender-EduTech)
|
|
# @lang: fr
|
|
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
|
|
# @copyright: Copyright (C) 2020-2022 Philippe Roy
|
|
# @license: GNU GPL
|
|
#
|
|
# Bibliothèque des actions du robot
|
|
#
|
|
# Ropy est destiné à la découverte de la programmation procédurale et du language Python.
|
|
# A travers plusieurs challenges, donc de manière graduée, les élèves vont apprendre à manipuler les structures algorithmiques de base et à les coder en Python.
|
|
#
|
|
###############################################################################
|
|
|
|
scene = bge.logic.getCurrentScene()
|
|
|
|
# Colors
|
|
purple = (0.202, 0.114, 0.521,1)
|
|
turquoise = (0.051, 0.270, 0.279,1)
|
|
magenta = (0.799, 0.005, 0.314,1)
|
|
orange = (0.799, 0.130, 0.063,1)
|
|
yellow = (0.799, 0.617, 0.021, 1)
|
|
green = (0.246, 0.687, 0.078, 1)
|
|
red = (0.799, 0.031, 0.038, 1)
|
|
blue = (0.127, 0.456, 1.000, 1)
|
|
black = (0, 0, 0, 1)
|
|
|
|
color_text = (0, 0, 0, 1) # Noir
|
|
color_text_red = (0.799, 0.031, 0.038, 1)
|
|
color_text_orange = (0.799, 0.176, 0.054, 1)
|
|
color_text_yellow = (0.799, 0.617, 0.021, 1)
|
|
|
|
# ray_yellow = (0.799, 0.617, 0.021, 1) # [0.8, 0.619, 0.021])
|
|
# ray_blue = (0.127, 0.456, 1.000, 1)
|
|
# ray_black = (0, 0, 0, 1)
|
|
|
|
color_kaykit_black = (0.019, 0.032, 0.037, 1)
|
|
|
|
# Sounds
|
|
# audiodev = aud.Device()
|
|
# snd_build = aud.Sound('asset/sounds/build.wav')
|
|
# sndbuff_build = aud.Sound.cache(snd_build)
|
|
# snd_archer = aud.Sound('asset/sounds/archer.wav')
|
|
# sndbuff_archer = aud.Sound.cache(snd_archer)
|
|
# snd_mage = aud.Sound('asset/sounds/mage.wav')
|
|
# sndbuff_mage = aud.Sound.cache(snd_mage)
|
|
# snd_life = aud.Sound('asset/sounds/life.ogg')
|
|
# sndbuff_life = aud.Sound.cache(snd_life)
|
|
|
|
threads_cmd=[]
|
|
debug_thread = scene.objects['Terrain']['debug_thread']
|
|
|
|
# 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
|
|
|
|
###############################################################################
|
|
# Méthode kill pour les tâches (threads)
|
|
###############################################################################
|
|
|
|
class thread_with_trace(threading.Thread):
|
|
def __init__(self, *args, **keywords):
|
|
threading.Thread.__init__(self, *args, **keywords)
|
|
self.killed = False
|
|
|
|
def start(self):
|
|
self.__run_backup = self.run
|
|
self.run = self.__run
|
|
threading.Thread.start(self)
|
|
|
|
def __run(self):
|
|
sys.settrace(self.globaltrace)
|
|
self.__run_backup()
|
|
self.run = self.__run_backup
|
|
|
|
def globaltrace(self, frame, event, arg):
|
|
if event == 'call':
|
|
return self.localtrace
|
|
else:
|
|
return None
|
|
|
|
def localtrace(self, frame, event, arg):
|
|
if self.killed:
|
|
if event == 'line':
|
|
raise SystemExit()
|
|
return self.localtrace
|
|
|
|
def kill(self):
|
|
self.killed = True
|
|
|
|
###############################################################################
|
|
# Start et stop des tâches (threads)
|
|
###############################################################################
|
|
|
|
def thread_start(threads, type_txt, fct):
|
|
threads.append(thread_with_trace(target = fct))
|
|
threads[len(threads)-1].start()
|
|
if (debug_thread):
|
|
print ("Thread",type_txt, "#", len(threads)-1, "open.")
|
|
|
|
def thread_stop(threads, type_txt):
|
|
i=0
|
|
zombie_flag=False
|
|
for t in threads:
|
|
if not t.is_alive():
|
|
if (debug_thread):
|
|
print ("Thread",type_txt, "#",i,"closed.")
|
|
else:
|
|
if (debug_thread):
|
|
print ("Thread",type_txt, "#",i,"still open ...")
|
|
t.kill()
|
|
t.join()
|
|
if not t.is_alive():
|
|
if (debug_thread):
|
|
print ("Thread",type_txt, "#",i,"killed.")
|
|
else:
|
|
if (debug_thread):
|
|
print ("Thread",type_txt, "#",i,"zombie...")
|
|
zombie_flag=True
|
|
i +=1
|
|
if zombie_flag==False:
|
|
if (debug_thread):
|
|
print ("All threads",type_txt, "are closed.")
|
|
scene.objects['Terrain']['thread_cmd']=False
|
|
return True
|
|
else:
|
|
if (debug_thread):
|
|
print ("There are zombies threads",type_txt, ".")
|
|
return False
|
|
|
|
def thread_cmd_start(fct):
|
|
thread_start(threads_cmd, "commands", fct)
|
|
|
|
def thread_cmd_stop():
|
|
thread_stop(threads_cmd, "commands")
|
|
|
|
def rp_end():
|
|
if (debug_thread):
|
|
print ("Thread commands is arrived.")
|
|
scene.objects['Terrain']['thread_cmd']=False
|
|
|
|
def rp_fin():
|
|
rp_end()
|
|
|
|
def rp_quit():
|
|
rp_end()
|
|
|
|
###############################################################################
|
|
# Sounds
|
|
###############################################################################
|
|
|
|
# FIXME : Sound crash in Windows (very strange : blender, UPBGE, python ?), no music for Bill
|
|
def sound_play (sound):
|
|
if scene.objects['Commands']['sound'] and sys.platform!="win32":
|
|
audiodev.play(sound)
|
|
|
|
###############################################################################
|
|
# Rover fonction élèves
|
|
###############################################################################
|
|
|
|
##
|
|
# Avancer le rover
|
|
##
|
|
|
|
def rp_avancer ():
|
|
print ("rp_avancer()")
|
|
scene.objects['Points']['step'] +=1
|
|
obj=scene.objects['Rover']
|
|
|
|
# Rapide
|
|
if scene.objects['Commands']['speed'] == 10:
|
|
x0 = obj.worldPosition.x
|
|
y0 = obj.worldPosition.y
|
|
z0 = obj.worldPosition.z
|
|
if round(obj.worldOrientation.to_euler().z, 2) == 0.00: # Sud
|
|
obj.worldPosition=[x0, y0-1, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi,2) or round(obj.worldOrientation.to_euler().z, 2) == - round(math.pi,2) : # Nord
|
|
obj.worldPosition=[x0, y0+1, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == -round(3*(math.pi/2),2) : # Est
|
|
obj.worldPosition=[x0+1, y0, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(-math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == round(3*(math.pi/2),2) : # Ouest
|
|
obj.worldPosition=[x0-1, y0, z0]
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
# FIXME : Animation sacadée
|
|
# step =1/100
|
|
# print (obj.worldOrientation.to_euler().z)
|
|
# x0 = obj.worldPosition.x
|
|
# y0 = obj.worldPosition.y
|
|
# z0 = obj.worldPosition.z
|
|
# for i in range (100) :
|
|
# if round(obj.worldOrientation.to_euler().z, 2) == 0.00: # Sud
|
|
# obj.worldPosition=[x0, y0-step*i, z0]
|
|
# if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi,2) or round(obj.worldOrientation.to_euler().z, 2) == - round(math.pi,2) : # Nord
|
|
# obj.worldPosition=[x0, y0+step*i, z0]
|
|
# if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == -round(3*(math.pi/2),2) : # Est
|
|
# obj.worldPosition=[x0+step*i, y0, z0]
|
|
# if round(obj.worldOrientation.to_euler().z, 2) == round(-math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == round(3*(math.pi/2),2) : # Ouest
|
|
# obj.worldPosition=[x0-step*i, y0, z0]
|
|
# rp_tempo (0.1*step)
|
|
|
|
# Animation
|
|
# obj['avancer_anim']=True
|
|
start = 1
|
|
end = 100
|
|
layer = 0
|
|
priority = 1
|
|
blendin = 1.0
|
|
mode = bge.logic.KX_ACTION_MODE_PLAY
|
|
layerWeight = 0.0
|
|
ipoFlags = 0
|
|
speed = scene.objects['Commands']['speed']*4
|
|
if round(obj.worldOrientation.to_euler().z, 2) == 0.00: # Sud
|
|
scene.objects['Rover'].playAction('Rover-Avancer-Y-', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
# obj.worldPosition=[x0, y0-step*i, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi,2) or round(obj.worldOrientation.to_euler().z, 2) == - round(math.pi,2) : # Nord
|
|
scene.objects['Rover'].playAction('Rover-Avancer-Y+', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
# obj.worldPosition=[x0, y0+step*i, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == -round(3*(math.pi/2),2) : # Est
|
|
scene.objects['Rover'].playAction('Rover-Avancer-X+', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
# obj.worldPosition=[x0+step*i, y0, z0]
|
|
if round(obj.worldOrientation.to_euler().z, 2) == round(-math.pi/2,2) or round(obj.worldOrientation.to_euler().z, 2) == round(3*(math.pi/2),2) : # Ouest
|
|
scene.objects['Rover'].playAction('Rover-Avancer-X-', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
# obj.worldPosition=[x0-step*i, y0, z0]
|
|
scene.objects['Wheel-right-front'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-mid'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-rear'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-front'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-mid'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-rear'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
while scene.objects['Wheel-right-front'].isPlayingAction(): # Forçage du redraw
|
|
# scene.objects['Camera'].applyMovement((0, 0, 0), True)
|
|
scene.objects['Sun'].applyMovement((0, 0, 0), True)
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
##
|
|
# Tourner à gauche
|
|
##
|
|
|
|
def rp_gauche ():
|
|
print ("rp_gauche()")
|
|
scene.objects['Points']['step'] +=1
|
|
step=math.pi/2 # Pas angulaire
|
|
obj=scene.objects['Rover']
|
|
|
|
# Rapide
|
|
if scene.objects['Commands']['speed'] == 10:
|
|
obj.applyRotation((0, 0, step), True)
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
# Animation
|
|
start = 1
|
|
end = 100
|
|
layer = 0
|
|
priority = 1
|
|
blendin = 1.0
|
|
mode = bge.logic.KX_ACTION_MODE_PLAY
|
|
layerWeight = 0.0
|
|
ipoFlags = 0
|
|
speed = scene.objects['Commands']['speed']*4
|
|
scene.objects['Rover'].playAction('Rover-Gauche', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-front'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-mid'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-rear'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-front'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-mid'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-rear'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
while scene.objects['Wheel-right-front'].isPlayingAction(): # Forçage du redraw
|
|
# scene.objects['Camera'].applyMovement((0, 0, 0), True)
|
|
scene.objects['Sun'].applyMovement((0, 0, 0), True)
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
##
|
|
# Tourner à droite
|
|
##
|
|
|
|
def rp_droite ():
|
|
print ("rp_droite()")
|
|
scene.objects['Points']['step'] +=1
|
|
step=math.pi/2 # Pas angulaire
|
|
obj=scene.objects['Rover']
|
|
|
|
# Rapide
|
|
if scene.objects['Commands']['speed'] == 10:
|
|
obj.applyRotation((0, 0, -step), True)
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
# Animation
|
|
start = 1
|
|
end = 100
|
|
layer = 0
|
|
priority = 1
|
|
blendin = 1.0
|
|
mode = bge.logic.KX_ACTION_MODE_PLAY
|
|
layerWeight = 0.0
|
|
ipoFlags = 0
|
|
speed = scene.objects['Commands']['speed']*4
|
|
scene.objects['Rover'].playAction('Rover-Droite', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-front'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-mid'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-right-rear'].playAction('Wheel-Reculer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-front'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-mid'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
scene.objects['Wheel-left-rear'].playAction('Wheel-Avancer', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
|
|
while scene.objects['Wheel-right-front'].isPlayingAction(): # Forçage du redraw
|
|
# scene.objects['Camera'].applyMovement((0, 0, 0), True)
|
|
scene.objects['Sun'].applyMovement((0, 0, 0), True)
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
##
|
|
# Marquer
|
|
##
|
|
|
|
def rp_marquer ():
|
|
print ("rp_marquer()")
|
|
scene.objects['Points']['step'] +=1
|
|
rp_tempo (0.1)
|
|
obj=scene.objects['Rover']
|
|
x = obj.worldPosition.x
|
|
y = obj.worldPosition.y
|
|
z = obj.worldPosition.z
|
|
|
|
# Vérification de l'absence de balise sur la tuile
|
|
if [x,y] in scene.objects['Terrain']['map_tile_beacon'] :
|
|
print ("Case déjà marquée !")
|
|
return False
|
|
|
|
for i in range (100):
|
|
beacon = scene.objects["Beacon-"+str(i)]
|
|
if beacon['activated']==False:
|
|
beacon.worldPosition=[x,y,0.2]
|
|
beacon['activated']=True
|
|
beacon.setVisible(True, True)
|
|
break
|
|
if i ==99 :
|
|
print ("Plus de balise disponible !")
|
|
# beacon= scene.addObject("Beacon", scene.objects['Terrain'])
|
|
# beacon.worldPosition=[x,y,0.2]
|
|
scene.objects['Terrain']['map_tile_beacon'].append([x,y])
|
|
rp_tempo (0.1)
|
|
return True
|
|
|
|
##
|
|
# Détecter
|
|
##
|
|
|
|
def rp_detect ():
|
|
print ("rp_detect")
|
|
# FIXME
|
|
|
|
##
|
|
# Prendre
|
|
##
|
|
|
|
def rover_prendre ():
|
|
print ("rp_prendre")
|
|
# FIXME
|
|
|
|
##
|
|
# Radar
|
|
##
|
|
|
|
def rover_radar ():
|
|
print ("rp_radar")
|
|
# FIXME
|
|
|
|
|
|
###############################################################################
|
|
# Rover
|
|
###############################################################################
|
|
|
|
##
|
|
# Colision
|
|
##
|
|
|
|
def rover_colision ():
|
|
pass
|
|
|
|
###############################################################################
|
|
# Temporisation
|
|
###############################################################################
|
|
|
|
# Temporisation basée sur l'horloge de l'OS
|
|
def rp_sleep (duration):
|
|
time.sleep(duration)
|
|
|
|
# Temporisation basée par l'horloge de UPBGE
|
|
def rp_tempo (duration):
|
|
# time.sleep(duration*(1/scene.objects['Commands']['speed']))
|
|
scene.objects['Commands']['time']=0
|
|
while scene.objects['Commands']['time']<duration*(1/scene.objects['Commands']['speed']):
|
|
# print("Temporization commands :",scene.objects['Terrain']['delay_cmd'])
|
|
time.sleep(0.001)
|
|
# # pass
|
|
|
|
###############################################################################
|
|
# Map
|
|
###############################################################################
|
|
|
|
def map_aim_near (cont):
|
|
obj = cont.owner
|
|
sensor = obj.sensors['Near']
|
|
if sensor.positive :
|
|
print ("Goall !!")
|