Tales-of-PKMN/game/pokemon/sent_pokemon.gd

101 lines
3.1 KiB
GDScript

class_name SentPokemon
extends Node3D
#un pokemon de l'equipe sorti dans le monde (apres un lancer).
#plusieurs peuvent etre sortis en meme temps ; un meme pokemon ne peut l'etre qu'une fois.
signal recalled
const GROUP : StringName = &"sent_pokemon"
const MODEL_FACES_PLUS_Z : bool = true #true si tes modeles regardent vers +Z (cas des glTF) : sinon mets false
static var _counter : int = 0 #ordre d'envoi, pour retrouver le plus recent
var pokemon : PokemonInstance
var model : Node3D
var order : int = 0
static func send(parent : Node, p : PokemonInstance, at : Vector3, look_at_pos : Vector3 = Vector3.INF) -> SentPokemon:
#un pokemon deja sorti est d'abord rappele (il "se deplace" a l'endroit du nouveau lancer)
for existing in parent.get_tree().get_nodes_in_group(GROUP):
if existing is SentPokemon and existing.pokemon == p:
existing.recall()
var sent := SentPokemon.new()
sent.pokemon = p
sent.order = _counter
_counter += 1
parent.add_child(sent)
sent.global_position = at
sent._build_model()
if look_at_pos != Vector3.INF:
var flat : Vector3 = Vector3(look_at_pos.x, at.y, look_at_pos.z)
if flat.distance_to(at) > 0.01:
sent.look_at(flat, Vector3.UP)
if MODEL_FACES_PLUS_Z: sent.rotate_y(PI) #look_at oriente -Z vers la cible
return sent
static func find_for(tree : SceneTree, p : PokemonInstance) -> SentPokemon:
#le SentPokemon de ce pokemon, s'il est actuellement dehors
for n in tree.get_nodes_in_group(GROUP):
if n is SentPokemon and n.pokemon == p and !n.is_queued_for_deletion(): return n
return null
static func get_latest(tree : SceneTree) -> SentPokemon:
#le pokemon sorti le plus recemment
var latest : SentPokemon = null
for n in tree.get_nodes_in_group(GROUP):
if n is SentPokemon and !n.is_queued_for_deletion() and (latest == null or n.order > latest.order):
latest = n
return latest
func _ready() -> void:
add_to_group(GROUP)
func _build_model() -> void:
model = create_model(pokemon)
add_child(model)
static func create_model(p : PokemonInstance) -> Node3D:
#modele 3D de l'espece ; capsule coloree selon le type s'il n'y en a pas
var result : Node3D = null
var scene : PackedScene = p.species.model_scene
if scene:
result = scene.instantiate() as Node3D
if result == null:
result = _create_placeholder(p)
return result
static func _create_placeholder(p : PokemonInstance) -> Node3D:
var colors : Array[Color] = TypeColors.for_species(p.species)
var body := MeshInstance3D.new()
var capsule := CapsuleMesh.new()
capsule.radius = 0.3
capsule.height = 1.0
body.mesh = capsule
body.position.y = 0.5
body.material_override = _make_material(colors[0])
#deuxieme type : anneau autour de la capsule
if colors.size() > 1:
var ring := MeshInstance3D.new()
var torus := TorusMesh.new()
torus.inner_radius = 0.29
torus.outer_radius = 0.36
ring.mesh = torus
ring.material_override = _make_material(colors[1])
body.add_child(ring)
return body
static func _make_material(color : Color) -> StandardMaterial3D:
var mat := StandardMaterial3D.new()
mat.albedo_color = color
mat.roughness = 0.8
return mat
func recall() -> void:
recalled.emit()
queue_free()