mirror of
https://forge.apps.education.fr/blender-edutech/ropy.git
synced 2024-01-27 08:23:20 +01:00
403 lines
17 KiB
Python
403 lines
17 KiB
Python
import bge # Bibliothèque Blender Game Engine (UPBGE)
|
||
import bpy # Blender
|
||
import random
|
||
from rp_lib import * # Bibliothèque Ropy
|
||
import os
|
||
|
||
###############################################################################
|
||
# rp_map1.py
|
||
# @title: Carte 1 pour Ropy
|
||
# @project: Ropy (Blender-EduTech)
|
||
# @lang: fr
|
||
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
|
||
# @copyright: Copyright (C) 2020-2022 Philippe Roy
|
||
# @license: GNU GPL
|
||
#
|
||
###############################################################################
|
||
|
||
scene = bge.logic.getCurrentScene()
|
||
|
||
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)
|
||
color_text_white = (1, 1, 1, 1)
|
||
|
||
###############################################################################
|
||
# Missions
|
||
###############################################################################
|
||
|
||
missions_card_description ={}
|
||
missions_conf ={}
|
||
missions_task ={}
|
||
|
||
###############################################################################
|
||
# Initialisation du niveau :
|
||
# Niveau 1 : Les premiers pas de Ropy
|
||
# Niveau 2 : Ma première fonction
|
||
# Niveau 3 : Sécuriser Ropy
|
||
# Niveau 4 : Partir au bout du monde
|
||
# Niveau 5 : Faire face à l'inconnu
|
||
# Niveau 6 : Se rendre utile
|
||
###############################################################################
|
||
|
||
missions_card=["mission_1-card", "mission_2-card", "mission_3-card", "mission_4-card", "mission_5-card", "mission_6-card"]
|
||
# missions_card=["mission_1-card", "mission_2-card", "mission_3-card", "mission_4-card", "mission_5-card", "mission_6-card", "mission_7-card", "mission_8-card"]
|
||
|
||
# Mission 1
|
||
mission_1_title="Mission 1\n Premiers pas"
|
||
mission_1_text="\n \n Il faut aider Ropy à atteindre la case \n de l'objectif (à l'est de la station). \n"
|
||
mission_1_text= mission_1_text +" -> Voir onglet Rover, page \"Avancer\" \n"
|
||
mission_1_text= mission_1_text +" -> Voir onglet Rover, page \"Tourner \" \n\n"
|
||
mission_1_text= mission_1_text +"Afin de visualiser le trajet, il faudra \n marquer les cases. \n"
|
||
mission_1_text= mission_1_text +" -> Voir onglet Rover, page \"Baliser\" \n"
|
||
mission_1_task = "- Atteindre l'objectif \n\n- Poser 6 balises \n minimum"
|
||
mission_1_init=[-11.0,3.0, "e"] # Rover init position (x,y), orientation ("n|s|e|w")
|
||
mission_1_aim=[-7.0,2.0] # Aim position (x,y)
|
||
missions_card_description.update({"mission_1-card" : [mission_1_title, mission_1_text]})
|
||
missions_conf.update({"1" : [mission_1_init, mission_1_aim]})
|
||
missions_task.update({"1" : [mission_1_task]})
|
||
|
||
# Mission 2
|
||
mission_2_title="Mission 2\n Ma première fonction"
|
||
mission_2_text="\n \n La case à atteindre est toujours la \n même (à l'est de la station). \n \n"
|
||
mission_2_text= mission_2_text + " Pour faciliter le codage, vous devez \n créer et utiliser la fonction \n \"mrp_avancer()\" regroupant avancer \n et marquer. \n -> Voir onglet Python, page \"Fonction\". \n\n\n\n\n"
|
||
mission_2_task = "- Atteindre l'objectif \n\n- Poser 6 balises \n minimum\n\n- 40 lignes de code \n maximum\n\n- Définition de la \n fonction \n \"mrp_avancer()\""
|
||
mission_2_init=[-11.0,3.0, "e"]
|
||
mission_2_aim=[-7.0,2.0]
|
||
missions_card_description.update({"mission_2-card" : [mission_2_title, mission_2_text]})
|
||
missions_conf.update({"2" : [mission_2_init, mission_2_aim]})
|
||
missions_task.update({"2" : [mission_2_task]})
|
||
|
||
# Mission 3
|
||
mission_3_title="Mission 3\n Apprendre le danger"
|
||
mission_3_text="\n \n Tout d'abords, il faut provoquer une \n collision avec un obstacle (pente \n ou station) et observer ce qui se \n passe.\n \n"
|
||
mission_3_text= mission_3_text + " Il faut donc sécuriser Ropy en \n utilisant une structure alternative. \n -> Voir onglet Python, page \"Si alors\" \n -> Voir onglet Rover, page \"Détecter\" \n \n"
|
||
mission_3_task = "- Utilisation de \n \"rp_detect()\" dans \n une structure \n alternative \"if\"."
|
||
mission_3_init=[-11.0,3.0, "e"] # Rover init position (x,y), orientation ("n|s|e|w")
|
||
mission_3_aim=[100.0,100.0] # Aim caché -> pas de de position objectif
|
||
missions_card_description.update({"mission_3-card" : [mission_3_title, mission_3_text]})
|
||
missions_conf.update({"3" : [mission_3_init, mission_3_aim]})
|
||
missions_task.update({"3" : [mission_3_task]})
|
||
|
||
# Mission 4
|
||
mission_4_title="Mission 4\n Partir au bout du monde"
|
||
mission_4_text="\n \n Ropy est maintenant prêt pour \n l'aventure soit atteindre la case \n du nouvel objectif (loin, très loin ...). \n \n Pour un tel voyage, l'utilisation \n d'une boucle du type \"for\" s'impose. \n"
|
||
mission_4_text= mission_4_text +" -> Voir onglet Python, page \"Boucle\" \n \n"
|
||
mission_4_text= mission_4_text + " Dans un deuxième temps, il faut créer \n la fonction \"mrp_avancer_nbpas(pas)\"\n afin d'avancer d'un nombre de pas."
|
||
mission_4_task = "- Atteindre l'objectif \n\n- 40 lignes de code \n maximum\n\n- Utilisation de \n boucle \"for\" \n\n- En bonus : création \n de la fonction \"mrp_\n avancer_nbpas(pas)\""
|
||
mission_4_init=[-7.0,4.0, "e"]
|
||
mission_4_aim=[12.0,9.0]
|
||
missions_card_description.update({"mission_4-card" : [mission_4_title, mission_4_text]})
|
||
missions_conf.update({"4" : [mission_4_init, mission_4_aim]})
|
||
missions_task.update({"4" : [mission_4_task]})
|
||
|
||
# Mission 5
|
||
mission_5_title="Mission 5\n Faire face à l'inconnu"
|
||
mission_5_text="\n \n La case à atteindre est toujours la \n même, mais le lieu de départ change \n à chaque fois. \n \n"
|
||
mission_5_text= mission_5_text +" Pour pallier à l\'aléatoire, vous \n utiliserez les pentes comme obstacle. \n"
|
||
mission_5_text= mission_5_text +" Il faut alors créer une fonction \n avec une boucle \"while\" (tant que) \n qui permet d'avancer jusqu'à un \n obstacle :"
|
||
mission_5_text= mission_5_text +" \"mrp_avancer_mur()\". \n \n \n"
|
||
mission_5_task = "- Atteindre l'objectif \n\n- 40 lignes de code \n maximum\n\n- Utilisation de \n boucle \"while\" \n\n- En bonus : création \n de la fonction \"mrp_\n avancer_mur()\""
|
||
mission_5_init=[0.0,0.0, "e"] # Position aléatoire tourné vers l'est -> défini dans le reset
|
||
mission_5_aim=[12.0,9.0]
|
||
missions_card_description.update({"mission_5-card" : [mission_5_title, mission_5_text]})
|
||
missions_conf.update({"5" : [mission_5_init, mission_5_aim]})
|
||
missions_task.update({"5" : [mission_5_task]})
|
||
|
||
# Mission 6
|
||
mission_6_title="Mission 6\n Se rendre utile"
|
||
mission_6_text="\n \n Une zone précise du terrain présente \n des carottages afin d'analyser la \n roche. \n \n Les lieux de forage sont définis de \n manière aléatoire (encore !), pour les \n réaliser, Ropy doit donc passer sur \n toutes les cases de la zone. \n \n \n \n \n \n \n"
|
||
mission_6_task = "- Passer sur les 10 \n lieux de forage"
|
||
mission_6_init=[0.0,0.0, "e"] # Position aléatoire tourné vers l'est -> défini dans le reset
|
||
mission_6_aim=[100.0,100.0] # Aim caché -> ramassage de pierre
|
||
missions_card_description.update({"mission_6-card" : [mission_6_title, mission_6_text]})
|
||
missions_conf.update({"6" : [mission_6_init, mission_6_aim]})
|
||
missions_task.update({"6" : [mission_6_task]})
|
||
|
||
# Mission 7
|
||
# mission_7_title="Mission 7\n FIXME"
|
||
# mission_7_text="\n \n FIXME"
|
||
# mission_7_task = "FIXME"
|
||
# missions_card_description.update({"mission_7-card" : [mission_7_title, mission_7_text]})
|
||
# missions_conf.update({"7" : [mission_7_init, mission_7_aim]})
|
||
# missions_task.update({"7" : [mission_7_task]})
|
||
|
||
# Mission 8
|
||
# mission_8_title="Mission 8\n FIXME"
|
||
# mission_8_text="\n \n FIXME"
|
||
# mission_8_task = "FIXME"
|
||
# missions_card_description.update({"mission_8-card" : [mission_8_title, mission_8_text]})
|
||
# missions_conf.update({"8" : [mission_8_init, mission_8_aim]})
|
||
# missions_task.update({"8" : [mission_8_task]})
|
||
|
||
# Description des cartes missions
|
||
|
||
def get_missions_card():
|
||
return missions_card
|
||
|
||
def get_card_description():
|
||
return missions_card_description
|
||
|
||
###############################################################################
|
||
# Map
|
||
###############################################################################
|
||
|
||
##
|
||
# Initialization
|
||
##
|
||
|
||
def map_init():
|
||
|
||
# Terrain
|
||
scene.objects['Terrain']['size'] = [-15,-11,15,10] # Map size
|
||
scene.objects['Terrain']['map_tile_montain']= []
|
||
scene.objects['Terrain']['map_tile_station']= [[-9,2],[-9,3]]
|
||
for obj_i in scene.objects:
|
||
if "terrain_sideCliff" in obj_i.name or "terrain_sideCorner" in obj_i.name or "terrain_sideCornerInner" in obj_i.name:
|
||
scene.objects['Terrain']['map_tile_montain'].append([round(obj_i.worldPosition.x), round(obj_i.worldPosition.y)])
|
||
|
||
# Couleurs
|
||
rp_couleur_init()
|
||
|
||
# Cacher les zones
|
||
scene.objects['Aim'].setVisible(False,True)
|
||
scene.objects['Initzone-mission-5'].setVisible(False,True)
|
||
scene.objects['Aimzone-mission-6'].setVisible(False,True)
|
||
|
||
# print (scene.objects['Terrain']['map_tile_montain'])
|
||
# i=0
|
||
# for i_xy in scene.objects['Terrain']['map_tile_montain']:
|
||
# beacon= scene.addObject("Beacon", scene.objects['Terrain'])
|
||
# beacon.worldPosition=[i_xy[0],i_xy[1],0.2]
|
||
# beacon.setVisible(True, True)
|
||
# i+=1
|
||
|
||
# Landscape
|
||
# file_path = 'asset/map/map1-landscape.blend'
|
||
# inner_path = 'Object'
|
||
# object_name = 'Landscape'
|
||
# bpy.ops.wm.append(
|
||
# filepath=os.path.join(file_path, inner_path, object_name),
|
||
# directory=os.path.join(file_path, inner_path),
|
||
# filename=object_name)
|
||
|
||
##
|
||
# Reset de la map
|
||
##
|
||
|
||
def map_reset():
|
||
scene.objects['Points']['step']=0
|
||
scene.objects['Points']['nbligne']=0
|
||
scene.objects['Points']['battery']=100
|
||
scene.objects['Points-Battery'].color = color_text_white
|
||
scene.objects['Points-Battery-text'].color = color_text
|
||
mission_init = missions_conf[str(scene.objects['Points']['mission'])][0]
|
||
mission_aim = missions_conf[str(scene.objects['Points']['mission'])][1]
|
||
|
||
# Cacher les balises
|
||
for i in range (200):
|
||
beacon = scene.objects["Beacon-"+str(i)]
|
||
beacon.worldPosition=[29,1+i,0.2]
|
||
beacon.setVisible(False,True)
|
||
beacon['activated']=False
|
||
scene.objects['Terrain']['map_tile_beacon']= []
|
||
|
||
# Initialisation du rover
|
||
obj = scene.objects['Rover']
|
||
obj.worldPosition.x = mission_init[0]
|
||
obj.worldPosition.y = mission_init[1]
|
||
obj.worldPosition.z = 0.2
|
||
applyRotationTo(obj, 0, 0, 0, True)
|
||
if mission_init[2] == "n":
|
||
obj.applyRotation((0, 0, math.pi), True)
|
||
if mission_init[2] == "e":
|
||
obj.applyRotation((0, 0, math.pi/2), True)
|
||
if mission_init[2] == "w":
|
||
obj.applyRotation((0, 0, -math.pi/2), True)
|
||
|
||
# Initialisation du rover pour les missions 5 et 6 : position aléatoire entre -3.0 ; 5.0 et 1.0 ; -10.0
|
||
if scene.objects['Points']['mission']==5 or scene.objects['Points']['mission']==6:
|
||
position_ok=False
|
||
while position_ok==False: # Exclusion de certaines cases
|
||
obj.worldPosition.x = random.randint(-3,1)
|
||
obj.worldPosition.y = random.randint(-10,5)
|
||
position_ok=True
|
||
if obj.worldPosition.x== 0 and obj.worldPosition.y== -10:
|
||
position_ok=False
|
||
if obj.worldPosition.x== 1 and obj.worldPosition.y== -8:
|
||
position_ok=False
|
||
if obj.worldPosition.x== 1 and obj.worldPosition.y== -9:
|
||
position_ok=False
|
||
if obj.worldPosition.x== 1 and obj.worldPosition.y== -10:
|
||
position_ok=False
|
||
|
||
# Initialisation des objectifs
|
||
scene.objects['Terrain']['map_aim']= [[mission_aim[0],mission_aim[1]]]
|
||
obj_aim = scene.objects['Aim']
|
||
obj_aim.worldPosition.x = mission_aim[0]
|
||
obj_aim.worldPosition.y = mission_aim[1]
|
||
obj_aim.worldPosition.z = 0.5
|
||
|
||
|
||
###############################################################################
|
||
# Objectif
|
||
###############################################################################
|
||
|
||
##
|
||
# Afficher l'objectif
|
||
##
|
||
|
||
def aim_show():
|
||
|
||
# Zone de départ
|
||
if scene.objects['Points']['mission']==5 or scene.objects['Points']['mission']==6:
|
||
scene.objects['Initzone-mission-5'].setVisible(True,True)
|
||
else:
|
||
scene.objects['Initzone-mission-5'].setVisible(False,True)
|
||
|
||
# Cible
|
||
if scene.objects['Points']['mission']==3 or scene.objects['Points']['mission']==6:
|
||
scene.objects['Aim'].setVisible(False,True)
|
||
else:
|
||
scene.objects['Aim'].setVisible(True,True)
|
||
|
||
# Zone cible
|
||
if scene.objects['Points']['mission']==6:
|
||
scene.objects['Aimzone-mission-6'].setVisible(True,True)
|
||
else:
|
||
scene.objects['Aimzone-mission-6'].setVisible(False,True)
|
||
|
||
##
|
||
# Cacher l'objectif
|
||
##
|
||
|
||
def aim_hide():
|
||
scene.objects['Aim'].setVisible(False,True)
|
||
scene.objects['Aimzone-mission-6'].setVisible(False,True)
|
||
scene.objects['Initzone-mission-5'].setVisible(False,True)
|
||
|
||
##
|
||
# Affichage des tâches
|
||
##
|
||
|
||
def task():
|
||
scene.objects['Task_text']['Text']=missions_task[str(scene.objects['Points']['mission'])][0]
|
||
|
||
##
|
||
# Validation de l'objectif atteint
|
||
##
|
||
|
||
def objectif_control(x,y):
|
||
|
||
# Mission 1
|
||
if scene.objects['Points']['mission']==1:
|
||
if [x,y] in scene.objects['Terrain']['map_aim']: # Aim
|
||
if len(scene.objects['Terrain']['map_tile_beacon'])>=6: # 6 balises posées mini
|
||
return True
|
||
|
||
# Mission 2 (fonction)
|
||
if scene.objects['Points']['mission']==2:
|
||
if [x,y] in scene.objects['Terrain']['map_aim']: # Aim
|
||
if len(scene.objects['Terrain']['map_tile_beacon'])>=6: # 6 balises posées mini
|
||
if scene.objects['Points']['nbligne'] <=40: # 40 lignes de code maxi
|
||
txt=["def mrp_avancer():", "def mrp_avancer() :", "def mrp_avancer ():", "def mrp_avancer () :"] # Présence de "def mrp_avancer():"
|
||
if rp_cmd_txtcount(txt, 1):
|
||
return True
|
||
|
||
# Mission 3 (structure alternative)
|
||
# Le controle de l'objectif est dans la fonction rp_detect().
|
||
|
||
# Mission 4 (boucle en for)
|
||
if scene.objects['Points']['mission']==4:
|
||
if [x,y] in scene.objects['Terrain']['map_aim']: # Aim
|
||
if scene.objects['Points']['nbligne'] <=40: # 40 lignes de code maxi
|
||
txt=["for" ] # Présence de "for i in range" 2x
|
||
if rp_cmd_txtcount(txt, 2):
|
||
txt=["in range" ]
|
||
if rp_cmd_txtcount(txt, 2):
|
||
return True
|
||
else:
|
||
txt=["def mrp_avancer_nbpas"] # Présence de "def mrp_avancer_nbpas"
|
||
if rp_cmd_txtcount(txt, 1):
|
||
txt=["for" ] # Présence de "for i in range" 1x
|
||
if rp_cmd_txtcount(txt, 1):
|
||
txt=["in range" ]
|
||
if rp_cmd_txtcount(txt, 1):
|
||
return True
|
||
|
||
# Mission 5 (boucle en while)
|
||
if scene.objects['Points']['mission']==5:
|
||
if [x,y] in scene.objects['Terrain']['map_aim']: # Aim
|
||
if scene.objects['Points']['nbligne'] <=40: # 40 lignes de code maxi
|
||
txt=["while" ] # Présence de "while" 2x
|
||
if rp_cmd_txtcount(txt, 2):
|
||
return True
|
||
else:
|
||
txt=["def mrp_avancer_mur():", "def mrp_avancer_mur() :", "def mrp_avancer_mur ():", "def mrp_avancer_mur () :"] # Présence de "def mrp_avancer_mur():"
|
||
if rp_cmd_txtcount(txt, 1):
|
||
txt=["while" ] # Présence de "while" 1x
|
||
if rp_cmd_txtcount(txt, 1):
|
||
return True
|
||
|
||
# Mission 6 (passer sur tout le terrain)
|
||
if scene.objects['Points']['mission']==6:
|
||
# FIXME
|
||
return False
|
||
|
||
return False
|
||
|
||
|
||
###############################################################################
|
||
# Fonction bas niveau
|
||
###############################################################################
|
||
|
||
##
|
||
# Recherche de texte dans le script
|
||
##
|
||
|
||
def rp_cmd_txtcount (text_list, n):
|
||
# print (os.getcwd())
|
||
file = open('rp_cmd.py', 'r')
|
||
file_txt = file.read()
|
||
for text in text_list:
|
||
if file_txt.count (text) >= n:
|
||
file.close()
|
||
return True
|
||
file.close()
|
||
return False
|
||
|
||
##
|
||
# Atteindre une orientation
|
||
##
|
||
|
||
def applyRotationTo(obj, rx=None, ry=None, rz=None, Local=True):
|
||
rres=0.001 # resolution rotation
|
||
|
||
# x
|
||
if rx is not None:
|
||
while (abs(rx-obj.worldOrientation.to_euler().x) > rres) :
|
||
if obj.worldOrientation.to_euler().x-rx > rres:
|
||
obj.applyRotation((-rres, 0, 0), Local)
|
||
if rx-obj.worldOrientation.to_euler().x > rres:
|
||
obj.applyRotation((rres, 0, 0), Local)
|
||
# print ("delta x ",rx-obj.worldOrientation.to_euler().x)
|
||
|
||
# y
|
||
if ry is not None:
|
||
while (abs(ry-obj.worldOrientation.to_euler().y) > rres) :
|
||
if obj.worldOrientation.to_euler().y-ry > rres:
|
||
obj.applyRotation((0, -rres, 0), Local)
|
||
if ry-obj.worldOrientation.to_euler().y > rres:
|
||
obj.applyRotation((0, rres, 0), Local)
|
||
# print ("delta y ",ry-obj.worldOrientation.to_euler().y)
|
||
|
||
# z
|
||
if rz is not None:
|
||
while (abs(rz-obj.worldOrientation.to_euler().z) > rres) :
|
||
if obj.worldOrientation.to_euler().z-rz > rres:
|
||
obj.applyRotation((0, 0, -rres), Local)
|
||
if rz-obj.worldOrientation.to_euler().z > rres:
|
||
obj.applyRotation((0, 0, rres), Local)
|
||
# print ("delta z ",rz-obj.worldOrientation.to_euler().z)
|