2022-03-11 00:21:00 +01:00
import bge # Bibliothèque Blender Game Engine (UPBGE)
import threading # Multithreading
import trace
import sys
import time
2022-03-20 05:57:07 +01:00
import math
2022-03-11 00:21:00 +01:00
import mathutils
2022-03-20 05:57:07 +01:00
import random
2022-03-23 00:27:11 +01:00
# from ct import * # Bibliothèque CodeTower
2022-03-11 00:21:00 +01:00
###############################################################################
# ct_lib.py
2022-03-20 05:57:07 +01:00
# @title: User library
2022-03-11 00:21:00 +01:00
# @project: CodeTower
2022-03-24 17:00:09 +01:00
# @lang: fr,en
2022-03-11 00:21:00 +01:00
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2022 Philippe Roy
# @license: GNU GPL
#
2022-03-20 05:57:07 +01:00
# Ce simulateur est un jeu du type tower defense où les tours sont à piloter par la programmation Python.
# This game is a tower defense coding game. The towers are driven with Python code.
#
2022-03-11 00:21:00 +01:00
# Commandes déclenchées par les joueurs : ct_*
# Commandes déclenchées par la scene 3D : scn_*
#
###############################################################################
scene = bge . logic . getCurrentScene ( )
2022-03-23 00:27:11 +01:00
# Colors
tower_purple = [ 0.202 , 0.114 , 0.521 , 1 ]
tower_turquoise = [ 0.051 , 0.270 , 0.279 , 1 ]
tower_magenta = [ 0.799 , 0.005 , 0.314 , 1 ]
tower_orange = [ 0.799 , 0.130 , 0.063 , 1 ]
tower_yellow = [ 0.799 , 0.617 , 0.021 , 1 ]
tower_green = [ 0.246 , 0.687 , 0.078 , 1 ]
tower_red = [ 0.799 , 0.031 , 0.038 , 1 ]
2022-03-11 00:21:00 +01:00
###############################################################################
# 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 ( )
2022-03-20 05:57:07 +01:00
print ( " Thread " , type_txt , " # " , len ( threads ) - 1 , " open. " )
2022-03-11 00:21:00 +01:00
def thread_stop ( threads , type_txt ) :
i = 0
zombie_flag = False
for t in threads :
if not t . is_alive ( ) :
2022-03-20 05:57:07 +01:00
print ( " Thread " , type_txt , " # " , i , " closed. " )
2022-03-11 00:21:00 +01:00
else :
2022-03-20 05:57:07 +01:00
print ( " Thread " , type_txt , " # " , i , " still open ... " )
2022-03-11 00:21:00 +01:00
t . kill ( )
t . join ( )
if not t . is_alive ( ) :
2022-03-20 05:57:07 +01:00
print ( " Thread " , type_txt , " # " , i , " killed. " )
2022-03-11 00:21:00 +01:00
else :
2022-03-20 05:57:07 +01:00
print ( " Thread " , type_txt , " # " , i , " zombie... " )
2022-03-11 00:21:00 +01:00
zombie_flag = True
i + = 1
if zombie_flag == False :
2022-03-20 05:57:07 +01:00
print ( " All threads " , type_txt , " are closed. " )
2022-03-11 00:21:00 +01:00
else :
2022-03-20 05:57:07 +01:00
print ( " There are zombies threads " , type_txt , " . " )
2022-03-11 00:21:00 +01:00
###############################################################################
2022-03-13 05:32:55 +01:00
# Vagues (minions)
2022-03-11 00:21:00 +01:00
###############################################################################
2022-03-23 00:27:11 +01:00
# Minion caracteristics : category (class), level, hp, speed, armor, bounty, lifes_damage
2022-03-20 05:57:07 +01:00
2022-03-24 17:00:09 +01:00
minion_carac = {
2022-03-20 05:57:07 +01:00
' Knight-lv1 ' : [ " Knight " , 1 , 2.0 , 1.0 , 0.0 , 5 , 1 ] ,
' Knight-lv2 ' : [ " Knight " , 2 , 4.0 , 1.0 , 1.0 , 20 , 1 ] ,
' Knight-lv3 ' : [ " Knight " , 3 , 8.0 , 1.0 , 2.0 , 80 , 1 ] }
2022-03-24 17:00:09 +01:00
# Minion 3d object : body (male,female,old, ...), head (A,B,C,D), level
minion_3d = {
' Knight-lv1 ' : [ [ ' Knight_m ' , ' Knight_f ' , ' OldKnight_m ' ] , [ ' A ' , ' B ' , ' C ' , ' D ' ] , [ ' common ' ] ] ,
' Knight-lv2 ' : [ [ ' Knight_m ' , ' Knight_f ' , ' OldKnight_m ' ] , [ ' A ' , ' B ' , ' C ' , ' D ' ] , [ ' uncommon ' ] ] ,
' Knight-lv3 ' : [ [ ' Knight_m ' , ' Knight_f ' , ' OldKnight_m ' ] , [ ' A ' , ' B ' , ' C ' , ' D ' ] , [ ' rare ' ] ] }
2022-03-13 05:32:55 +01:00
# Création d'un minion
2022-03-20 05:57:07 +01:00
def ct_minion ( x , y , cat , level ) :
2022-03-24 17:00:09 +01:00
category = cat + " -lv " + str ( level )
# Pause
while scene . objects [ ' Terrain ' ] [ ' run ' ] == False :
2022-03-23 00:27:11 +01:00
time . sleep ( 0 )
2022-03-20 05:57:07 +01:00
2022-03-24 17:00:09 +01:00
# Object 3D
body = random . choice ( minion_3d [ category ] [ 0 ] ) + " _ " + random . choice ( minion_3d [ category ] [ 1 ] ) + " _ " + random . choice ( minion_3d [ category ] [ 2 ] )
minion = scene . addObject ( body , scene . objects [ ' Terrain ' ] )
2022-03-20 05:57:07 +01:00
minion . worldScale = mathutils . Vector ( ( 0.25 , 0.25 , 0.25 ) )
minion . worldPosition = mathutils . Vector ( ( x , y , 0.1 ) )
# minion.worldPosition=mathutils.Vector((x,y,0.3))
# minion.worldPosition=mathutils.Vector((x,y,0.37)) # old 2
2022-03-13 05:32:55 +01:00
scene . objects [ ' Points ' ] [ ' minions ' ] = scene . objects [ ' Points ' ] [ ' minions ' ] + 1
2022-03-20 05:57:07 +01:00
2022-03-24 17:00:09 +01:00
# Caracteristics
minion . components [ ' Minion ' ] . args [ ' cat ' ] = minion_carac [ category ] [ 0 ]
minion . components [ ' Minion ' ] . args [ ' level ' ] = minion_carac [ category ] [ 1 ]
minion . components [ ' Minion ' ] . args [ ' hp ' ] = minion_carac [ category ] [ 2 ]
minion . components [ ' Minion ' ] . args [ ' speed ' ] = minion_carac [ category ] [ 3 ]
minion . components [ ' Minion ' ] . args [ ' armor ' ] = minion_carac [ category ] [ 4 ]
minion . components [ ' Minion ' ] . args [ ' bounty ' ] = minion_carac [ category ] [ 5 ]
minion . components [ ' Minion ' ] . args [ ' lifes_damage ' ] = minion_carac [ category ] [ 6 ]
2022-03-20 05:57:07 +01:00
minion [ ' hp ' ] = minion . components [ ' Minion ' ] . args [ ' hp ' ]
2022-03-24 17:00:09 +01:00
# Actuator Steering
2022-03-23 00:27:11 +01:00
minion . actuators [ ' Steering ' ] . navmesh = scene . objects [ scene . objects [ ' Terrain ' ] [ ' navmesh ' ] ]
minion . actuators [ ' Steering ' ] . target = scene . objects [ scene . objects [ ' Terrain ' ] [ ' endtile ' ] ]
2022-03-20 05:57:07 +01:00
minion . actuators [ ' Steering ' ] . distance = 0.5
2022-03-23 00:27:11 +01:00
minion . actuators [ ' Steering ' ] . velocity = minion . components [ ' Minion ' ] . args [ ' speed ' ] * scene . objects [ ' Terrain ' ] [ ' speed ' ]
2022-03-20 05:57:07 +01:00
# Destruction d'un minion
def scn_minion_dead ( cont ) :
obj = cont . owner
2022-03-23 00:27:11 +01:00
scene . objects [ ' Points ' ] [ ' minions ' ] = scene . objects [ ' Points ' ] [ ' minions ' ] - 1
scene . objects [ ' Points ' ] [ ' coins ' ] = scene . objects [ ' Points ' ] [ ' coins ' ] + obj . components [ ' Minion ' ] . args [ ' bounty ' ]
2022-03-20 05:57:07 +01:00
obj . endObject ( )
2022-03-13 05:32:55 +01:00
2022-03-11 00:21:00 +01:00
###############################################################################
# Tours
###############################################################################
2022-03-23 00:27:11 +01:00
# Tower caracteristics : category (class), damage, speed, range
2022-03-24 17:00:09 +01:00
tower_carac = {
2022-03-23 00:27:11 +01:00
' Base ' : [ " Base " , 1.0 , 0.02 , 3.0 ] }
2022-03-24 17:00:09 +01:00
# carac_tower={
# 'Base' : ["Base", 1.0 , 0.02, 3.0]}
2022-03-11 00:21:00 +01:00
# Création d'une tour
2022-03-23 00:27:11 +01:00
def ct_build ( x , y , tower_name = " Tower " , color = tower_purple , cat = ' Base ' ) :
# Vérification de la place
if [ x , y ] in scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] or [ x , y ] in scene . objects [ ' Terrain ' ] [ ' scene_tile_tower ' ] :
return False
# Vérification du niveau
scene . objects [ ' Points ' ] [ ' level ' ] = scene . objects [ ' Points ' ] [ ' level ' ] + 1
if scene . objects [ ' Points ' ] [ ' level ' ] > scene . objects [ ' Points ' ] [ ' level_max ' ] :
tour = scene . addObject ( " Tower_error " , scene . objects [ ' Terrain ' ] )
tour . worldPosition = mathutils . Vector ( ( x , y , 0.2 ) )
tour . worldScale = mathutils . Vector ( ( 1 , 1 , 1 ) )
scene . objects [ ' Terrain ' ] [ ' scene_tile_tower ' ] . append ( [ x , y ] )
return False
2022-03-20 05:57:07 +01:00
# Objet 3D
tour = scene . addObject ( " Tower " , scene . objects [ ' Terrain ' ] )
2022-03-23 00:27:11 +01:00
tour . color = color
2022-03-11 00:21:00 +01:00
tour . worldPosition = mathutils . Vector ( ( x , y , 0.2 ) )
tour . worldScale = mathutils . Vector ( ( 1 , 1 , 1 ) )
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_tower ' ] . append ( [ x , y ] )
# Caractéristiques (composant python et propriétés de l'objet 3D)
2022-03-24 17:00:09 +01:00
tour . components [ ' Tower ' ] . args [ ' cat ' ] = tower_carac [ cat ] [ 0 ]
2022-03-23 00:27:11 +01:00
tour . components [ ' Tower ' ] . args [ ' lvl ' ] = 1
tour . components [ ' Tower ' ] . args [ ' tower_name ' ] = tower_name
2022-03-24 17:00:09 +01:00
tour . components [ ' Tower ' ] . args [ ' damage ' ] = tower_carac [ cat ] [ 1 ]
tour . components [ ' Tower ' ] . args [ ' speed ' ] = tower_carac [ cat ] [ 2 ]
tour . components [ ' Tower ' ] . args [ ' range ' ] = tower_carac [ cat ] [ 3 ]
tour [ ' cat ' ] = tower_carac [ cat ] [ 0 ]
2022-03-23 00:27:11 +01:00
tour [ ' lvl ' ] = 1
tour [ ' tower_name ' ] = tower_name
2022-03-24 17:00:09 +01:00
tour [ ' damage ' ] = tower_carac [ cat ] [ 1 ]
tour [ ' speed ' ] = tower_carac [ cat ] [ 2 ]
tour [ ' range ' ] = tower_carac [ cat ] [ 3 ]
2022-03-23 00:27:11 +01:00
# Capteur Near
tour . sensors [ ' Near ' ] . distance = tour . components [ ' Tower ' ] . args [ ' range ' ]
tour . sensors [ ' Near ' ] . skippedTicks = round ( 1 / ( tour . components [ ' Tower ' ] . args [ ' speed ' ] * scene . objects [ ' Terrain ' ] [ ' speed ' ] ) )
2022-03-24 17:00:09 +01:00
print ( tour . sensors [ ' Near ' ] . skippedTicks )
# for obj_i in scene.objects:
# if "type_tower" in obj_i.getPropertyNames():
# print (obj_i['tower_name'])
2022-03-23 00:27:11 +01:00
return True
# Supression d'une tour
def ct_remove ( x , y ) :
for obj_i in scene . objects : # Supprimer les tours
if " type_tower " in obj_i . getPropertyNames ( ) :
if x == obj_i . worldPosition . x and y == obj_i . worldPosition . y :
obj_i . endObject ( )
scene . objects [ ' Points ' ] [ ' level ' ] = scene . objects [ ' Points ' ] [ ' level ' ] - 1
2022-03-20 05:57:07 +01:00
2022-03-11 00:21:00 +01:00
# Réaction d'une tour
2022-03-20 05:57:07 +01:00
def scn_tower_near ( cont ) :
2022-03-11 00:21:00 +01:00
obj = cont . owner
sensor = obj . sensors [ ' Near ' ]
2022-03-24 17:00:09 +01:00
# Tir
# FIXME: deux tirs à la fois ?
# FIXME: tir sur le plus avancé
2022-03-20 05:57:07 +01:00
if len ( sensor . hitObjectList ) > 0 and scene . objects [ ' Terrain ' ] [ ' run ' ] == True :
2022-03-13 05:32:55 +01:00
target = sensor . hitObjectList [ 0 ]
2022-03-24 17:00:09 +01:00
# target.actuators['Steering'].velocity=(target.components['Minion'].args['speed']*scene.objects['Terrain']['speed'])/2 # Reduction de la vitesse du minion
# Bullet (3d object) (vitesse <=1)
if scene . objects [ ' Terrain ' ] [ ' speed ' ] < = 1 :
bullet = scene . addObject ( " Bullet " , scene . objects [ ' Terrain ' ] )
bullet . mass = 0.001 # bullet.applyForce=((0,0,9.81),True)
bullet . worldPosition = mathutils . Vector ( ( obj . worldPosition . x , obj . worldPosition . y , 1.5 ) )
bullet . worldScale = [ 0.75 , 0.75 , 0.75 ]
# bullet.worldScale=[0.5,0.5,0.5]
bullet . worldLinearVelocity . x = ( target . worldPosition . x - bullet . worldPosition . x ) * bullet [ ' velocity ' ]
bullet . worldLinearVelocity . y = ( target . worldPosition . y - bullet . worldPosition . y ) * bullet [ ' velocity ' ]
bullet . worldLinearVelocity . z = ( target . worldPosition . z + 0.1 - bullet . worldPosition . z ) * bullet [ ' velocity ' ]
# Line (vitesse >=2)
if scene . objects [ ' Terrain ' ] [ ' speed ' ] > = 2 :
bge . render . drawLine ( [ obj . worldPosition . x , obj . worldPosition . y , obj . worldPosition . z + 0.1 ] ,
[ target . worldPosition . x , target . worldPosition . y , target . worldPosition . z ] ,
[ 0.8 , 0.619 , 0.021 ] )
2022-03-20 05:57:07 +01:00
# Dégats
target [ ' hp ' ] = target [ ' hp ' ] - obj . components [ ' Tower ' ] . args [ ' damage ' ]
if target [ ' hp ' ] < = 0 :
target [ ' dead ' ] = True
###############################################################################
# Carte
###############################################################################
2022-03-13 05:32:55 +01:00
2022-03-20 05:57:07 +01:00
# Fin
def ct_map_end ( x , y ) :
mapend = scene . addObject ( " Map_end " , scene . objects [ ' Terrain ' ] )
mapend . worldPosition = [ x , y , 0.2 ]
mapend . worldScale = [ 0.25 , 0.25 , 0.25 ]
# Minion arrivé à la fin
def scn_map_end_near ( cont ) :
obj = cont . owner
sensor = obj . sensors [ ' Near ' ]
2022-03-23 00:27:11 +01:00
# if len(sensor.hitObjectList)>0:
# print ("Arrive à la fin", sensor.hitObjectList)
2022-03-20 05:57:07 +01:00
for i in range ( len ( sensor . hitObjectList ) ) :
sensor . hitObjectList [ i ] . endObject ( )
scene . objects [ ' Points ' ] [ ' lifes ' ] = scene . objects [ ' Points ' ] [ ' lifes ' ] - sensor . hitObjectList [ 0 ] . components [ ' Minion ' ] . args [ ' lifes_damage ' ]
scene . objects [ ' Points ' ] [ ' minions ' ] = scene . objects [ ' Points ' ] [ ' minions ' ] - 1
# Drapeau de fin
def ct_map_endflag ( x , y ) :
endflag = scene . addObject ( " Map_endflag " , scene . objects [ ' Terrain ' ] )
endflag . worldPosition = [ x , y , 0.3 ]
endflag . worldScale = [ 0.3 , 0.3 , 0.3 ]
if round ( x ) == x :
if round ( y ) == y :
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ x , y ] )
2022-03-20 05:57:07 +01:00
else :
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ x , math . floor ( y ) ] )
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ x , math . ceil ( y ) ] )
2022-03-20 05:57:07 +01:00
else :
if round ( y ) == y :
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . floor ( x ) , y ] )
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . ceil ( x ) , y ] )
2022-03-20 05:57:07 +01:00
else :
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . floor ( x ) , math . floor ( y ) ] )
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . floor ( x ) , math . ceil ( y ) ] )
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . ceil ( x ) , math . floor ( y ) ] )
scene . objects [ ' Terrain ' ] [ ' scene_tile_noncontruct ' ] . append ( [ math . ceil ( x ) , math . ceil ( y ) ] )
2022-03-11 00:21:00 +01:00
###############################################################################
# Temporisation
###############################################################################
2022-03-24 17:00:09 +01:00
def ct_sleep ( duration ) :
time . sleep ( duration * ( 1 / scene . objects [ ' Terrain ' ] [ ' speed ' ] ) )
def ct_tempo ( duration ) :
scene . objects [ ' Terrain ' ] [ ' delay_cmd ' ] = 0
while scene . objects [ ' Terrain ' ] [ ' delay_cmd ' ] < duration * ( 1 / scene . objects [ ' Terrain ' ] [ ' speed ' ] ) :
# print("Temporization commands :",scene.objects['Terrain']['delay_cmd'])
time . sleep ( 0.001 )
# pass
def ct_tempo_wave ( duration ) :
scene . objects [ ' Terrain ' ] [ ' delay_wave ' ] = 0
while scene . objects [ ' Terrain ' ] [ ' delay_wave ' ] < duration * ( 1 / scene . objects [ ' Terrain ' ] [ ' speed ' ] ) :
# print("Temporization waves :",scene.objects['Terrain']['delay_wave'])
time . sleep ( 0.001 )
# pass
# def ct_tempo_wave_trigger (duree):
# print ("delay wave ", scene.objects['Terrain']['delay_wave'])
2022-03-23 00:27:11 +01:00
###############################################################################
# Affichage
###############################################################################
2022-03-11 00:21:00 +01:00
2022-03-23 00:27:11 +01:00
# Texte du panel d'information
2022-03-24 17:00:09 +01:00
def ct_print ( text ) :
2022-03-23 00:27:11 +01:00
# text_info (texte)
2022-03-24 17:00:09 +01:00
if text == " " :
2022-03-23 00:27:11 +01:00
scene . objects [ ' Text_info-1 ' ] . setVisible ( False , False )
scene . objects [ ' Text_info-2 ' ] . setVisible ( False , False )
else :
2022-03-24 17:00:09 +01:00
lines_txt = texte . split ( " \n " , 6 )
for i in range ( len ( lines_txt ) , 6 ) :
lines_txt . append ( " " )
2022-03-23 00:27:11 +01:00
scene . objects [ ' Text_info-1 ' ] . setVisible ( True , False )
scene . objects [ ' Text_info-2 ' ] . setVisible ( True , False )
2022-03-24 17:00:09 +01:00
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 ]
2022-03-23 00:27:11 +01:00
# Texte de carte
def ct_map_text ( text ) :
scene . objects [ ' Map_text ' ] [ ' Text ' ] = text
scene . objects [ ' Map_text ' ] . setVisible ( True , False )