codetower/ct_lib.py

317 lines
12 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 bge # Bibliothèque Blender Game Engine (UPBGE)
import threading # Multithreading
import trace
import sys
import time
import math
import mathutils
import random
# from ct import * # Bibliothèque CodeTower
###############################################################################
# ct_lib.py
# @title: User library
# @project: CodeTower
# @lang: fr
# @authors: Philippe Roy <philippe.roy@ac-grenoble.fr>
# @copyright: Copyright (C) 2022 Philippe Roy
# @license: GNU GPL
#
# 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.
#
# Commandes déclenchées par les joueurs : ct_*
# Commandes déclenchées par la scene 3D : scn_*
#
###############################################################################
scene = bge.logic.getCurrentScene()
# 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]
###############################################################################
# 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()
print ("Thread",type_txt, "#", len(threads)-1, "open.")
def thread_stop(threads, type_txt):
i=0
zombie_flag=False
for t in threads:
if not t.is_alive():
print ("Thread",type_txt, "#",i,"closed.")
else:
print ("Thread",type_txt, "#",i,"still open ...")
t.kill()
t.join()
if not t.is_alive():
print ("Thread",type_txt, "#",i,"killed.")
else:
print ("Thread",type_txt, "#",i,"zombie...")
zombie_flag=True
i +=1
if zombie_flag==False:
print ("All threads",type_txt, "are closed.")
else:
print ("There are zombies threads",type_txt, ".")
###############################################################################
# Vagues (minions)
###############################################################################
# Minion caracteristics : category (class), 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]}
# Création d'un minion
def ct_minion(x,y,cat,level):
while scene.objects['Terrain']['run'] == False: # Pause
time.sleep(0)
# 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
scene.objects['Points']['minions']= scene.objects['Points']['minions']+1
# 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']
# Actionneur Steering
minion.actuators['Steering'].navmesh=scene.objects[scene.objects['Terrain']['navmesh']]
minion.actuators['Steering'].target=scene.objects[scene.objects['Terrain']['endtile']]
minion.actuators['Steering'].distance=0.5
minion.actuators['Steering'].velocity=minion.components['Minion'].args['speed']*scene.objects['Terrain']['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
scene.objects['Points']['minions']= scene.objects['Points']['minions']-1
scene.objects['Points']['coins']= scene.objects['Points']['coins']+obj.components['Minion'].args['bounty']
obj.endObject()
###############################################################################
# Tours
###############################################################################
# Tower caracteristics : category (class), damage, speed, range
carac_tower={
'Base' : ["Base", 1.0 , 0.02, 3.0]}
# Création d'une tour
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
# Objet 3D
tour= scene.addObject("Tower", scene.objects['Terrain'])
tour.color = color
tour.worldPosition=mathutils.Vector((x,y,0.2))
tour.worldScale=mathutils.Vector((1,1,1))
scene.objects['Terrain']['scene_tile_tower'].append([x,y])
# Caractéristiques (composant python et propriétés de l'objet 3D)
tour.components['Tower'].args['cat']=carac_tower[cat][0]
tour.components['Tower'].args['lvl']=1
tour.components['Tower'].args['tower_name']=tower_name
tour.components['Tower'].args['damage']=carac_tower[cat][1]
tour.components['Tower'].args['speed']=carac_tower[cat][2]
tour.components['Tower'].args['range']=carac_tower[cat][3]
tour['cat']=carac_tower[cat][0]
tour['lvl']=1
tour['tower_name']=tower_name
tour['damage']=carac_tower[cat][1]
tour['speed']=carac_tower[cat][2]
tour['range']=carac_tower[cat][3]
# 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']))
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
# Réaction d'une tour
def scn_tower_near(cont):
obj = cont.owner
sensor = obj.sensors['Near']
if len(sensor.hitObjectList)>0 and scene.objects['Terrain']['run']==True :
# Tir
target=sensor.hitObjectList[0]
target.actuators['Steering'].velocity=(target.components['Minion'].args['speed']*scene.objects['Terrain']['speed'])/2
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']
# Dégats
target['hp'] = target['hp'] - obj.components['Tower'].args['damage']
if target['hp']<=0:
target['dead']=True
###############################################################################
# Carte
###############################################################################
# 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 ("Arrive à la fin", 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 :
scene.objects['Terrain']['scene_tile_noncontruct'].append([x,y])
else:
scene.objects['Terrain']['scene_tile_noncontruct'].append([x,math.floor(y)])
scene.objects['Terrain']['scene_tile_noncontruct'].append([x,math.ceil(y)])
else:
if round(y) == y :
scene.objects['Terrain']['scene_tile_noncontruct'].append([math.floor(x),y])
scene.objects['Terrain']['scene_tile_noncontruct'].append([math.ceil(x),y])
else:
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)])
###############################################################################
# Temporisation
###############################################################################
def ct_tempo (duree):
time.sleep(duree*(1/scene.objects['Terrain']['speed']))
###############################################################################
# Affichage
###############################################################################
# Texte du panel d'information
def ct_print (texte):
# text_info (texte)
if texte=="":
scene.objects['Text_info-1'].setVisible(False,False)
scene.objects['Text_info-2'].setVisible(False,False)
else:
lignes_txt=texte.split("\n", 6)
for i in range (len(lignes_txt),6):
lignes_txt.append("")
scene.objects['Text_info-1'].setVisible(True,False)
scene.objects['Text_info-2'].setVisible(True,False)
scene.objects['Text_info-1']['Text']=lignes_txt[0]+"\n"+lignes_txt[1]+"\n"+lignes_txt[2]
scene.objects['Text_info-2']['Text']=lignes_txt[3]+"\n"+lignes_txt[4]+"\n"+lignes_txt[5]
# Texte de carte
def ct_map_text(text):
scene.objects['Map_text']['Text']=text
scene.objects['Map_text'].setVisible(True,False)