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
|
|
|
|
|
|
|
|
|
|
import ct # 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
|
|
|
|
|
# @lang: fr
|
|
|
|
|
# @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()
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# 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-20 05:57:07 +01:00
|
|
|
|
# Minion category : base, level, hp, speed, armor, bounty, lifes_damage
|
|
|
|
|
|
|
|
|
|
carac_minion={
|
|
|
|
|
'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-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):
|
|
|
|
|
|
|
|
|
|
# while scene.objects['Terrain']['run'] == False: # Pause
|
|
|
|
|
# pass
|
|
|
|
|
|
|
|
|
|
# Objet 3D
|
|
|
|
|
minion= scene.addObject(cat, scene.objects['Terrain'])
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
# Caractéristiques
|
|
|
|
|
minion.components['Minion'].args['cat']=carac_minion[cat+"-lv"+str(level)][0]
|
|
|
|
|
minion.components['Minion'].args['level']=carac_minion[cat+"-lv"+str(level)][1]
|
|
|
|
|
minion.components['Minion'].args['hp']=carac_minion[cat+"-lv"+str(level)][2]
|
|
|
|
|
minion.components['Minion'].args['speed']=carac_minion[cat+"-lv"+str(level)][3]
|
|
|
|
|
minion.components['Minion'].args['armor']=carac_minion[cat+"-lv"+str(level)][4]
|
|
|
|
|
minion.components['Minion'].args['bounty']=carac_minion[cat+"-lv"+str(level)][5]
|
|
|
|
|
minion.components['Minion'].args['lifes_damage']=carac_minion[cat+"-lv"+str(level)][6]
|
|
|
|
|
minion['hp'] =minion.components['Minion'].args['hp']
|
|
|
|
|
|
|
|
|
|
# Steering
|
|
|
|
|
minion.actuators['Steering'].navmesh=scene.objects['Navmesh.004']
|
|
|
|
|
minion.actuators['Steering'].target=scene.objects['tile_straight.036']
|
|
|
|
|
minion.actuators['Steering'].distance=0.5
|
|
|
|
|
minion.actuators['Steering'].velocity=2
|
|
|
|
|
# minion.actuators['Steering'].velocity=minion.components['Minion'].args['speed']
|
|
|
|
|
|
|
|
|
|
# Tete
|
|
|
|
|
# if class_minion=="Knight":
|
|
|
|
|
# head = random.choice(['Knight_head-A', 'Knight_head-B'])
|
|
|
|
|
# minion_head= scene.addObject(head, minion)
|
|
|
|
|
# minion_head.worldScale=mathutils.Vector((0.25,0.25,0.25))
|
|
|
|
|
# minion_head.setParent(minion, True, True)
|
|
|
|
|
# minion_head.localPosition.z=0.703713 # Position de la tête
|
|
|
|
|
|
|
|
|
|
# Accessoires
|
|
|
|
|
|
|
|
|
|
# Destruction d'un minion
|
|
|
|
|
def scn_minion_dead(cont):
|
|
|
|
|
obj = cont.owner
|
|
|
|
|
# if obj['dead']==True:
|
|
|
|
|
obj.endObject()
|
2022-03-13 05:32:55 +01:00
|
|
|
|
|
2022-03-11 00:21:00 +01:00
|
|
|
|
###############################################################################
|
|
|
|
|
# Tours
|
2022-03-13 05:32:55 +01:00
|
|
|
|
#
|
|
|
|
|
# Caractéristiques :
|
2022-03-20 05:57:07 +01:00
|
|
|
|
# - Tour basique : dégats = 1.0 ; portée = 3.0 ; vitesse =0,2, portée = 3.0
|
2022-03-13 05:32:55 +01:00
|
|
|
|
#
|
2022-03-11 00:21:00 +01:00
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
# Création d'une tour
|
2022-03-20 05:57:07 +01:00
|
|
|
|
def ct_tower(x,y):
|
|
|
|
|
|
|
|
|
|
# Objet 3D
|
|
|
|
|
tour= scene.addObject("Tower", scene.objects['Terrain'])
|
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-13 05:32:55 +01:00
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([x,y])
|
2022-03-20 05:57:07 +01:00
|
|
|
|
|
|
|
|
|
# Caractéristiques
|
|
|
|
|
tour.components['Tower'].args['damage']=1.0
|
|
|
|
|
tour.components['Tower'].args['speed']=0.2
|
|
|
|
|
tour.components['Tower'].args['range']=3.0
|
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-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
|
|
|
|
|
2022-03-20 05:57:07 +01:00
|
|
|
|
# Tir
|
2022-03-13 05:32:55 +01:00
|
|
|
|
target=sensor.hitObjectList[0]
|
2022-03-20 05:57:07 +01:00
|
|
|
|
target.actuators['Steering'].velocity=target.components['Minion'].args['speed']/2
|
|
|
|
|
bullet= scene.addObject("Bullet", scene.objects['Terrain'])
|
2022-03-11 00:21:00 +01:00
|
|
|
|
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.5,0.5,0.5]
|
2022-03-20 05:57:07 +01:00
|
|
|
|
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']
|
|
|
|
|
|
|
|
|
|
# Dégats
|
|
|
|
|
target['hp'] = target['hp'] - obj.components['Tower'].args['damage']
|
|
|
|
|
if target['hp']<=0:
|
|
|
|
|
target['dead']=True
|
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
|
|
|
|
scene.objects['Points']['coins']= scene.objects['Points']['coins']+target.components['Minion'].args['bounty']
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# 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']
|
|
|
|
|
if len(sensor.hitObjectList)>0:
|
|
|
|
|
print (sensor.hitObjectList)
|
|
|
|
|
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 :
|
|
|
|
|
print (x,y)
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([x,y])
|
|
|
|
|
else:
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([x,math.floor(y)])
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([x,math.ceil(y)])
|
|
|
|
|
else:
|
|
|
|
|
if round(y) == y :
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.floor(x),y])
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.ceil(x),y])
|
|
|
|
|
else:
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.floor(x),math.floor(y)])
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.floor(x),math.ceil(y)])
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.ceil(x),math.floor(y)])
|
|
|
|
|
scene.objects['Terrain']['scene_non_contruct'].append([math.ceil(x),math.ceil(y)])
|
|
|
|
|
|
|
|
|
|
# Texte de carte
|
|
|
|
|
def ct_map_text(text):
|
|
|
|
|
scene.objects['Map_text']['Text']=text
|
|
|
|
|
scene.objects['Map_text'].setVisible(True,False)
|
2022-03-11 00:21:00 +01:00
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
# Temporisation
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
def tempo (duree):
|
|
|
|
|
time.sleep(duree)
|
|
|
|
|
|