Send Pokemon in overworld
This commit is contained in:
parent
9efc974344
commit
6867a4ece9
|
|
@ -1,15 +1,52 @@
|
|||
extends Node
|
||||
# Autoload : GameData
|
||||
|
||||
signal selected_pokemon_changed
|
||||
signal battle_requested(sent : SentPokemon, target : Node) #emis par ThrowState : le systeme de combat s'y branchera
|
||||
|
||||
var story_progress : int = 0 # 0 = début, 1 = après 1er badge, 2 = après 2e badge, etc.
|
||||
var player_team : PokemonTeam = PokemonTeam.new()
|
||||
var player_storage : PokemonStorage = PokemonStorage.new()
|
||||
var selected_index : int = -1 #pokemon de l'equipe choisi pour etre envoye (HUD), -1 = aucun
|
||||
|
||||
func give_pokemon(pokemon : PokemonInstance) -> PokemonStorage.ReceiveResult:
|
||||
#point d'entree unique pour obtenir un pokemon (starter, cadeau, capture...) :
|
||||
#equipe si elle a de la place, sinon PC. A l'appelant d'informer le joueur selon le resultat.
|
||||
return player_storage.receive_pokemon(player_team, pokemon)
|
||||
|
||||
#---------- pokemon selectionne (a envoyer) ----------
|
||||
#seuls les pokemon aptes au combat (non K.O.) peuvent etre selectionnes
|
||||
|
||||
func get_selected_pokemon() -> PokemonInstance:
|
||||
validate_selection()
|
||||
return player_team.get_pokemon(selected_index)
|
||||
|
||||
func validate_selection() -> void:
|
||||
#corrige la selection si le pokemon n'existe plus, est K.O., ou a change de place
|
||||
var p : PokemonInstance = player_team.get_pokemon(selected_index)
|
||||
if p != null and !p.is_fainted(): return
|
||||
_set_selected(player_team.get_first_able_index())
|
||||
|
||||
func select_pokemon(index : int) -> bool:
|
||||
var p : PokemonInstance = player_team.get_pokemon(index)
|
||||
if p == null or p.is_fainted(): return false
|
||||
_set_selected(index)
|
||||
return true
|
||||
|
||||
func cycle_selection(direction : int) -> void:
|
||||
validate_selection()
|
||||
var able : Array[int] = []
|
||||
for i in player_team.size():
|
||||
if !player_team.get_pokemon(i).is_fainted(): able.append(i)
|
||||
if able.size() < 2: return
|
||||
var pos : int = able.find(selected_index)
|
||||
_set_selected(able[posmod(pos + direction, able.size())])
|
||||
|
||||
func _set_selected(index : int) -> void:
|
||||
if index == selected_index: return
|
||||
selected_index = index
|
||||
selected_pokemon_changed.emit()
|
||||
|
||||
func save() -> void:
|
||||
var config := ConfigFile.new()
|
||||
config.set_value("progress", "story_progress", story_progress)
|
||||
|
|
|
|||
54
game/player/aim/thrown_ball.gd
Normal file
54
game/player/aim/thrown_ball.gd
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
class_name ThrownBall
|
||||
extends Node3D
|
||||
|
||||
#balle lancee : suit un arc entre deux points, puis emet "landed" et disparait.
|
||||
#autonome (pas lie a l'etat du joueur) : continue meme si le joueur change d'etat avant l'atterrissage.
|
||||
|
||||
signal landed(position : Vector3)
|
||||
|
||||
const SPIN_SPEED : float = 12.0
|
||||
|
||||
var _start : Vector3
|
||||
var _end : Vector3
|
||||
var _arc_height : float = 1.5
|
||||
var _duration : float = 0.5
|
||||
var _elapsed : float = 0.0
|
||||
|
||||
static func launch(parent : Node, from : Vector3, to : Vector3, duration : float, arc_height : float, visual_scene : PackedScene = null) -> ThrownBall:
|
||||
var ball := ThrownBall.new()
|
||||
ball._start = from
|
||||
ball._end = to
|
||||
ball._duration = maxf(duration, 0.05)
|
||||
ball._arc_height = arc_height
|
||||
parent.add_child(ball)
|
||||
ball.global_position = from
|
||||
ball._build_visual(visual_scene)
|
||||
return ball
|
||||
|
||||
func _build_visual(visual_scene : PackedScene) -> void:
|
||||
if visual_scene:
|
||||
var visual : Node = visual_scene.instantiate()
|
||||
add_child(visual)
|
||||
return
|
||||
#balle par defaut (sphere rouge) en attendant ton modele
|
||||
var mesh_instance := MeshInstance3D.new()
|
||||
var sphere := SphereMesh.new()
|
||||
sphere.radius = 0.12
|
||||
sphere.height = 0.24
|
||||
mesh_instance.mesh = sphere
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = Color(0.9, 0.15, 0.15)
|
||||
mesh_instance.material_override = mat
|
||||
add_child(mesh_instance)
|
||||
|
||||
func _process(delta : float) -> void:
|
||||
_elapsed += delta
|
||||
var t : float = clampf(_elapsed / _duration, 0.0, 1.0)
|
||||
global_position = _start.lerp(_end, t) + Vector3.UP * _arc_height * 4.0 * t * (1.0 - t)
|
||||
rotate_x(SPIN_SPEED * delta)
|
||||
|
||||
if t >= 1.0:
|
||||
set_process(false)
|
||||
global_position = _end
|
||||
landed.emit(_end)
|
||||
queue_free()
|
||||
1
game/player/aim/thrown_ball.gd.uid
Normal file
1
game/player/aim/thrown_ball.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c4nec4y6jc5eg
|
||||
26
game/player/input/recall_input.gd
Normal file
26
game/player/input/recall_input.gd
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
class_name RecallInput
|
||||
extends Node
|
||||
|
||||
#rappel d'un pokemon hors visee : un appui sur RT / clic gauche rappelle le pokemon sorti.
|
||||
#- le pokemon selectionne (HUD) s'il est dehors, sinon le dernier sorti
|
||||
#- pendant la visee et le lancer, c'est AimState / ThrowState qui gerent cet appui
|
||||
#
|
||||
#usage : ajouter ce node comme enfant de ton PlayerCharacter (il le detecte via son parent)
|
||||
|
||||
@export var player : PlayerCharacter
|
||||
@export var throw_action : StringName = &"player_throw"
|
||||
@export var ignored_states : Array[String] = ["Aim", "Throw"] #valeurs de state_name
|
||||
|
||||
func _ready() -> void:
|
||||
if player == null: player = get_parent() as PlayerCharacter
|
||||
|
||||
func _physics_process(_delta : float) -> void:
|
||||
if player == null or !InputMap.has_action(throw_action): return
|
||||
if !Input.is_action_just_pressed(throw_action): return
|
||||
if player.state_machine.curr_state_name in ignored_states: return
|
||||
|
||||
var target : SentPokemon = null
|
||||
var selected : PokemonInstance = GameData.get_selected_pokemon()
|
||||
if selected: target = SentPokemon.find_for(get_tree(), selected)
|
||||
if target == null: target = SentPokemon.get_latest(get_tree())
|
||||
if target: target.recall()
|
||||
1
game/player/input/recall_input.gd.uid
Normal file
1
game/player/input/recall_input.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c820hnwuwpmlg
|
||||
|
|
@ -9,8 +9,10 @@
|
|||
[ext_resource type="Script" uid="uid://dr5p8ygj25w6x" path="res://game/player/states/jump_state.gd" id="6_lwgph"]
|
||||
[ext_resource type="Script" uid="uid://dn5idrvu68k83" path="res://game/player/states/aim_state.gd" id="7_kxr4l"]
|
||||
[ext_resource type="Script" uid="uid://dpcfffs3vt5co" path="res://game/player/states/run_state.gd" id="8_j4mf1"]
|
||||
[ext_resource type="Script" uid="uid://c3jh22p4w3xco" path="res://game/player/states/throw_state.gd" id="8_k0r6x"]
|
||||
[ext_resource type="Script" uid="uid://bwojkp7yrwswt" path="res://game/player/states/dodge_state.gd" id="9_6abew"]
|
||||
[ext_resource type="Script" uid="uid://d0577tj0c23bu" path="res://game/player/states/crouch_state.gd" id="10_mi63v"]
|
||||
[ext_resource type="Script" uid="uid://c820hnwuwpmlg" path="res://game/player/input/recall_input.gd" id="13_siyau"]
|
||||
|
||||
[sub_resource type="Curve" id="Curve_kxr4l"]
|
||||
_limits = [0.0, 10.0, 0.0, 1.0]
|
||||
|
|
@ -84,6 +86,21 @@ script = ExtResource("6_lwgph")
|
|||
|
||||
[node name="AimState" type="Node" parent="StateMachine" unique_id=296560188]
|
||||
script = ExtResource("7_kxr4l")
|
||||
aim_action = null
|
||||
switch_target_action = null
|
||||
unlock_action = null
|
||||
throw_action = null
|
||||
throw_range = null
|
||||
max_aim_angle = null
|
||||
auto_lock_angle = null
|
||||
lose_range_margin = null
|
||||
check_line_of_sight = null
|
||||
line_of_sight_mask = null
|
||||
aim_move_speed = null
|
||||
aim_move_accel = null
|
||||
|
||||
[node name="ThrowState" type="Node" parent="StateMachine" unique_id=1159570489]
|
||||
script = ExtResource("8_k0r6x")
|
||||
|
||||
[node name="RunState" type="Node" parent="StateMachine" unique_id=1345421775]
|
||||
script = ExtResource("8_j4mf1")
|
||||
|
|
@ -96,3 +113,6 @@ script = ExtResource("10_mi63v")
|
|||
|
||||
[node name="InputManagementComponent" type="Node" parent="." unique_id=1981951371]
|
||||
script = ExtResource("2_r5dqo")
|
||||
|
||||
[node name="RecallInput" type="Node" parent="." unique_id=1544887696]
|
||||
script = ExtResource("13_siyau")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ var play_char : CharacterBody3D
|
|||
@export var aim_action : StringName = &"player_aim_camera"
|
||||
@export var switch_target_action : StringName = &"player_aim_switch_target"
|
||||
@export var unlock_action : StringName = &"player_aim_unlock"
|
||||
@export var throw_action : StringName = &"player_throw" #RT / clic gauche (cree automatiquement s'il n'existe pas)
|
||||
|
||||
@export_group("Targeting")
|
||||
@export var throw_range : float = 20.0
|
||||
|
|
@ -25,6 +26,18 @@ var play_char : CharacterBody3D
|
|||
var auto_lock_blocked : bool = false #true apres un deverrouillage manuel, tant que la cible est encore au centre
|
||||
var dodging_from_aim : bool = false #true quand on quitte Aim pour rouler, pour ne pas relacher la cible verrouillee
|
||||
var came_from_crouch : bool = false #true si Aim a ete declenche depuis CrouchState, pour y retourner en sortant
|
||||
var keep_aim_on_exit : bool = false #true quand on part vers ThrowState : camera et verrouillage restent en place
|
||||
|
||||
func _ready() -> void:
|
||||
if InputMap.has_action(throw_action): return
|
||||
InputMap.add_action(throw_action)
|
||||
var trigger := InputEventJoypadMotion.new()
|
||||
trigger.axis = JOY_AXIS_TRIGGER_RIGHT
|
||||
trigger.axis_value = 1.0
|
||||
InputMap.action_add_event(throw_action, trigger)
|
||||
var click := InputEventMouseButton.new()
|
||||
click.button_index = MOUSE_BUTTON_LEFT
|
||||
InputMap.action_add_event(throw_action, click)
|
||||
|
||||
func enter(play_char_ref : CharacterBody3D) -> void:
|
||||
play_char = play_char_ref
|
||||
|
|
@ -38,6 +51,9 @@ func verifications() -> void:
|
|||
play_char.cam_holder.cam_aimed = true
|
||||
|
||||
func exit() -> void:
|
||||
if keep_aim_on_exit:
|
||||
keep_aim_on_exit = false
|
||||
return
|
||||
if dodging_from_aim:
|
||||
#on roule en visant : la camera et la cible verrouillee restent actives pendant la roulade
|
||||
dodging_from_aim = false
|
||||
|
|
@ -71,6 +87,15 @@ func input_management() -> bool:
|
|||
transitioned.emit(self, play_char.walk_or_run if play_char.move_dir else "IdleState")
|
||||
return true
|
||||
|
||||
if Input.is_action_just_pressed(throw_action):
|
||||
#si le pokemon selectionne est deja dehors, un nouvel appui le rappelle au lieu de relancer
|
||||
var selected : PokemonInstance = GameData.get_selected_pokemon()
|
||||
var already_out : SentPokemon = SentPokemon.find_for(get_tree(), selected) if selected else null
|
||||
if already_out:
|
||||
already_out.recall()
|
||||
elif start_throw():
|
||||
return true
|
||||
|
||||
if Input.is_action_just_pressed(unlock_action):
|
||||
auto_lock_blocked = true
|
||||
release_target()
|
||||
|
|
@ -78,6 +103,13 @@ func input_management() -> bool:
|
|||
switch_target()
|
||||
return false
|
||||
|
||||
func start_throw() -> bool:
|
||||
if GameData.get_selected_pokemon() == null: return false #personne a envoyer
|
||||
if !play_char.state_machine.states.has("throwstate"): return false #pas de node ThrowState dans la StateMachine
|
||||
keep_aim_on_exit = true
|
||||
transitioned.emit(self, "ThrowState")
|
||||
return true
|
||||
|
||||
func move(delta : float) -> void:
|
||||
play_char.move_dir = Input.get_vector(play_char.move_left_action, play_char.move_right_action, play_char.move_forward_action, play_char.move_backward_action).rotated(-play_char.cam_holder.global_rotation.y)
|
||||
|
||||
|
|
|
|||
155
game/player/states/throw_state.gd
Normal file
155
game/player/states/throw_state.gd
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
extends State
|
||||
|
||||
class_name ThrowState
|
||||
|
||||
var state_name : String = "Throw"
|
||||
|
||||
var play_char : CharacterBody3D
|
||||
|
||||
@export var aim_action : StringName = &"player_aim_camera"
|
||||
|
||||
@export_group("Timing")
|
||||
@export var windup_time : float = 0.25 #delai avant que la balle parte (a caler sur l'animation)
|
||||
@export var recovery_time : float = 0.35 #temps de recuperation apres le lancer
|
||||
|
||||
@export_group("Ball")
|
||||
@export var ball_scene : PackedScene #modele de la balle (optionnel : sphere rouge par defaut)
|
||||
@export var hand_height : float = 1.4
|
||||
@export var ball_speed : float = 18.0
|
||||
@export var min_flight_time : float = 0.25
|
||||
@export var max_flight_time : float = 1.2
|
||||
@export var arc_height : float = 1.5
|
||||
@export var land_distance_from_target : float = 1.5 #la balle s'arrete devant une cible de combat
|
||||
|
||||
@export_group("Targeting")
|
||||
@export var throw_range : float = 20.0
|
||||
@export_flags_3d_physics var ground_mask : int = 1
|
||||
|
||||
var _elapsed : float = 0.0
|
||||
var _thrown : bool = false
|
||||
var _keep_aim : bool = false #true quand on retourne a AimState : on garde camera et verrouillage
|
||||
var _pokemon : PokemonInstance = null
|
||||
var _target : Variant = null #AimTarget verrouille au moment du lancer
|
||||
var _free_aim_point : Vector3 = Vector3.ZERO
|
||||
|
||||
func enter(play_char_ref : CharacterBody3D) -> void:
|
||||
play_char = play_char_ref
|
||||
_elapsed = 0.0
|
||||
_thrown = false
|
||||
_keep_aim = false
|
||||
|
||||
_pokemon = GameData.get_selected_pokemon()
|
||||
_target = play_char.aim_target if is_instance_valid(play_char.aim_target) else null
|
||||
_free_aim_point = _compute_free_aim_point() #visee libre : le point est fige au moment ou on appuie
|
||||
|
||||
play_char.floor_snap_length = 1.0
|
||||
#play_char.godot_plush_skin.set_state("throw")
|
||||
|
||||
func exit() -> void:
|
||||
#retour a la visee : on garde tout tel quel ; sinon on libere camera et verrouillage (comme AimState)
|
||||
if _keep_aim:
|
||||
_keep_aim = false
|
||||
return
|
||||
_release_aim()
|
||||
|
||||
func physics_update(delta : float) -> void:
|
||||
if applies(): return
|
||||
|
||||
play_char.gravity_apply(delta)
|
||||
slow_down(delta)
|
||||
|
||||
if _pokemon == null:
|
||||
finish() #rien a lancer (equipe vide ou tous K.O.)
|
||||
return
|
||||
|
||||
_elapsed += delta
|
||||
if !_thrown and _elapsed >= windup_time:
|
||||
throw_ball()
|
||||
if _elapsed >= windup_time + recovery_time:
|
||||
finish()
|
||||
|
||||
func applies() -> bool:
|
||||
if !play_char.is_on_floor() and play_char.velocity.y < 0.0:
|
||||
transitioned.emit(self, "InairState")
|
||||
return true
|
||||
return false
|
||||
|
||||
func slow_down(delta : float) -> void:
|
||||
play_char.velocity.x = lerp(play_char.velocity.x, 0.0, play_char.move_deccel * delta)
|
||||
play_char.velocity.z = lerp(play_char.velocity.z, 0.0, play_char.move_deccel * delta)
|
||||
|
||||
func finish() -> void:
|
||||
if Input.is_action_pressed(aim_action):
|
||||
_keep_aim = true
|
||||
transitioned.emit(self, "AimState")
|
||||
return
|
||||
|
||||
var dir : Vector2 = Input.get_vector(play_char.move_left_action, play_char.move_right_action, play_char.move_forward_action, play_char.move_backward_action)
|
||||
transitioned.emit(self, play_char.walk_or_run if dir != Vector2.ZERO else "IdleState")
|
||||
|
||||
#---------- lancer ----------
|
||||
|
||||
func throw_ball() -> void:
|
||||
_thrown = true
|
||||
|
||||
var from : Vector3 = play_char.global_position + Vector3.UP * hand_height
|
||||
var to : Vector3 = _get_landing_point()
|
||||
var flight_time : float = clampf(from.distance_to(to) / ball_speed, min_flight_time, max_flight_time)
|
||||
|
||||
var scene : Node = play_char.get_tree().current_scene
|
||||
var ball : ThrownBall = ThrownBall.launch(scene, from, to, flight_time, arc_height, ball_scene)
|
||||
#la balle est autonome : l'atterrissage est gere ici meme si le joueur a change d'etat entre-temps
|
||||
ball.landed.connect(_on_ball_landed.bind(_pokemon, _target, from))
|
||||
|
||||
func _get_landing_point() -> Vector3:
|
||||
if !is_instance_valid(_target): return _free_aim_point
|
||||
|
||||
var target_pos : Vector3 = _target.global_position
|
||||
if _starts_battle(_target):
|
||||
#la balle s'arrete devant la cible, du cote du joueur
|
||||
var to_player : Vector3 = play_char.global_position - target_pos
|
||||
to_player.y = 0.0
|
||||
if to_player.length() > land_distance_from_target:
|
||||
target_pos += to_player.normalized() * land_distance_from_target
|
||||
return _snap_to_ground(target_pos)
|
||||
|
||||
func _compute_free_aim_point() -> Vector3:
|
||||
#point vise au centre de l'ecran : premier obstacle, sinon fin de portee ramenee au sol
|
||||
var cam : Camera3D = play_char.cam_holder.cam
|
||||
var origin : Vector3 = cam.global_position
|
||||
var far : Vector3 = origin - cam.global_basis.z * throw_range
|
||||
var query := PhysicsRayQueryParameters3D.create(origin, far, ground_mask, [play_char.get_rid()])
|
||||
var hit : Dictionary = play_char.get_world_3d().direct_space_state.intersect_ray(query)
|
||||
if hit.is_empty(): return _snap_to_ground(far)
|
||||
return _snap_to_ground(hit["position"] + hit["normal"] * 0.5)
|
||||
|
||||
func _snap_to_ground(point : Vector3) -> Vector3:
|
||||
var query := PhysicsRayQueryParameters3D.create(point + Vector3.UP * 2.0, point + Vector3.DOWN * 6.0, ground_mask, [play_char.get_rid()])
|
||||
var hit : Dictionary = play_char.get_world_3d().direct_space_state.intersect_ray(query)
|
||||
return hit["position"] if !hit.is_empty() else point
|
||||
|
||||
func _starts_battle(target : Object) -> bool:
|
||||
#AimTarget doit avoir : @export var starts_battle : bool = false
|
||||
return "starts_battle" in target and target.starts_battle
|
||||
|
||||
func _on_ball_landed(landing_pos : Vector3, pokemon : PokemonInstance, target : Variant, thrower_pos : Vector3) -> void:
|
||||
var scene : Node = get_tree().current_scene if is_inside_tree() else null
|
||||
if scene == null: return
|
||||
|
||||
var target_valid : bool = is_instance_valid(target)
|
||||
#le pokemon regarde la cible, ou dans la direction du lancer s'il n'y en a pas
|
||||
var look_pos : Vector3 = target.global_position if target_valid else landing_pos + (landing_pos - thrower_pos)
|
||||
var sent : SentPokemon = SentPokemon.send(scene, pokemon, landing_pos, look_pos)
|
||||
|
||||
if target_valid and _starts_battle(target):
|
||||
GameData.battle_requested.emit(sent, target)
|
||||
|
||||
#---------- nettoyage ----------
|
||||
|
||||
func _release_aim() -> void:
|
||||
#meme comportement que AimState.exit() / release_target()
|
||||
if !play_char: return
|
||||
if is_instance_valid(play_char.aim_target): play_char.aim_target.set_locked(false)
|
||||
play_char.aim_target = null
|
||||
play_char.cam_holder.set_lock_target(null)
|
||||
play_char.cam_holder.cam_aimed = false
|
||||
1
game/player/states/throw_state.gd.uid
Normal file
1
game/player/states/throw_state.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c3jh22p4w3xco
|
||||
73
game/pokemon/sent_pokemon.gd
Normal file
73
game/pokemon/sent_pokemon.gd
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
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:
|
||||
var scene : PackedScene = pokemon.species.model_scene
|
||||
if scene:
|
||||
model = scene.instantiate() as Node3D
|
||||
if model == null:
|
||||
#modele de remplacement si l'espece n'a pas de modele 3D
|
||||
var mesh_instance := MeshInstance3D.new()
|
||||
var capsule := CapsuleMesh.new()
|
||||
capsule.radius = 0.3
|
||||
capsule.height = 1.0
|
||||
mesh_instance.mesh = capsule
|
||||
mesh_instance.position.y = 0.5
|
||||
model = mesh_instance
|
||||
add_child(model)
|
||||
|
||||
func recall() -> void:
|
||||
recalled.emit()
|
||||
queue_free()
|
||||
1
game/pokemon/sent_pokemon.gd.uid
Normal file
1
game/pokemon/sent_pokemon.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bc3a1pvuq6dy6
|
||||
Loading…
Reference in a new issue