codetower/ct.py
2022-04-12 01:45:23 +02:00

988 lines
47 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# import importlib
# import imp
import bge # Blender Game Engine (UPBGE)
import bpy # Blender
import aud # Sounds
import math
import mathutils
import time
import sys
import os
import webbrowser
import threading # Multithreading
import xml.etree.ElementTree as ET # Creating/parsing XML file
import runpy
import ct_map1 as ct_map # waves script
# import ct_cmd # user script (commands)
###############################################################################
# ct.py
# @title: the CodeTower game
# @project: CodeTower
# @lang: fr,en
# @authors: Philippe Roy <phroy@phroy.org>
# @copyright: Copyright (C) 2022 Philippe Roy
# @license: GNU GPL
#
# This game is a tower defense coding game. The towers are driven by Python code.
# Ce simulateur est un jeu du type tower defense où les tours sont à piloter par la programmation Python.
#
# Commands trigged by button : cmd_*
# Commands trigged by 3D scene objects : scn_*
# Commands trigged by user (student or map designer) : ct_*
# 3D scene manipulation : manip_*
#
###############################################################################
sys.setrecursionlimit(10**5) # Limite sur la récursivité (valeur par défaut : 1000) -> segfault de Blender
# Dynamic import user file
# importlib.invalidate_caches()
# ct_map = importlib.import_module('ct_map1') # Waves script
# ct_cmd = importlib.import_module('ct_cmd') # User script (commands) -> segfault de Blender
# UPBGE scene
scene = bge.logic.getCurrentScene()
eevee = bpy.context.scene.eevee
fps_time=0.0
# Config file
# print (os.getcwd())
ct_config = ET.parse('ct_config.xml')
ct_config_tree = ct_config.getroot()
# Colors
color_magenta = (0.800, 0.005, 0.315,1)
color_orange = (0.799, 0.130, 0.063,1)
color_white = (0.8, 0.8, 0.8, 1)
color_yellow = (0.8, 0.619, 0.021, 1)
color_black = (0, 0, 0, 1)
color_kaykit_black = (0.019, 0.032, 0.037, 1)
color_endbanner_bluelight = (0.361, 0.527, 0.716, 1)
color_endbanner_bluedark = (0.130, 0.254, 0.407, 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)
color_cmd = (0.8, 0.8, 0.8, 1) # blanc
color_cmd_hl = (0.8, 0.619, 0.021, 1) # jaune
# color_link = (0.024, 0.006, 0.8, 1) # bleu
# color_link_hl = (0.8, 0.005, 0.315, 1) # majenta
color_link = (0.799, 0.617, 0.021, 1)
color_link_hl = (0.8, 0.8, 0.8, 1)
# Sounds
audiodev = aud.Device()
snd_click = aud.Sound('asset/sounds/click.ogg')
sndbuff_click = aud.Sound.cache(snd_click)
snd_construct = aud.Sound('asset/sounds/click_construct.ogg')
sndbuff_construct = aud.Sound.cache(snd_construct)
# 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
###############################################################################
# Tour
###############################################################################
# Commande pour afficher la position de la tour de construction
def cmd_tower_construct(cont):
obj = cont.owner
obj_Hl= scene.objects[obj.name+"-Hl"]
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['Terrain']['manip_mode']==0:
audiodev.play(sndbuff_construct)
if scene.objects['Terrain']['construct_mode']==True:
scene.objects['Terrain']['construct_mode']=False
obj.worldScale=[1, 1, 1]
obj.color = color_cmd
obj_Hl.worldScale=[1, 1, 1]
obj_Hl.color = color_cmd
scene.objects['Tower_construc_mode'].setVisible(False,False)
scene.objects['Tower_construc_mode'].color = color_cmd
text_info ("")
else:
scene.objects['Terrain']['construct_mode']=True
obj.worldScale=[1.25, 1.25, 1.25]
obj.color = color_cmd_hl
obj_Hl.worldScale=[1.25, 1.25, 1.25]
obj_Hl.color = color_cmd_hl
scene.objects['Tower_construc_mode'].setVisible(True,False)
scene.objects['Tower_construc_mode'].color = color_cmd
text_info ("Tower position : ")
###############################################################################
# User interface : texte info et compteurs
###############################################################################
# Affichage sur la boite de texte sur 6 lignes
def text_info (text):
if text=="":
scene.objects['Text_info-1'].setVisible(False,False)
scene.objects['Text_info-2'].setVisible(False,False)
else:
lines_txt=text.split("\n", 6)
for i in range (len(lines_txt),6):
lines_txt.append("")
scene.objects['Text_info-1'].setVisible(True,False)
scene.objects['Text_info-2'].setVisible(True,False)
scene.objects['Text_info-1']['Text']=lines_txt[0]+"\n"+lines_txt[1]+"\n"+lines_txt[2]
scene.objects['Text_info-2']['Text']=lines_txt[3]+"\n"+lines_txt[4]+"\n"+lines_txt[5]
# Mise à jour de l'affichage des compteurs
def points_maj (cont):
global fps_time
# Synchronisation des threads
while scene.objects['Terrain']['thread_cmd_lock'] == True:
# print ("UPBGE : thread_cmd_lock =True")
time.sleep(0.01)
# Texte
scene.objects['Lifes_text']['Text']=str(scene.objects['Points']['lifes'])+"/"+str(scene.objects['Points']['lifes_max'])
scene.objects['Coins_text']['Text']=str(scene.objects['Points']['coins'])
scene.objects['Level_text']['Text']=str(scene.objects['Points']['level'])+"/"+str(scene.objects['Points']['level_max'])
scene.objects['Minions_text']['Text']=str(scene.objects['Points']['minions'])
scene.objects['Points']['tics'] +=1
# Texte de la vague
if scene.objects['Map_text']['anim']:
if scene.objects['Map_text']['timer']>0:
scene.objects['Map_text'].worldPosition.x = scene.objects['Map_text']['position_init'][0]+(scene.objects['Map_text']['position_end'][0]-scene.objects['Map_text']['position_init'][0])*(scene.objects['Map_text']['timer']/120)
scene.objects['Map_text'].worldPosition.y = scene.objects['Map_text']['position_init'][1]+(scene.objects['Map_text']['position_end'][1]-scene.objects['Map_text']['position_init'][1])*(scene.objects['Map_text']['timer']/120)
scene.objects['Map_text'].worldPosition.z = scene.objects['Map_text']['position_init'][2]+(scene.objects['Map_text']['position_end'][2]-scene.objects['Map_text']['position_init'][2])*(scene.objects['Map_text']['timer']/120)
scene.objects['Map_text']['timer']-=1
if scene.objects['Map_text']['timer']==0:
scene.objects['Map_text'].color = color_text
scene.objects['Map_text'].worldPosition= scene.objects['Map_text']['position_end']
scene.objects['Map_text']['anim']=False
# Gestion du FPS
if scene.objects['Commands']['debug_fps']:
if scene.objects['Points']['tics']%60 ==0: # Toutes les 60 tics
milliseconds = int(time.time() * 1000)
print (milliseconds-fps_time)
print ("Tics/second, coins :", milliseconds-fps_time, str(scene.objects['Points']['coins']))
fps_time = milliseconds
# Augmentation d'un niveau
if scene.objects['Points']['coins']>=100:
scene.objects['Points']['level_max'] +=1
scene.objects['Points']['coins'] -=100
# Level trop élevé
if scene.objects['Points']['level'] > scene.objects['Points']['level_max'] :
scene.objects['Level_text'].color = color_text_red
if scene.objects['Points']['level'] < scene.objects['Points']['level_max'] :
scene.objects['Level_text'].color = color_text_yellow
if scene.objects['Points']['level'] == scene.objects['Points']['level_max']:
scene.objects['Level_text'].color = color_text
# Ramasse minions perdues ou zombis
if scene.objects['Terrain']['run'] == True: # Pas en pause
if scene.objects['Points']['tics']%240 == 0: # Toutes les 4 secondes
scene.objects['Points']['minions_lost']=[]
for obj_i in scene.objects:
if "type_minion" in obj_i.getPropertyNames() and "type_towerminion" not in obj_i.getPropertyNames():
# print ("Minion lost : (dist, dist_old, x, last_x, y, last_y) : ", obj_i.name, obj_i['dist'], obj_i['dist_old'], obj_i.worldPosition.x, obj_i['dist_last_x'], obj_i.worldPosition.y, obj_i['dist_last_y'])
if obj_i['dist']==obj_i['dist_old'] and obj_i['dist_new']==False:
print ("Minion lost : dist =dist_old (dist, dist_old) : ", obj_i.name, obj_i['dist'], obj_i['dist_old'])
obj_i['dead']=True
elif obj_i.worldLinearVelocity.x >0 and abs(obj_i.worldLinearVelocity.x) < 0.001 and obj_i.worldLinearVelocity.y >0 and abs(obj_i.worldLinearVelocity.y) < 0.001:
print ("Minion lost : x' or y' very slow (x, y, z, x', y') : ", obj_i.name, obj_i.worldPosition.x, obj_i.worldPosition.y, obj_i.worldPosition.z, abs(obj_i.worldLinearVelocity.x), abs(obj_i.worldLinearVelocity.y))
obj_i['dead']=True
elif obj_i.worldPosition.x<scene.objects['Terrain']['size'][0] or obj_i.worldPosition.x>scene.objects['Terrain']['size'][1] or obj_i.worldPosition.y<scene.objects['Terrain']['size'][2] or obj_i.worldPosition.y>scene.objects['Terrain']['size'][3]:
print ("Minion lost : x or y outside the map (x, y, z, x', y') : ", obj_i.name, obj_i.worldPosition.x, obj_i.worldPosition.y, obj_i.worldPosition.z, abs(obj_i.worldLinearVelocity.x), abs(obj_i.worldLinearVelocity.y))
obj_i['dead']=True
obj_i['dist_old'] = obj_i['dist']
obj_i['dist_new']=False
# Fin de la vague
if scene.objects['Terrain']['thread_wave']==False and scene.objects['Terrain']['map_run'] == True :
if scene.objects['Points']['minions_run']==0 :
# Fin ou vague suivante
if scene.objects['Points']['lifes'] == 0 or scene.objects['Points']['wave'] == scene.objects['Terrain']['nb_waves'] :
terrain_end ()
else:
scene.objects['Points']['minions']=0
scene.objects['Points']['wave'] +=1
ct_map.start(scene.objects['Points']['wave']) # Lancement du script de la vague
###############################################################################
# Terrain
###############################################################################
# Mouse over du terrain
def scn_terrain_mo (cont):
# Affiche la position de la tour de construction
if scene.objects['Terrain']['construct_mode']==True:
hitObject = cont.sensors['MO'].hitObject
hitPosition = cont.sensors['MO'].hitPosition
if hitObject is not None :
if round(hitPosition.x) >= scene.objects['Terrain']['size'][0] and round(hitPosition.x) <= scene.objects['Terrain']['size'][1] and round(hitPosition.y) >= scene.objects['Terrain']['size'][2] and round(hitPosition.y) <= scene.objects['Terrain']['size'][3] :
if [round(hitPosition.x),round(hitPosition.y)] in scene.objects['Terrain']['scene_tile_noncontruct'] or [round(hitPosition.x),round(hitPosition.y)] in scene.objects['Terrain']['scene_tile_tower']:
pass
else:
scene.objects['Tower_construc_mode'].worldPosition.x=round(hitPosition.x)
scene.objects['Tower_construc_mode'].worldPosition.y=round(hitPosition.y)
scene.objects['Tower_construc_mode'].worldPosition.z=0.2
text_info ("Tower position : "+str(round(hitPosition.x))+","+str(round(hitPosition.y)))
# Affiche les informations sur la tour
# FIXME : High-light sur la tower sélectionnée
else:
hitPosition = cont.sensors['MO'].hitPosition
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['Terrain']['manip_mode']==0:
if [round(hitPosition.x),round(hitPosition.y)] in scene.objects['Terrain']['scene_tile_tower']:
for obj_i in scene.objects:
if "type_tower" in obj_i.getPropertyNames():
if round(hitPosition.x) == obj_i.worldPosition.x and round(hitPosition.y) == obj_i.worldPosition.y:
text =obj_i['tower_name'] + "\n" + "- level : "+ str(obj_i['lvl']) + "\n" + "- damage : "+ str(obj_i['damage']) + "\n" + "- speed : "+ str(round(obj_i['speed'],2)) + "\n" + "- range : "+ str(obj_i['range'])
text_info (text)
break
else:
text_info ("")
# Initialisation lors du chargement du terrain
def terrain_init (cont):
# Cacher la bannière de fin
scene.objects['End'].setVisible(False,True)
scene.objects['End']['timer']=0
# Pile des draws
scene.objects['Terrain']['draw_process']=False
scene.objects['Terrain']['draw_list']=[]
# Ramasse-miettes
scene.objects['Points']['minions_lost']=[]
# Configuration du moteur de rendu
eevee.use_eevee_smaa = False
if scene.objects['Terrain']['speed']<10: # smaa avec en vitesse 4 et 10 -> tendance au plantage
eevee.use_eevee_smaa = True
# Recherche les tuiles non constructibles (chemin)
scene.objects['Terrain']['scene_tile_noncontruct'] = []
for obj_i in scene.objects:
if "tile_straight" in obj_i.name:
scene.objects['Terrain']['scene_tile_noncontruct'].append([obj_i.worldPosition.x, obj_i.worldPosition.y])
obj_i.collisionGroup=2
if "tile_cornerRound" in obj_i.name:
scene.objects['Terrain']['scene_tile_noncontruct'].append([obj_i.worldPosition.x, obj_i.worldPosition.y])
obj_i.collisionGroup=2
if "tile_hill" in obj_i.name:
obj_i.collisionGroup=2
scene.objects['Terrain']['scene_tile_tower']= []
# Init de la carte
ct_map.map_init()
ct_map.map_reset()
scene.objects['Level_text'].color = color_text
# Mise en route et pause du cycle
def terrain_run ():
audiodev.play(sndbuff_click)
# Pause
if scene.objects['Terrain']['run'] == True:
scene.objects['Terrain']['run']=False
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Run-Hl'].setVisible(True,False)
for obj_i in scene.objects: # Pause des Steerings
if "type_minion" in obj_i.getPropertyNames() and "type_towerminion" not in obj_i.getPropertyNames():
obj_i.actuators['Steering'].velocity=0
# Run
else :
scene.objects['Terrain']['run']=True
scene.objects['Run'].setVisible(False,False)
scene.objects['Run-Hl'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(True,False)
# Démarrage de la map
if scene.objects['Terrain']['thread_run']==False:
scene.objects['Stop'].setVisible(True,False)
runpy.run_module('ct_cmd', run_name='stop') # Stop du script utilisateur
ct_map.stop() # Stop du script des vagues
# Mise à zéro des compteurs
ct_map.map_reset()
# Supprimer les tours
for obj_i in scene.objects:
if "type_tower" in obj_i.getPropertyNames() :
obj_i.endObject()
if "type_towerminion" in obj_i.getPropertyNames() :
obj_i.endObject()
scene.objects['Terrain']['scene_tile_tower']= []
# Scripts utilisateur et vagues
scene.objects['Terrain']['map_run'] = True
scene.objects['Terrain']['thread_run']=True
scene.objects['Points']['time_begin']=time.localtime()
# scene.objects['Commands']['cmd_start']=True
# Execution du script utilisateur par importlib -> Segfault de Blender
# importlib.reload(ct_cmd)
# ct_cmd.start() # Execution du script utilisateur
runpy.run_module('ct_cmd', run_name='start') # Execution du script utilisateur
ct_map.start(1) # Lancement du script de la permière vague
# Arrêt de la pause
else:
for obj_i in scene.objects: # Relance des Steerings
if "type_minion" in obj_i.getPropertyNames() and "type_towerminion" not in obj_i.getPropertyNames():
obj_i.actuators['Steering'].velocity=obj_i['speed_base']*scene.objects['Terrain']['speed']
# Arrêt et réinitialisation du cycle
def terrain_stop ():
audiodev.play(sndbuff_click)
# Arrêt des threads utilisateurs
scene.objects['Terrain']['run']=False
scene.objects['Terrain']['thread_run']=False
scene.objects['Terrain']['map_run'] = False # Ne pas afficher la bannière de fin
runpy.run_module('ct_cmd', run_name='stop') # Stop du script utilisateur
ct_map.stop() # Stop du script des vagues
# Supprimer les enemis
for obj_i in scene.objects:
if "type_minion" in obj_i.getPropertyNames() and "type_towerminion" not in obj_i.getPropertyNames():
obj_i.endObject()
scene.objects['Points']['minions']=0
scene.objects['Points']['minions_run']=0
# Commandes
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Run'].setVisible(True,False)
scene.objects['Stop'].setVisible(False,False)
scene.objects['Stop-Hl'].setVisible(False,False)
# Fin de la map
def terrain_end ():
scene.objects['Terrain']['run']=False
scene.objects['Terrain']['thread_run']=False
# Commandes
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Run'].setVisible(True,False)
scene.objects['Stop'].setVisible(False,False)
scene.objects['Stop-Hl'].setVisible(False,False)
# Affichage des résultats
if scene.objects['End']['timer']== 0:
scene.objects['Terrain']['manip_mode']=9 # Fenêtre modale
scene.objects['Camera'].worldPosition.x = scene.objects['Camera']['init_lx']
scene.objects['Camera'].worldPosition.y = scene.objects['Camera']['init_ly']
scene.objects['Camera'].worldPosition.z = scene.objects['Camera']['init_lz']
# Wave
if scene.objects['Points']['wave']== scene.objects['Terrain']['nb_waves'] and scene.objects['Points']['lifes'] > 0:
scene.objects['Endbanner_wave']['Text']="Victory"
else:
scene.objects['Endbanner_wave']['Text']="Wave \n"+str(scene.objects['Points']['wave'])
# Time
maptime_mn=time.localtime().tm_min-scene.objects['Points']['time_begin'].tm_min
maptime_sec=time.localtime().tm_sec-scene.objects['Points']['time_begin'].tm_sec
if maptime_sec<0:
maptime_mn-=1
maptime_sec+=60
if maptime_mn<=99:
scene.objects['Endbanner_points']['Text']="Level "+str(scene.objects['Points']['level_max'])+"\n Time "+ str(maptime_mn)+"'"+ str(maptime_sec)+"\""
else:
scene.objects['Endbanner_points']['Text']="Level "+str(scene.objects['Points']['level_max'])+"\n Time "+ str(maptime_mn)+"'"
# Object 3D
scene.objects['Endbanner'].color = color_endbanner_bluelight
scene.objects['Endbanner_wave'].color = color_black
scene.objects['Endbanner_points'].color = color_black
scene.objects['Endbanner_ok'].color = color_black
scene.objects['End'].setVisible(True,True)
scene.objects['End'].worldPosition = [0, 1.53623, -1.8]
scene.objects['End']['timer'] = 0
scene.objects['End']['anim'] = True
# Animation
pas=0.5
scene.objects['End'].localPosition.y -= pas
scene.objects['End'].localPosition.z += (0.85*pas)
# scene.objects['End'].localPosition.y=scene.objects['End'].localPosition.y-1*pas
# scene.objects['End'].localPosition.z=scene.objects['End'].localPosition.z+0.85*pas
scene.objects['End']['timer']+=1
if scene.objects['End']['timer']== 40:
scene.objects['Terrain']['map_run'] = False
# Vitesse du jeu
def terrain_speed (obj):
audiodev.play(sndbuff_click)
speed_mode=[0.25, 0.5, 1,2,4,10]
speed_mode_txt=["1/4", "1/2", "1", "2","4","10"]
i=speed_mode.index(scene.objects['Terrain']['speed'])
# Affichage
if obj.name=="Speed_up" and i<5:
scene.objects['Terrain']['speed']=speed_mode[i+1]
scene.objects['Text_speed']['Text']=speed_mode_txt[i+1]
if obj.name=="Speed_down" and i>0:
scene.objects['Terrain']['speed']=speed_mode[i-1]
scene.objects['Text_speed']['Text']=speed_mode_txt[i-1]
# Maj des Nears (Towers) et des Steerings (Minions)
for obj_i in scene.objects:
if "type_tower" in obj_i.getPropertyNames() and "Near" in obj_i.sensors :
obj_i.sensors['Near'].skippedTicks =round(1/(obj_i['speed']*scene.objects['Terrain']['speed']))
if scene.objects['Terrain']['run'] == True: # Pas en pause
if "type_minion" in obj_i.getPropertyNames() and "type_towerminion" not in obj_i.getPropertyNames():
obj_i.actuators['Steering'].velocity=obj_i['speed_base']*scene.objects['Terrain']['speed']
# Configuration du moteur de rendu
if scene.objects['Terrain']['speed']<10: # smaa avec en vitesse 4 et 10 -> tendance au plantage
eevee.use_eevee_smaa = True
else:
eevee.use_eevee_smaa = False
# Maj du fichier de config (vitesse du jeu : data/config/speed)
ct_config_tree[0][0].text=str(scene.objects['Terrain']['speed'])
buffer_xml = ET.tostring(ct_config_tree)
with open("ct_config.xml", "wb") as f:
f.write(buffer_xml)
# Page de fin
def endbanner_hl(cont):
if cont.sensors['MO'].status == JUST_ACTIVATED:
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_up()
scene.objects['Endbanner'].color = color_white
scene.objects['Endbanner_wave'].color = color_white
scene.objects['Endbanner_points'].color = color_white
scene.objects['Endbanner_ok'].color = color_white
if cont.sensors['MO'].status == JUST_RELEASED:
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_down()
scene.objects['Endbanner'].color = color_endbanner_bluelight
scene.objects['Endbanner_wave'].color = color_black
scene.objects['Endbanner_points'].color = color_black
scene.objects['Endbanner_ok'].color = color_black
def endbanner_close(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
audiodev.play(sndbuff_click)
scene.objects['Terrain']['manip_mode']=0
scene.objects['End'].setVisible(False,True)
scene.objects['End'].worldPosition = [20, 1.53623, -0.892838]
scene.objects['Endbanner'].color = [0.592, 0.68, 0.407, 1]
scene.objects['Endbanner_wave'].color = color_black
scene.objects['Endbanner_points'].color = color_black
scene.objects['End']['timer']= 0
###############################################################################
# Commandes
###############################################################################
# Init
def cmd_init():
# scene.objects['Terrain']['run']=False
# UI : Commandes
scene.objects['Run-Hl'].setVisible(False,False)
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Stop'].setVisible(False,False)
scene.objects['Stop-Hl'].setVisible(False,False)
scene.objects['Construc-Hl'].setVisible(False,False)
scene.objects['About-cmd-Hl'].setVisible(False,False)
scene.objects['About'].setVisible(False,True)
# UI : Texte, ...
scene.objects['Map_text'].setVisible(False,False)
scene.objects['Text_info-1'].setVisible(False,False)
scene.objects['Text_info-2'].setVisible(False,False)
scene.objects['Tower_construc_mode'].setVisible(False,False)
scene.objects['Terrain']['map_run'] = False
# UI : Mouse
# Window size : 738.5 415.5
if scene.objects['Mouse_main']['mouse_graphic']:
bge.render.setMousePosition(int(bge.render.getWindowWidth() / 2), int(bge.render.getWindowHeight() / 2))
bge.render.showMouse(scene.objects['Commands']['debug_mouse'])
scene.objects['Mouse_main'].worldPosition = [0.07, -8.11, 4.71035] # Vielle version : [0.118161, -8.24305, 4.71035] ; [0, -3.5, 2], [0, -8, 6]
scene.objects['Mouse_main'].worldScale=[30, 30, 30]
scene.objects['Mouse_main']['past_x']=0
scene.objects['Mouse_main']['past_y']=0
scene.objects['Mouse_main']['mouse_up']=0
else:
scene.objects['Mouse_main'].setVisible(False,False)
bge.render.showMouse(True)
# scene.objects['Raz-vue-Hl'].setVisible(False,False)
# scene.objects['Aide-cmd-Hl'].setVisible(False,False)
# Récupérer la config (vitesse du jeu : data/config/speed)
speed_mode=[0.25, 0.5, 1,2,4,10]
speed_mode_txt=["1/4", "1/2", "1", "2","4","10"]
scene.objects['Terrain']['speed']=float(ct_config_tree[0][0].text)
i=speed_mode.index(scene.objects['Terrain']['speed'])
scene.objects['Text_speed']['Text']=speed_mode_txt[i]
# Le highlight des commandes
def cmd_hl(cont):
obj = cont.owner
# Activation
if cont.sensors['MO'].status == JUST_ACTIVATED and scene.objects['Terrain']['manip_mode']==0:
if obj.name!="Run" and obj.name!="Pause" and obj.name!="Run-Hl" and obj.name!="Pause-Hl" and obj.name!="Stop" and obj.name!="Stop-Hl" :
obj.setVisible(False,True)
scene.objects[obj.name+'-Hl'].setVisible(True,True)
# Run et pause
if obj.name=="Pause" or obj.name=="Run":
if scene.objects['Terrain']['run'] == True:
scene.objects['Pause'].setVisible(False,False)
scene.objects['Pause-Hl'].setVisible(True,False)
else:
scene.objects['Run'].setVisible(False,False)
scene.objects['Run-Hl'].setVisible(True,False)
# Stop
if obj.name=="Stop":
if scene.objects['Terrain']['thread_run']==True:
scene.objects['Stop'].setVisible(False,False)
scene.objects['Stop-Hl'].setVisible(True,False)
# Désactivation
if cont.sensors['MO'].status == JUST_RELEASED and (scene.objects['Terrain']['manip_mode']==0 or scene.objects['Terrain']['manip_mode']==9):
if obj.name!="Run" and obj.name!="Pause" and obj.name!="Run-Hl" and obj.name!="Pause-Hl" and obj.name!="Stop" and obj.name!="Stop-Hl" :
scene.objects[obj.name+'-Hl'].setVisible(False,True)
obj.setVisible(True,True)
# Run et pause
if obj.name=="Pause" or obj.name=="Run":
if scene.objects['Terrain']['run'] == True:
scene.objects['Pause-Hl'].setVisible(False,False)
scene.objects['Pause'].setVisible(True,False)
else:
scene.objects['Run-Hl'].setVisible(False,False)
scene.objects['Run'].setVisible(True,False)
# Stop
if obj.name=="Stop":
if scene.objects['Terrain']['thread_run']==True:
scene.objects['Stop-Hl'].setVisible(False,False)
scene.objects['Stop'].setVisible(True,False)
# Click sur les commandes
def cmd_click (cont):
obj = cont.owner
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['Terrain']['manip_mode']==0:
if obj.name=="Pause" or obj.name=="Run": # FIXME problème sur l'icone pause
terrain_run ()
if obj.name=="Stop":
terrain_stop ()
if obj.name=="Speed_up" or obj.name=="Speed_down":
terrain_speed (obj)
if obj.name=="About-cmd":
about_open ()
###############################################################################
# Gestion du clavier
###############################################################################
# Mode :
# 0 : rien (par défaut)
# 1 : Pan avec Shift
# 2 : Zoom avec Ctrl
# 9 : Fenêtre modale
def mode(cont):
obj = cont.owner
keyboard = bge.logic.keyboard
# Touche ESC
if JUST_ACTIVATED in keyboard.inputs[bge.events.ESCKEY].queue:
terrain_stop ()
bge.logic.endGame()
# Fenêtre modale
if scene.objects['Terrain']['manip_mode']==9:
return
# Shift -> mode 1 : Pan (clic milieu)
if JUST_ACTIVATED in keyboard.inputs[bge.events.LEFTSHIFTKEY].queue:
obj['manip_mode']=1
if JUST_ACTIVATED in keyboard.inputs[bge.events.RIGHTSHIFTKEY].queue:
obj['manip_mode']=1
# Ctrl -> mode 2 : Zoom (clic milieu)
if JUST_ACTIVATED in keyboard.inputs[bge.events.LEFTCTRLKEY].queue:
obj['manip_mode']=2
if JUST_ACTIVATED in keyboard.inputs[bge.events.RIGHTCTRLKEY].queue:
obj['manip_mode']=2
# Pas de modificateur -> mode 0 : Pas de Orbit (mode 0) ici
if JUST_RELEASED in keyboard.inputs[bge.events.LEFTSHIFTKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.RIGHTSHIFTKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.LEFTCTRLKEY].queue:
obj['manip_mode']=0
if JUST_RELEASED in keyboard.inputs[bge.events.RIGHTCTRLKEY].queue:
obj['manip_mode']=0
# Touche Home -> Reset de la vue
if JUST_ACTIVATED in keyboard.inputs[bge.events.HOMEKEY].queue:
scene.objects['Camera'].worldPosition.x = scene.objects['Camera']['init_lx']
scene.objects['Camera'].worldPosition.y = scene.objects['Camera']['init_ly']
scene.objects['Camera'].worldPosition.z = scene.objects['Camera']['init_lz']
applyRotationTo(scene.objects['Terrain'], 0, 0, 0)
if scene.objects['Mouse_main']['mouse_graphic']:
bge.render.setMousePosition(int(bge.render.getWindowWidth() / 2), int(bge.render.getWindowHeight() / 2))
scene.objects['Mouse_main'].worldPosition = [0.07, -8.11, 4.71035] # Vielle version : [0.118161, -8.24305, 4.71035] ; [0, -3.5, 2], [0, -8, 6]
scene.objects['Mouse_main'].worldScale=[30, 30, 30]
scene.objects['Mouse_main']['past_x']=0
scene.objects['Mouse_main']['past_y']=0
# Touche F5 -> Run et Pause
if JUST_ACTIVATED in keyboard.inputs[bge.events.F5KEY].queue:
terrain_run ()
# Touche F6 -> Stop / Init
if JUST_ACTIVATED in keyboard.inputs[bge.events.F6KEY].queue:
if scene.objects['Terrain']['thread_run']==True:
terrain_stop ()
# Touche +/- du pad -> Vitesse + ou /
if JUST_ACTIVATED in keyboard.inputs[bge.events.PADPLUSKEY].queue:
terrain_speed (scene.objects['Speed_up'])
if JUST_ACTIVATED in keyboard.inputs[bge.events.PADMINUS].queue:
terrain_speed (scene.objects['Speed_down'])
###############################################################################
# Manipulation 3D de la scène
###############################################################################
# Mémorisation de la position et orientation initiales du modèle 3D et de la caméra
def manip_init(cont):
scene.objects['Camera']['init_lx']=scene.objects['Camera'].worldPosition.x
scene.objects['Camera']['init_ly']=scene.objects['Camera'].worldPosition.y
scene.objects['Camera']['init_lz']=scene.objects['Camera'].worldPosition.z
scene.objects['Camera']['past_lx']=scene.objects['Camera'].worldPosition.x
scene.objects['Camera']['past_ly']=scene.objects['Camera'].worldPosition.y
scene.objects['Camera']['past_lz']=scene.objects['Camera'].worldPosition.z
scene.objects['Terrain']['init_lx']=scene.objects['Terrain'].worldPosition.x
scene.objects['Terrain']['init_ly']=scene.objects['Terrain'].worldPosition.y
scene.objects['Terrain']['init_lz']=scene.objects['Terrain'].worldPosition.z
scene.objects['Terrain']['init_rx']=scene.objects['Terrain'].worldOrientation.to_euler().x
scene.objects['Terrain']['init_ry']=scene.objects['Terrain'].worldOrientation.to_euler().y
scene.objects['Terrain']['init_rz']=scene.objects['Terrain'].worldOrientation.to_euler().z
# Atteindre une orientation (bas niveau)
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)
# Reset de la manipulation de la vue
def manip_reset(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['Terrain']['manip_mode']==0:
scene.objects['Camera'].worldPosition.x = scene.objects['Camera']['init_lx']
scene.objects['Camera'].worldPosition.y = scene.objects['Camera']['init_ly']
scene.objects['Camera'].worldPosition.z = scene.objects['Camera']['init_lz']
applyRotationTo(scene.objects['Terrain'], 0, 0, 0)
# Position de départ pour la manipulation de la vue
def manip_start(cont):
if scene.objects['Terrain']['manip_mode']!=9:
obj = cont.owner
obj['click_x']=cont.sensors['ClickM'].position[0]
obj['click_y']=cont.sensors['ClickM'].position[1]
# Cacher le cercle de la manipulation Orbit
def manip_stop(cont):
# scene.objects['Orbit'].setVisible(False,False)
pass
# Manipulation du modèle ou de la caméra
def manip(cont):
obj = cont.owner
sensibilite_orbit=0.00005 # Base : 0.0005
sensibilite_pan=0.001 # Base : 0.005
sensibilite_zoom=0.005 # Base : 0.01
delta_x=cont.sensors['DownM'].position[0]-obj['click_x']
delta_y=cont.sensors['DownM'].position[1]-obj['click_y']
# Pan
if obj['manip_mode']==1: # Shift
scene.objects['Camera'].applyMovement((delta_x*-sensibilite_pan, delta_y*sensibilite_pan, 0), True)
if scene.objects['Mouse_main']['mouse_graphic']:
scene.objects['Mouse_main'].applyMovement((delta_x*-sensibilite_pan, delta_y*sensibilite_pan, 0), True)
# Zoom FIXME : marche pas au niveau de la souris
if obj['manip_mode']==2: # Ctrl
if scene.objects['Mouse_main']['mouse_graphic']:
position_scale_x = 0.0005
position_scale_y = position_scale_x
mouse_x=scene.objects['Mouse_main'].sensors["Mouse"].position[0]-int(bge.render.getWindowWidth() / 2)
mouse_y=scene.objects['Mouse_main'].sensors["Mouse"].position[1]-int(bge.render.getWindowHeight() / 2)
distance_cam_past= math.sqrt(scene.objects['Camera']['past_ly']**2+scene.objects['Camera']['past_lz']**2)
distance_cam = math.sqrt((scene.objects['Camera'].worldPosition.y**2+scene.objects['Camera'].worldPosition.z**2))
size_scale = (distance_cam/distance_cam_past) * 0.23
scene.objects['Camera'].applyMovement((0, 0, (delta_x+delta_y)*sensibilite_zoom), True)
if scene.objects['Mouse_main']['mouse_graphic']:
scene.objects['Mouse_main'].applyMovement((mouse_x*(delta_x+delta_y)*sensibilite_zoom*position_scale_x, -mouse_y*(delta_x+delta_y)*sensibilite_zoom*position_scale_y, 0), True)
scene.objects['Mouse_main'].worldScale *= (delta_x+delta_y)*sensibilite_zoom*size_scale
scene.objects['Camera']['past_ly']=scene.objects['Camera'].worldPosition.y
scene.objects['Camera']['past_lz']=scene.objects['Camera'].worldPosition.z
# Manipulation du modèle ou de la caméra
def manip_wheel(cont):
if scene.objects['Terrain']['manip_mode']!=9: # Fenêtre modale
obj = cont.owner
sensibilite_wheel = 5 # Base : 20
if scene.objects['Mouse_main']['mouse_graphic']:
position_scale_x = 0.0005
position_scale_y = position_scale_x
mouse_x=scene.objects['Mouse_main'].sensors["Mouse"].position[0]-int(bge.render.getWindowWidth() / 2)
mouse_y=scene.objects['Mouse_main'].sensors["Mouse"].position[1]-int(bge.render.getWindowHeight() / 2)
distance_cam_past = math.sqrt((scene.objects['Camera'].worldPosition.y**2+scene.objects['Camera'].worldPosition.z**2))
# size_scale = (distance_cam/distance_cam_past) * 0.23
size_scale = 0.2
# size_scale = 0.23
if cont.sensors['WheelUp'].positive:
scene.objects['Camera'].applyMovement((0, 0, -sensibilite_wheel), True)
if scene.objects['Mouse_main']['mouse_graphic']:
distance_cam = math.sqrt((scene.objects['Camera'].worldPosition.y**2+scene.objects['Camera'].worldPosition.z**2))
scene.objects['Mouse_main'].applyMovement((-mouse_x*sensibilite_wheel*position_scale_x, mouse_y*sensibilite_wheel*position_scale_y, 0), True)
scene.objects['Mouse_main'].worldScale *= sensibilite_wheel* (distance_cam/distance_cam_past) *size_scale
elif cont.sensors['WheelDown'].positive:
scene.objects['Camera'].applyMovement((0, 0, sensibilite_wheel), True)
if scene.objects['Mouse_main']['mouse_graphic']:
distance_cam = math.sqrt((scene.objects['Camera'].worldPosition.y**2+scene.objects['Camera'].worldPosition.z**2))
scene.objects['Mouse_main'].applyMovement((mouse_x*sensibilite_wheel*position_scale_x, -mouse_y*sensibilite_wheel*position_scale_y, 0), True)
scene.objects['Mouse_main'].worldScale /= sensibilite_wheel* (distance_cam_past/distance_cam) *size_scale
else:
return
# Icone de la souris
def mouse(cont):
if scene.objects['Mouse_main']['mouse_graphic']==False:
return
obj = cont.owner
# Ancienne version basée sur la position de la caméra
# distance_cam_init= math.sqrt(scene.objects['Camera']['init_ly']**2+scene.objects['Camera']['init_lz']**2)
# distance_cam = math.sqrt((scene.objects['Camera'].worldPosition.y**2+scene.objects['Camera'].worldPosition.z**2))
# ratio = ((distance_cam_init - distance_cam)/distance_cam_init)*1.39 # trop vite -> +, pas assez vite -> -
# scale_x=0.0118-0.0118*ratio
# scale_y=scale_x
# delta_x=cont.sensors["Mouse"].position[0]-obj['past_x']
# delta_y=cont.sensors["Mouse"].position[1]-obj['past_y']
# if delta_x<500 and delta_y<500:
# scene.objects['Mouse_main'].worldPosition.x += delta_x*scale_x
# scene.objects['Mouse_main'].worldPosition.y -= delta_y*scale_y*math.cos(50*2*math.pi*(1/360))
# scene.objects['Mouse_main'].worldPosition.z -= delta_y*scale_y*math.sin(50*2*math.pi*(1/360))
# scene.objects['Mouse_main']['past_x']=cont.sensors["Mouse"].position[0]
# scene.objects['Mouse_main']['past_y']=cont.sensors["Mouse"].position[1]
# Version basée sur obj.getDistanceTo(scene.objects['Camera'])
delta_x=cont.sensors["Mouse"].position[0]-obj['past_x']
delta_y=cont.sensors["Mouse"].position[1]-obj['past_y']
vect=mathutils.Vector((1,1,1))-obj.getVectTo(scene.objects['Camera'])[1]
dist= obj.getDistanceTo(scene.objects['Camera'])
# print ("delta_x, delta_y, vect, dist : ", delta_x, delta_y, vect, dist)
if obj['past_dist']==0:
obj['past_dist']=obj.getDistanceTo(scene.objects['Camera'])
ratio = dist/obj['past_dist']
# print ("delta_x, delta_y, vect, dist : ", delta_x, delta_y, vect, dist)
scale_x=ratio*0.016
scale_y=ratio*0.0162
# scale_xy=ratio*0.0005
scale_xy=ratio*0
if delta_x<500 and delta_y<500:
# scene.objects['Mouse_main'].applyMovement((delta_x*scale_x, -vect[1]*delta_y*scale_y, -vect[1]*delta_y*scale_y), False)
scene.objects['Mouse_main'].applyMovement((delta_x*scale_x+delta_x*delta_y*scale_xy,
-delta_y*scale_y*math.cos(50*2*math.pi*(1/360)),
-delta_y*scale_y*math.sin(50*2*math.pi*(1/360))), False)
obj['past_x']=cont.sensors["Mouse"].position[0]
obj['past_y']=cont.sensors["Mouse"].position[1]
# Mise en avant de la souris
def mouse_up():
scene.objects['Mouse_main']['mouse_up']+=1
if scene.objects['Mouse_main']['mouse_up'] == 1:
decal = 18
size_scale = 0.2
# print (scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1])
vect=scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1]
dist_past= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
scene.objects['Mouse_main'].applyMovement((vect[0]*decal, vect[1]*decal, vect[2]*decal), False)
dist= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
scene.objects['Mouse_main'].worldScale *= (dist/dist_past) *size_scale
scene.objects['Mouse_main'].worldScale=[8, 8, 8]
# Mise en arrière de la souris
def mouse_down():
scene.objects['Mouse_main']['mouse_up']-=1
if scene.objects['Mouse_main']['mouse_up'] == 0:
decal = 18
size_scale = 0.2
# print (scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1])
vect=scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1]
dist_past= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
scene.objects['Mouse_main'].applyMovement((-vect[0]*decal, -vect[1]*decal, -vect[2]*decal), False)
dist= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
scene.objects['Mouse_main'].worldScale /= (dist_past/dist) *size_scale
scene.objects['Mouse_main'].worldScale=[30, 30, 30]
###############################################################################
# About
###############################################################################
def about_open():
scene.objects['Terrain']['manip_mode']=9 # Fenêtre modale
scene.objects['About_title'].color = color_black
scene.objects['About_text'].color = color_black
scene.objects['About_copyright'].color = color_black
scene.objects['About_link_git'].color= color_link
scene.objects['About_link_gpl'].color= color_link
scene.objects['About_link_blender'].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_ok'].color = color_black
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
scene.objects['About']['anim'] = True
def about_open_anim():
pas=0.5
scene.objects['About'].localPosition.y -= pas
scene.objects['About'].localPosition.z += 0.85*pas
# scene.objects['About'].localPosition.y=scene.objects['About'].localPosition.y-1*pas
# scene.objects['About'].localPosition.z=scene.objects['About'].localPosition.z+0.85*pas
scene.objects['About']['timer']+=1
if scene.objects['About']['timer']== 40:
scene.objects['About']['anim'] = False
def about_hl(cont):
# decal = 18
# size_scale = 0.2
if cont.sensors['MO'].status == JUST_ACTIVATED:
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_up()
# # print (scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1])
# vect=scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1]
# dist_past= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
# scene.objects['Mouse_main'].applyMovement((vect[0]*decal, vect[1]*decal, vect[2]*decal), False)
# dist= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
# scene.objects['Mouse_main'].worldScale *= (dist/dist_past) *size_scale
scene.objects['Aboutbanner'].color = color_white
scene.objects['About_ok'].color = color_white
scene.objects['About_title'].color = color_white
# scene.objects['Mouse_main'].worldScale=[8, 8, 8]
# print("about_hl A après", scene.objects['Mouse_main'].worldPosition)
if cont.sensors['MO'].status == JUST_RELEASED:
# print("about_hl R avant", scene.objects['Mouse_main'].worldPosition)
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_down()
# print (scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1])
# vect=scene.objects['Mouse_main'].getVectTo(scene.objects['Camera'])[1]
# dist_past= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
# scene.objects['Mouse_main'].applyMovement((-vect[0]*decal, -vect[1]*decal, -vect[2]*decal), False)
# dist= scene.objects['Mouse_main'].getDistanceTo(scene.objects['Camera'])
# scene.objects['Mouse_main'].worldScale /= (dist_past/dist) *size_scale
scene.objects['Aboutbanner'].color = color_endbanner_bluelight
scene.objects['About_ok'].color = color_black
scene.objects['About_title'].color = color_black
# scene.objects['Mouse_main'].worldScale=[30, 30, 30]
# print("about_hl R après", scene.objects['Mouse_main'].worldPosition)
def about_close(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
audiodev.play(sndbuff_click)
scene.objects['Terrain']['manip_mode']=0
scene.objects['About'].setVisible(False,True)
scene.objects['About'].worldPosition = [22, 1.53623, -0.892838]
scene.objects['Aboutbanner'].color = [0.592, 0.68, 0.407, 1]
scene.objects['About']['timer']= 0
def about_link(cont):
if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive :
obj = cont.owner
if obj.name == "About_link_git-colbox" :
webbrowser.open('https://gitlab.com/phroy/codetower')
if obj.name == "About_link_gpl-colbox" :
webbrowser.open('https://www.gnu.org/licenses/gpl-3.0.html')
if obj.name == "About_link_blender-colbox" :
webbrowser.open('https://www.blender.org')
if obj.name == "About_link_upbge-colbox" :
webbrowser.open('https://www.upbge.org')
if obj.name == "About_link_kay-colbox" :
webbrowser.open('https://www.kaylousberg.com')
if obj.name == "About_link_kenney-colbox" :
webbrowser.open('https://www.kenney.nl')
if obj.name == "About_link_blender-colbox" :
webbrowser.open('https://www.blender.org')
# FIXME: souris graphique trop compliqué
def about_link_hl(cont):
decal = 15
if cont.sensors['MO'].status == JUST_ACTIVATED :
obj = cont.owner
name=obj.name[:-7]
scene.objects[name].color = color_link_hl
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_up()
if cont.sensors['MO'].status == JUST_RELEASED :
obj = cont.owner
name=obj.name[:-7]
scene.objects[name].color = color_link
if scene.objects['Mouse_main']['mouse_graphic']:
mouse_down()