2022-03-29 14:12:58 +02:00
import bge # Blender Game Engine (UPBGE)
import aud # Sounds
2022-03-11 00:21:00 +01:00
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-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-04-11 22:42:09 +02:00
# @authors: Philippe Roy <phroy@phroy.org>
2022-03-11 00:21:00 +01:00
# @copyright: Copyright (C) 2022 Philippe Roy
# @license: GNU GPL
#
2022-04-01 01:34:54 +02:00
# This game is a tower defense coding game. The towers are driven by Python code.
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.
#
2022-03-30 03:10:33 +02:00
# 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_*
2022-03-11 00:21:00 +01:00
#
###############################################################################
scene = bge . logic . getCurrentScene ( )
2022-03-23 00:27:11 +01:00
# Colors
2022-04-03 06:21:42 +02:00
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 )
tower_blue = ( 0.127 , 0.456 , 1.000 , 1 )
tower_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 )
2022-03-29 14:12:58 +02:00
# 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 )
2022-04-06 17:28:16 +02:00
threads_waves = [ ]
threads_cmd = [ ]
2022-04-22 02:04:48 +02:00
# 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
2022-03-30 03:10:33 +02:00
###############################################################################
# Données générales
###############################################################################
def ct_level_current ( ) :
return scene . objects [ ' Points ' ] [ ' level ' ]
def ct_level ( ) :
return scene . objects [ ' Points ' ] [ ' level_max ' ]
2022-03-23 00:27:11 +01:00
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-29 14:12:58 +02:00
return True
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-29 14:12:58 +02:00
return False
2022-03-11 00:21:00 +01:00
2022-04-06 17:28:16 +02:00
def thread_waves_start ( fct ) :
thread_start ( threads_waves , " waves " , fct )
def thread_waves_stop ( ) :
thread_stop ( threads_waves , " waves " )
def thread_cmd_start ( fct ) :
thread_start ( threads_cmd , " commands " , fct )
def thread_cmd_stop ( ) :
thread_stop ( threads_cmd , " commands " )
2022-04-22 16:54:49 +02:00
###############################################################################
# Sounds
###############################################################################
def sound_play ( sound ) :
if scene . objects [ ' Commands ' ] [ ' sound ' ] :
audiodev . play ( sound )
2022-04-06 17:28:16 +02:00
2022-03-11 00:21:00 +01:00
###############################################################################
2022-04-22 16:54:49 +02:00
# Waves (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-25 01:56:02 +01:00
# Minion 3d object : body (male,female,old, ...), variante (A,B,C,D, ...), level
2022-03-24 17:00:09 +01:00
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 )
2022-03-30 03:10:33 +02:00
minion_3d = scene . objects [ ' Terrain ' ] [ ' minion_3d ' ]
2022-03-27 10:28:03 +02:00
body = random . choice ( minion_3d [ category ] [ 0 ] ) + " _ " + random . choice ( minion_3d [ category ] [ 1 ] ) + " _ " + random . choice ( minion_3d [ category ] [ 2 ] )
ct_minion_details ( x , y , cat , level , body )
2022-03-29 14:12:58 +02:00
# Création d'un minion détaillée
2022-03-27 10:28:03 +02:00
def ct_minion_details ( x , y , cat , level , body = " Knight_m_A_common " ) :
category = cat + " -lv " + str ( level )
2022-03-24 17:00:09 +01:00
# Pause
while scene . objects [ ' Terrain ' ] [ ' run ' ] == False :
2022-03-27 10:28:03 +02:00
time . sleep ( 0.01 )
2022-03-20 05:57:07 +01:00
2022-04-11 22:42:09 +02:00
# Synchronisation des threads
while scene . objects [ ' Terrain ' ] [ ' thread_cmd_lock ' ] == True :
# print ("ct_minion : thread_cmd_lock =True")
time . sleep ( 0.01 )
2022-03-24 17:00:09 +01:00
# Object 3D
minion = scene . addObject ( body , scene . objects [ ' Terrain ' ] )
2022-03-27 10:28:03 +02:00
minion . worldScale = [ 0.25 , 0.25 , 0.25 ]
minion . worldPosition = [ x , y , 0.1 ]
scene . objects [ ' Terrain ' ] [ ' idm ' ] = scene . objects [ ' Terrain ' ] [ ' idm ' ] + 1
2022-04-06 06:25:03 +02:00
minion [ ' id ' ] = scene . objects [ ' Terrain ' ] [ ' idm ' ]
minion . name = " wm( " + str ( minion [ ' id ' ] ) + " ) " # Wave minion (wm), identifier minion (idm)
2022-03-29 14:12:58 +02:00
scene . objects [ ' Points ' ] [ ' minions ' ] + = 1
scene . objects [ ' Points ' ] [ ' minions_run ' ] + = 1
2022-04-06 06:25:03 +02:00
# Gestion de la distance et des minions zombis
2022-04-03 06:21:42 +02:00
minion [ ' dist ' ] = 0.0
2022-04-06 06:25:03 +02:00
minion [ ' dist_old ' ] = 0.0
minion [ ' dist_last_x ' ] = minion . worldPosition . x
minion [ ' dist_last_y ' ] = minion . worldPosition . y
minion [ ' dist_new ' ] = True
2022-03-20 05:57:07 +01:00
2022-03-24 17:00:09 +01:00
# Caracteristics
2022-03-30 03:10:33 +02:00
minion_carac = scene . objects [ ' Terrain ' ] [ ' minion_carac ' ]
2022-03-31 18:26:55 +02:00
minion [ ' cat ' ] = minion_carac [ category ] [ 0 ]
minion [ ' level ' ] = minion_carac [ category ] [ 1 ]
minion [ ' hp ' ] = minion_carac [ category ] [ 2 ]
minion [ ' speed ' ] = minion_carac [ category ] [ 3 ]
minion [ ' speed_base ' ] = minion_carac [ category ] [ 3 ]
minion [ ' armor ' ] = minion_carac [ category ] [ 4 ]
minion [ ' bounty ' ] = minion_carac [ category ] [ 5 ]
minion [ ' lifes_damage ' ] = minion_carac [ category ] [ 6 ]
minion [ ' buff ' ] = [ ]
2022-04-01 01:34:54 +02:00
minion [ ' resist ' ] = [ ]
2022-03-20 05:57:07 +01:00
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-04-06 17:28:16 +02:00
minion . actuators [ ' Steering ' ] . distance = 2
# minion.actuators['Steering'].distance=0.5
2022-03-31 18:26:55 +02:00
minion . actuators [ ' Steering ' ] . velocity = minion [ ' speed_base ' ] * 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-29 14:12:58 +02:00
scene . objects [ ' Points ' ] [ ' minions ' ] - = 1
scene . objects [ ' Points ' ] [ ' minions_run ' ] - = 1
scene . objects [ ' Points ' ] [ ' kills ' ] + = 1
2022-03-31 18:26:55 +02:00
scene . objects [ ' Points ' ] [ ' coins ' ] = scene . objects [ ' Points ' ] [ ' coins ' ] + obj [ ' bounty ' ]
2022-03-20 05:57:07 +01:00
obj . endObject ( )
2022-03-13 05:32:55 +01:00
2022-04-01 01:34:54 +02:00
###############################################################################
2022-04-03 06:21:42 +02:00
# Spells / Casts
2022-04-01 01:34:54 +02:00
###############################################################################
# Buff/debuff Minion
def scn_minion_affect ( cont ) :
2022-04-11 22:42:09 +02:00
if scene . objects [ ' Terrain ' ] [ ' run ' ] == False : # Pause
return
2022-04-01 01:34:54 +02:00
obj = cont . owner
# print (obj.name, obj['buff'])
slow_state = False
2022-04-03 06:21:42 +02:00
# Distance parcourue
obj [ ' dist ' ] = obj [ ' dist ' ] + math . sqrt ( ( obj . worldPosition . x - obj [ ' dist_last_x ' ] ) * * 2 + ( obj . worldPosition . y - obj [ ' dist_last_y ' ] ) * * 2 )
obj [ ' dist_last_x ' ] = obj . worldPosition . x
obj [ ' dist_last_y ' ] = obj . worldPosition . y
2022-04-01 01:34:54 +02:00
# Etats actif
for debuff_i in obj [ ' buff ' ] :
if debuff_i [ 1 ] < = 0 :
obj [ ' buff ' ] . remove ( debuff_i )
continue
if debuff_i [ 0 ] == " slow " :
slow_state = True
debuff_i [ 1 ] - = scene . objects [ ' Terrain ' ] [ ' speed ' ]
# Effets
if slow_state :
2022-04-06 06:25:03 +02:00
obj . actuators [ ' Steering ' ] . velocity = ( obj [ ' speed_base ' ] * scene . objects [ ' Terrain ' ] [ ' speed ' ] ) / 3
# obj.actuators['Steering'].velocity =(obj['speed_base']*scene.objects['Terrain']['speed'])/2
2022-04-01 01:34:54 +02:00
else :
obj . actuators [ ' Steering ' ] . velocity = obj [ ' speed_base ' ] * scene . objects [ ' Terrain ' ] [ ' speed ' ]
2022-03-11 00:21:00 +01:00
###############################################################################
2022-04-22 16:54:49 +02:00
# Towers
2022-03-11 00:21:00 +01:00
###############################################################################
2022-03-23 00:27:11 +01:00
# Tower caracteristics : category (class), damage, speed, range
2022-03-11 00:21:00 +01:00
# Création d'une tour
2022-03-27 10:28:03 +02:00
def ct_build ( x , y , cat = ' Archer tower ' , tower_name = " Tower " , color = tower_purple , tower_3d = " square-A " ) :
2022-03-30 03:10:33 +02:00
tower_minion_3d = scene . objects [ ' Terrain ' ] [ ' tower_minion_3d ' ]
2022-03-27 10:28:03 +02:00
if cat == ' Archer tower ' : # Archer
category = " Archer-lv1 "
if cat == ' Mage tower ' : # Mage
category = " Mage-lv1 "
body = random . choice ( tower_minion_3d [ category ] [ 0 ] ) + " _ " + random . choice ( tower_minion_3d [ category ] [ 1 ] ) + " _ " + random . choice ( tower_minion_3d [ category ] [ 2 ] )
ct_build_details ( x , y , cat , tower_name , color , tower_3d , body )
2022-03-29 14:12:58 +02:00
# Création d'une tour détaillée
2022-03-27 10:28:03 +02:00
def ct_build_details ( x , y , cat = ' Archer tower ' , tower_name = " Tower " , color = tower_purple , tower_3d = " square-A " , body = " Archer_m_A_common " ) :
2022-03-23 00:27:11 +01:00
# 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
2022-04-11 22:42:09 +02:00
2022-03-23 00:27:11 +01:00
# 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 ' ] )
2022-03-27 10:28:03 +02:00
tour . worldPosition = [ x , y , 0.2 ]
tour . worldScale = [ 1 , 1 , 1 ]
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_tower ' ] . append ( [ x , y ] )
return False
2022-03-20 05:57:07 +01:00
2022-04-11 22:42:09 +02:00
# Blocage des autres threads pendant la construction
scene . objects [ ' Terrain ' ] [ ' thread_cmd_lock ' ] = True
2022-03-27 10:28:03 +02:00
# Objets 3D
2022-04-16 05:43:32 +02:00
time . sleep ( 0.02 )
2022-03-25 01:56:02 +01:00
tour = scene . addObject ( ' Tower- ' + tower_3d , scene . objects [ ' Terrain ' ] )
2022-04-16 05:43:32 +02:00
time . sleep ( 0.02 )
2022-03-23 00:27:11 +01:00
tour . color = color
2022-03-27 10:28:03 +02:00
tour . worldPosition = [ x , y , 0.2 ]
tour . worldScale = [ 1 , 1 , 1 ]
2022-03-23 00:27:11 +01:00
scene . objects [ ' Terrain ' ] [ ' scene_tile_tower ' ] . append ( [ x , y ] )
2022-03-27 10:28:03 +02:00
tower_minion = scene . addObject ( body , scene . objects [ ' Terrain ' ] )
tower_minion [ " type_towerminion " ] = False
tower_minion . name = " tm( " + str ( x ) + ' , ' + str ( y ) + " ) " # Tower minion (tm)
tower_minion . worldPosition = [ x , y , 1 ]
tower_minion . worldScale = [ 0.25 , 0.25 , 0.25 ]
2022-03-29 14:12:58 +02:00
# Sounds
2022-04-22 16:54:49 +02:00
sound_play ( sndbuff_build )
2022-03-27 10:28:03 +02:00
2022-03-30 03:10:33 +02:00
# Caracteristics
tower_carac = scene . objects [ ' Terrain ' ] [ ' tower_carac ' ]
2022-03-24 17:00:09 +01:00
tour [ ' cat ' ] = tower_carac [ cat ] [ 0 ]
2022-03-23 00:27:11 +01:00
tour [ ' tower_name ' ] = tower_name
2022-03-31 18:26:55 +02:00
tour [ ' xp ' ] = 0
tour [ ' lvl_current ' ] = 1
tour [ ' lvl ' ] = 1
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-31 18:26:55 +02:00
tour [ ' techno ' ] = [ ]
2022-04-01 01:34:54 +02:00
tour [ ' cast ' ] = " slow "
2022-04-06 06:25:03 +02:00
# tour['cast_duration']=2
tour [ ' cast_duration ' ] = 3
2022-04-03 06:21:42 +02:00
tour [ ' target ' ] = [ ]
tour [ ' target_past ' ] = [ ]
2022-03-27 10:28:03 +02:00
2022-03-23 00:27:11 +01:00
# Capteur Near
2022-03-31 18:26:55 +02:00
tour . sensors [ ' Near ' ] . distance = tour [ ' range ' ]
tour . sensors [ ' Near ' ] . skippedTicks = round ( 1 / ( tour [ ' speed ' ] * scene . objects [ ' Terrain ' ] [ ' speed ' ] ) )
2022-04-11 22:42:09 +02:00
scene . objects [ ' Terrain ' ] [ ' thread_cmd_lock ' ] = False
2022-03-23 00:27:11 +01:00
return True
2022-03-27 10:28:03 +02:00
# Suppression d'une tour
2022-03-23 00:27:11 +01:00
def ct_remove ( x , y ) :
2022-03-27 10:28:03 +02:00
for obj_i in scene . objects :
2022-03-23 00:27:11 +01:00
if " type_tower " in obj_i . getPropertyNames ( ) :
if x == obj_i . worldPosition . x and y == obj_i . worldPosition . y :
2022-03-27 10:28:03 +02:00
scene . objects [ " tm( " + str ( round ( obj_i . worldPosition . x ) ) + ' , ' + str ( round ( obj_i . worldPosition . y ) ) + " ) " ] . endObject ( )
2022-03-23 00:27:11 +01:00
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
2022-03-27 10:28:03 +02:00
if sensor . positive and len ( sensor . hitObjectList ) > 0 and scene . objects [ ' Terrain ' ] [ ' run ' ] == True :
2022-04-03 06:21:42 +02:00
# Tir sur le plus avancé basé sur les distances parcourues
2022-03-13 05:32:55 +01:00
target = sensor . hitObjectList [ 0 ]
2022-04-03 06:21:42 +02:00
target_dist = target [ ' dist ' ]
for obj_i in sensor . hitObjectList :
if obj_i [ ' dist ' ] > target_dist :
target = obj_i
target_dist = target [ ' dist ' ]
# Tir sur le plus avancé basé sur l'ordre de passage
# target=sensor.hitObjectList[0]
# target_id = target['navPosition']
# for obj_i in sensor.hitObjectList:
# if obj_i['navPosition']< target_id:
# target=obj_i
# target_id = target['navPosition']
# Tir sur le plus avancé basé sur les distances par rapport à la tour -> ne marche pas
# target=sensor.hitObjectList[0]
# if len(sensor.hitObjectList)>1:
# target_eloignement = False
# target_distance_eloignement = 0
# target_distance_approche = 100
# print ("detection:",sensor.hitObjectList)
# for obj_i in sensor.hitObjectList:
# for obj_j in obj['target_past']:
# if obj_j[0]==obj_i.name:
# print ("name :", obj_j[0], "distance :", obj.getDistanceTo(obj_i), "distance old :", obj_j[1], "ecart :", obj.getDistanceTo(obj_i) - obj_j[1])
# # Éloignement
# if obj.getDistanceTo(obj_i) - obj_j[1] > 0: # Ecart de distance
# target_eloignement = True
# if obj.getDistanceTo(obj_i) > target_distance_eloignement:
# target=obj_i
# target_distance_eloignement = obj.getDistanceTo(obj_i)
# # Approche
# else:
# if target_eloignement == False:
# if obj.getDistanceTo(obj_i) < target_distance_approche:
# target=obj_i
# target_distance_approche = obj.getDistanceTo(obj_i)
# if target_eloignement == True:
# print ("Eloignement : target:", target.name, "distance :", obj.getDistanceTo(target))
# print ("")
# else:
# print ("Approche : target:", target.name, "distance :", obj.getDistanceTo(target))
# print ("")
# obj['target_past']=[]
# for obj_i in sensor.hitObjectList:
# obj['target_past'].append([obj_i.name, obj.getDistanceTo(obj_i)])
2022-03-24 17:00:09 +01:00
2022-03-27 10:28:03 +02:00
# Orientation du tower minion
towerminion = " tm( " + str ( round ( obj . worldPosition . x ) ) + ' , ' + str ( round ( obj . worldPosition . y ) ) + " ) "
angle = math . atan ( ( target . worldPosition . y - obj . worldPosition . y ) / ( target . worldPosition . x - obj . worldPosition . x ) )
if target . worldPosition . x > obj . worldPosition . x :
angle2 = math . pi / 2 + angle - scene . objects [ towerminion ] . worldOrientation . to_euler ( ) . z
angle3 = angle
else :
angle2 = math . pi + math . pi / 2 + angle - scene . objects [ towerminion ] . worldOrientation . to_euler ( ) . z
angle3 = math . pi + angle
scene . objects [ towerminion ] . applyRotation ( ( 0 , 0 , angle2 ) , False )
# Bullet (3d object) (vitesse lente) # -> tendance au plantage
# 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=[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']
2022-03-31 18:26:55 +02:00
# Sounds
if obj [ ' cat ' ] == " Archer tower " :
2022-04-22 16:54:49 +02:00
sound_play ( sndbuff_archer )
2022-03-31 18:26:55 +02:00
if obj [ ' cat ' ] == " Mage tower " :
2022-04-22 16:54:49 +02:00
sound_play ( sndbuff_mage )
2022-03-31 18:26:55 +02:00
2022-03-27 10:28:03 +02:00
# Ligne (drawLine) (vitesse rapide)
# if scene.objects['Terrain']['speed']>=1:
if scene . objects [ ' Terrain ' ] [ ' speed ' ] < 10 : # Pas d'animation à 10 -> plantage
# Archer (tir de flêche)
if obj [ ' cat ' ] == " Archer tower " :
if target . name in scene . objects :
scene . objects [ ' Terrain ' ] [ ' draw_process ' ] = True
2022-03-30 03:10:33 +02:00
scene . objects [ ' Terrain ' ] [ ' draw_list ' ] . append ( [ 5 , " arrow " , [ obj . worldPosition . x , obj . worldPosition . y , obj . worldPosition . z + 0.8 ] , target . name , angle3 , ray_black , 5 ] )
2022-03-27 10:28:03 +02:00
# Cast zone
if obj [ ' cat ' ] == " Mage tower " : # Mage (cast)
scene . objects [ ' Terrain ' ] [ ' draw_process ' ] = True
scene . objects [ ' Terrain ' ] [ ' draw_list ' ] . append ( [ 30 , " cast " , [ obj . worldPosition . x , obj . worldPosition . y , obj . worldPosition . z + 0.8 ] , ray_blue , 30 ] )
# Rayon
if obj [ ' cat ' ] == " Test " :
if target . name in scene . objects :
scene . objects [ ' Terrain ' ] [ ' draw_process ' ] = True
scene . objects [ ' Terrain ' ] [ ' draw_list ' ] . append ( [ 5 , " ray " , [ obj . worldPosition . x , obj . worldPosition . y , obj . worldPosition . z + 0.8 ] , target . name , angle3 , ray_yellow , 5 ] ) # Suivi du minion
2022-03-20 05:57:07 +01:00
# Dégats
2022-03-31 18:26:55 +02:00
target [ ' hp ' ] = target [ ' hp ' ] - obj [ ' damage ' ]
2022-03-20 05:57:07 +01:00
if target [ ' hp ' ] < = 0 :
target [ ' dead ' ] = True
2022-04-01 01:34:54 +02:00
# Cast (buff and debuff)
2022-03-30 03:10:33 +02:00
if obj [ ' cat ' ] == " Mage tower " :
for target_i in sensor . hitObjectList :
2022-04-01 01:34:54 +02:00
target_i [ ' buff ' ] . append ( [ obj [ ' cast ' ] , obj [ ' cast_duration ' ] ] )
2022-03-30 03:10:33 +02:00
2022-03-20 05:57:07 +01:00
###############################################################################
# Carte
###############################################################################
2022-03-13 05:32:55 +01:00
2022-04-03 06:21:42 +02:00
# Texte de carte
def ct_map_text_wave ( wave ) :
scene . objects [ ' Map_text ' ] [ ' Text ' ] = ( " Wave " + str ( wave ) )
scene . objects [ ' Map_text ' ] . setVisible ( True , False )
scene . objects [ ' Map_text ' ] . color = color_text_yellow
scene . objects [ ' Map_text ' ] [ ' timer ' ] = 120
2022-04-11 22:42:09 +02:00
scene . objects [ ' Map_text ' ] [ ' position_init ' ] = [ 8.37716 , - 2.39401 , 5.56759 ]
2022-04-03 06:21:42 +02:00
scene . objects [ ' Map_text ' ] [ ' position_end ' ] = [ 11.1751 , 5.99318 , 0.480557 ]
scene . objects [ ' Map_text ' ] . worldPosition = scene . objects [ ' Map_text ' ] [ ' position_init ' ]
scene . objects [ ' Map_text ' ] [ ' anim ' ] = True
2022-04-06 06:25:03 +02:00
# Texte de carte
2022-04-03 06:21:42 +02:00
def ct_map_text ( text ) :
scene . objects [ ' Map_text ' ] [ ' Text ' ] = text
scene . objects [ ' Map_text ' ] . setVisible ( True , False )
2022-03-20 05:57:07 +01:00
# Fin
def ct_map_end ( x , y ) :
2022-04-06 06:25:03 +02:00
scene . objects [ ' Map_end ' ] . worldPosition = [ x , y , 0.2 ]
scene . objects [ ' Map_end ' ] . worldScale = [ 0.25 , 0.25 , 0.25 ]
2022-03-20 05:57:07 +01:00
# Minion arrivé à la fin
def scn_map_end_near ( cont ) :
obj = cont . owner
sensor = obj . sensors [ ' Near ' ]
2022-04-06 06:25:03 +02:00
if sensor . positive :
for obj_i in sensor . hitObjectList :
2022-04-22 16:54:49 +02:00
sound_play ( sndbuff_life )
2022-04-06 06:25:03 +02:00
if scene . objects [ ' Points ' ] [ ' lifes ' ] > 0 :
scene . objects [ ' Points ' ] [ ' lifes ' ] = scene . objects [ ' Points ' ] [ ' lifes ' ] - obj_i [ ' lifes_damage ' ]
scene . objects [ ' Points ' ] [ ' minions_run ' ] - = 1
for obj_i in sensor . hitObjectList :
obj_i . endObject ( )
# def scn_map_end_near(cont):
# obj = cont.owner
# print(obj)
# sensor = obj.sensors['Near']
# if sensor.positive and len(sensor.hitObjectList)>0 :
# # print ("end, len(sensor.hitObjectList) : ", len(sensor.hitObjectList))
# for obj_i in sensor.hitObjectList :
# # print ("obj['idm_last'], obj_i ['id'] : ", obj['idm_last'], obj_i ['id'])
# if obj['idm_last'] != obj_i ['id']:
# obj['idm_last'] = obj_i ['id']
2022-04-22 16:54:49 +02:00
# sound_play(sndbuff_life)
2022-04-06 06:25:03 +02:00
# if scene.objects['Points']['lifes']>0:
# scene.objects['Points']['lifes']= scene.objects['Points']['lifes']-obj_i['lifes_damage']
# scene.objects['Points']['minions_run'] -=1
# obj['idm_last'] = obj_i ['id']
# for obj_i in sensor.hitObjectList :
# obj_i.endObject()
2022-03-20 05:57:07 +01:00
# 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 ' ] ) )
2022-03-27 10:28:03 +02:00
# 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
2022-03-24 17:00:09 +01:00
2022-03-27 10:28:03 +02:00
# 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
2022-03-24 17:00:09 +01:00
# 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
2022-03-27 10:28:03 +02:00
###############################################################################
# Dessin bas niveau (bge.render.drawLine)
###############################################################################
def circle ( center , radius , color ) :
ang = 0.0
2022-03-29 14:12:58 +02:00
# ang_step = 0.1
ang_step = 0.2
2022-03-27 10:28:03 +02:00
while ang < 2 * math . pi :
x0 = center [ 0 ] + float ( radius * math . cos ( ang ) )
y0 = center [ 1 ] + float ( radius * math . sin ( ang ) )
x1 = center [ 0 ] + float ( radius * math . cos ( ang + ang_step ) )
y1 = center [ 1 ] + float ( radius * math . sin ( ang + ang_step ) )
bge . render . drawLine ( [ x0 , y0 , center [ 2 ] ] , [ x1 , y1 , center [ 2 ] ] , color )
ang + = ang_step
# Affiche les draws en cours
# FIXME: tir sur le plus avancé
#
# Type de draw :
# arrow : [5, "arrow", [obj.worldPosition.x, obj.worldPosition.y, obj.worldPosition.z+0.8],target.name, angle3, ray_yellow,5]
# cast : [30, "cast", [obj.worldPosition.x, obj.worldPosition.y, obj.worldPosition.z+0.8], ray_blue,30]
# ray : [5, "ray", [obj.worldPosition.x, obj.worldPosition.y, obj.worldPosition.z+0.8],[target.worldPosition.x, target.worldPosition.y, target.worldPosition.z], angle3, ray_yellow,5]
#
def scn_draw ( cont ) :
obj = cont . owner
2022-03-30 03:10:33 +02:00
if obj . sensors [ ' Draw ' ] . positive == False :
2022-03-27 10:28:03 +02:00
return
if len ( scene . objects [ ' Terrain ' ] [ ' draw_list ' ] ) == 0 :
scene . objects [ ' Terrain ' ] [ ' draw_process ' ] = False
return
# Dépilage des draws à executer
for draw_cmd in scene . objects [ ' Terrain ' ] [ ' draw_list ' ] :
# Archer (tir de flêche)
if draw_cmd [ 1 ] == " arrow " :
if draw_cmd [ 3 ] in scene . objects :
# x0 = draw_cmd[2][0]+0.25*(math.cos(draw_cmd[4]))
# y0 = draw_cmd[2][1]+0.25*(math.sin(draw_cmd[4]))
x0 = draw_cmd [ 2 ] [ 0 ]
y0 = draw_cmd [ 2 ] [ 1 ]
z0 = draw_cmd [ 2 ] [ 2 ]
x1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . x
y1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . y
z1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . z - 0.1 # ajustement -0.1
distance = math . sqrt ( ( x1 - x0 ) * * 2 + ( y1 - y0 ) * * 2 + ( z1 - z0 ) * * 2 )
distance_xy = math . sqrt ( ( x1 - x0 ) * * 2 + ( y1 - y0 ) * * 2 )
distance_z = z1 - z0
angle_z = math . atan ( ( z1 - z0 ) / ( distance_xy ) )
angle_xy = math . atan ( ( y1 - y0 ) / ( x1 - x0 ) )
step = distance_xy / ( 2 + draw_cmd [ 6 ] )
step_z = distance_z / ( 2 + draw_cmd [ 6 ] )
if x1 > x0 :
angle2 = angle_xy
else :
angle2 = math . pi + angle_xy
x2 = x0 + ( ( ( 6 - draw_cmd [ 0 ] ) * step ) * ( math . cos ( angle2 ) ) )
y2 = y0 + ( ( ( 6 - draw_cmd [ 0 ] ) * step ) * ( math . sin ( angle2 ) ) )
z2 = z0 - ( ( ( 6 - draw_cmd [ 0 ] ) * step_z ) * ( math . sin ( angle_z ) ) )
x3 = x0 + ( ( ( 6 - draw_cmd [ 0 ] ) * step + step ) * ( math . cos ( angle2 ) ) )
y3 = y0 + ( ( ( 6 - draw_cmd [ 0 ] ) * step + step ) * ( math . sin ( angle2 ) ) )
z3 = z0 - ( ( ( 6 - draw_cmd [ 0 ] ) * step_z + step_z ) * ( math . sin ( angle_z ) ) )
bge . render . drawLine ( [ x2 , y2 , z2 ] , [ x3 , y3 , z3 ] , draw_cmd [ 5 ] )
draw_cmd [ 0 ] = draw_cmd [ 0 ] - scene . objects [ ' Terrain ' ] [ ' speed ' ]
# if scene.objects['Terrain']['speed']<1:
# draw_cmd[0] = draw_cmd[0]-scene.objects['Terrain']['speed']
# else:
# draw_cmd[0] = draw_cmd[0]-1
# bge.render.drawLine([draw_cmd[2][0]+((6-draw_cmd[0])*0.25)*(math.cos(draw_cmd[4])), draw_cmd[2][1]+((6-draw_cmd[0])*0.25)*(math.sin(draw_cmd[4])),draw_cmd[2][2]],
# [draw_cmd[2][0]+((6-draw_cmd[0])*0.25+0.25)*(math.cos(draw_cmd[4])), draw_cmd[2][1]+((6-draw_cmd[0])*0.25+0.25)*(math.sin(draw_cmd[4])),draw_cmd[2][2]],
# draw_cmd[5])
# Mage (cast)
2022-03-30 03:10:33 +02:00
# FIXME : Problème
2022-03-27 10:28:03 +02:00
if draw_cmd [ 1 ] == " cast " : # Mage (cast)
circle ( draw_cmd [ 2 ] , 3.1 - draw_cmd [ 0 ] * 0.1 , draw_cmd [ 3 ] )
circle ( draw_cmd [ 2 ] , 3 - draw_cmd [ 0 ] * 0.1 , draw_cmd [ 3 ] )
circle ( draw_cmd [ 2 ] , 2.9 - draw_cmd [ 0 ] * 0.1 , draw_cmd [ 3 ] )
draw_cmd [ 0 ] = draw_cmd [ 0 ] - scene . objects [ ' Terrain ' ] [ ' speed ' ]
# if scene.objects['Terrain']['speed']<=2:
# draw_cmd[0] = draw_cmd[0]-scene.objects['Terrain']['speed']
# if scene.objects['Terrain']['speed']==4:
# draw_cmd[0] = draw_cmd[0]-draw_cmd[4]/2
# circle(draw_cmd[2], 3, draw_cmd[3]) # simple
# radius=[3,3,2.5,2.5,2,2,1.5,1.5,1,1,1] # basé sur un tableau
# circle(draw_cmd[2], radius[draw_cmd[0]], draw_cmd[3])
# Rayon
if draw_cmd [ 1 ] == " ray " :
if draw_cmd [ 3 ] in scene . objects :
x0 = draw_cmd [ 2 ] [ 0 ] + 0.25 * ( math . cos ( draw_cmd [ 4 ] ) )
y0 = draw_cmd [ 2 ] [ 1 ] + 0.25 * ( math . sin ( draw_cmd [ 4 ] ) )
x1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . x
y1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . y
z1 = scene . objects [ draw_cmd [ 3 ] ] . worldPosition . z
bge . render . drawLine ( [ x0 , y0 , draw_cmd [ 2 ] [ 2 ] ] , [ x1 , y1 , z1 ] , draw_cmd [ 5 ] ) # suivi minion
# bge.render.drawLine([draw_cmd[2][0]+0.25*(math.cos(draw_cmd[4])), draw_cmd[2][1]+0.25*(math.sin(draw_cmd[4])), draw_cmd[2][2]], draw_cmd[3], draw_cmd[5]) # décalage minion
# bge.render.drawLine(draw_cmd[2], draw_cmd[3], draw_cmd[5]) # simple
draw_cmd [ 0 ] = draw_cmd [ 0 ] - scene . objects [ ' Terrain ' ] [ ' speed ' ]
# Suppression des draws finis
i = 0
for draw_cmd in scene . objects [ ' Terrain ' ] [ ' draw_list ' ] :
if draw_cmd [ 0 ] < = 0 :
scene . objects [ ' Terrain ' ] [ ' draw_list ' ] . pop ( i )
else :
i = i + 1
if len ( scene . objects [ ' Terrain ' ] [ ' draw_list ' ] ) == 0 :
scene . objects [ ' Terrain ' ] [ ' draw_process ' ] = False